Commit 96012e14 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: rename keeps inheritable inode opts consistent

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 4d269918
...@@ -282,6 +282,32 @@ int bch2_fs_quota_transfer(struct bch_fs *c, ...@@ -282,6 +282,32 @@ int bch2_fs_quota_transfer(struct bch_fs *c,
return ret; return ret;
} }
int bch2_reinherit_attrs_fn(struct bch_inode_info *inode,
struct bch_inode_unpacked *bi,
void *p)
{
struct bch_inode_info *dir = p;
u64 src, dst;
unsigned id;
int ret = 1;
for (id = 0; id < Inode_opt_nr; id++) {
if (bi->bi_fields_set & (1 << id))
continue;
src = bch2_inode_opt_get(&dir->ei_inode, id);
dst = bch2_inode_opt_get(bi, id);
if (src == dst)
continue;
bch2_inode_opt_set(bi, id, src);
ret = 0;
}
return ret;
}
static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum) static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
{ {
struct bch_inode_unpacked inode_u; struct bch_inode_unpacked inode_u;
...@@ -765,6 +791,7 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode, ...@@ -765,6 +791,7 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode,
void *p) void *p)
{ {
struct rename_info *info = p; struct rename_info *info = p;
int ret;
if (inode == info->src_dir) { if (inode == info->src_dir) {
bi->bi_nlink -= S_ISDIR(info->src_inode->v.i_mode); bi->bi_nlink -= S_ISDIR(info->src_inode->v.i_mode);
...@@ -779,6 +806,19 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode, ...@@ -779,6 +806,19 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode,
S_ISDIR(info->dst_inode->v.i_mode); S_ISDIR(info->dst_inode->v.i_mode);
} }
if (inode == info->src_inode) {
ret = bch2_reinherit_attrs_fn(inode, bi, info->dst_dir);
BUG_ON(!ret && S_ISDIR(info->src_inode->v.i_mode));
}
if (inode == info->dst_inode &&
info->mode == BCH_RENAME_EXCHANGE) {
ret = bch2_reinherit_attrs_fn(inode, bi, info->src_dir);
BUG_ON(!ret && S_ISDIR(info->dst_inode->v.i_mode));
}
if (inode == info->dst_inode && if (inode == info->dst_inode &&
info->mode == BCH_RENAME_OVERWRITE) { info->mode == BCH_RENAME_OVERWRITE) {
BUG_ON(bi->bi_nlink && BUG_ON(bi->bi_nlink &&
...@@ -844,6 +884,39 @@ static int bch2_rename2(struct mnt_idmap *idmap, ...@@ -844,6 +884,39 @@ static int bch2_rename2(struct mnt_idmap *idmap,
i.dst_inode); i.dst_inode);
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
if (S_ISDIR(i.src_inode->v.i_mode) &&
inode_attrs_changing(i.dst_dir, i.src_inode)) {
ret = -EXDEV;
goto err;
}
if (i.mode == BCH_RENAME_EXCHANGE &&
S_ISDIR(i.dst_inode->v.i_mode) &&
inode_attrs_changing(i.src_dir, i.dst_inode)) {
ret = -EXDEV;
goto err;
}
if (inode_attr_changing(i.dst_dir, i.src_inode, Inode_opt_project)) {
ret = bch2_fs_quota_transfer(c, i.src_inode,
i.dst_dir->ei_qid,
1 << QTYP_PRJ,
KEY_TYPE_QUOTA_PREALLOC);
if (ret)
goto err;
}
if (i.mode == BCH_RENAME_EXCHANGE &&
inode_attr_changing(i.src_dir, i.dst_inode, Inode_opt_project)) {
ret = bch2_fs_quota_transfer(c, i.dst_inode,
i.src_dir->ei_qid,
1 << QTYP_PRJ,
KEY_TYPE_QUOTA_PREALLOC);
if (ret)
goto err;
}
retry: retry:
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
i.now = bch2_current_time(c); i.now = bch2_current_time(c);
...@@ -894,6 +967,17 @@ static int bch2_rename2(struct mnt_idmap *idmap, ...@@ -894,6 +967,17 @@ static int bch2_rename2(struct mnt_idmap *idmap,
ATTR_CTIME); ATTR_CTIME);
err: err:
bch2_trans_exit(&trans); bch2_trans_exit(&trans);
bch2_fs_quota_transfer(c, i.src_inode,
bch_qid(&i.src_inode->ei_inode),
1 << QTYP_PRJ,
KEY_TYPE_QUOTA_NOCHECK);
if (i.dst_inode)
bch2_fs_quota_transfer(c, i.dst_inode,
bch_qid(&i.dst_inode->ei_inode),
1 << QTYP_PRJ,
KEY_TYPE_QUOTA_NOCHECK);
bch2_unlock_inodes(i.src_dir, bch2_unlock_inodes(i.src_dir,
i.dst_dir, i.dst_dir,
i.src_inode, i.src_inode,
......
...@@ -66,6 +66,27 @@ static inline unsigned nlink_bias(umode_t mode) ...@@ -66,6 +66,27 @@ static inline unsigned nlink_bias(umode_t mode)
return S_ISDIR(mode) ? 2 : 1; return S_ISDIR(mode) ? 2 : 1;
} }
static inline bool inode_attr_changing(struct bch_inode_info *dir,
struct bch_inode_info *inode,
enum inode_opt_id id)
{
return !(inode->ei_inode.bi_fields_set & (1 << id)) &&
bch2_inode_opt_get(&dir->ei_inode, id) !=
bch2_inode_opt_get(&inode->ei_inode, id);
}
static inline bool inode_attrs_changing(struct bch_inode_info *dir,
struct bch_inode_info *inode)
{
unsigned id;
for (id = 0; id < Inode_opt_nr; id++)
if (inode_attr_changing(dir, inode, id))
return true;
return false;
}
struct bch_inode_unpacked; struct bch_inode_unpacked;
#ifndef NO_BCACHEFS_FS #ifndef NO_BCACHEFS_FS
...@@ -91,6 +112,10 @@ int __must_check bch2_write_inode_trans(struct btree_trans *, ...@@ -91,6 +112,10 @@ int __must_check bch2_write_inode_trans(struct btree_trans *,
int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *, int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *,
inode_set_fn, void *, unsigned); inode_set_fn, void *, unsigned);
int bch2_reinherit_attrs_fn(struct bch_inode_info *,
struct bch_inode_unpacked *,
void *);
void bch2_vfs_exit(void); void bch2_vfs_exit(void);
int bch2_vfs_init(void); int bch2_vfs_init(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment