diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-12-17 05:31:49 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:13 -0400 |
commit | 96012e143e699db1a7644e4c5903b63bdde33772 (patch) | |
tree | 42d608d11785d609c5b24f9047726aec5571af9b /fs | |
parent | 4d269918ed502cba80ddad998bdb087a633c63ab (diff) | |
download | lwn-96012e143e699db1a7644e4c5903b63bdde33772.tar.gz lwn-96012e143e699db1a7644e4c5903b63bdde33772.zip |
bcachefs: rename keeps inheritable inode opts consistent
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/fs.c | 84 | ||||
-rw-r--r-- | fs/bcachefs/fs.h | 25 |
2 files changed, 109 insertions, 0 deletions
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index d22b9e7e2082..033582a87852 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -282,6 +282,32 @@ int bch2_fs_quota_transfer(struct bch_fs *c, 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) { struct bch_inode_unpacked inode_u; @@ -765,6 +791,7 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode, void *p) { struct rename_info *info = p; + int ret; if (inode == info->src_dir) { 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, 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 && info->mode == BCH_RENAME_OVERWRITE) { BUG_ON(bi->bi_nlink && @@ -844,6 +884,39 @@ static int bch2_rename2(struct mnt_idmap *idmap, i.dst_inode); 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: bch2_trans_begin(&trans); i.now = bch2_current_time(c); @@ -894,6 +967,17 @@ retry: ATTR_CTIME); err: 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, i.dst_dir, i.src_inode, diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h index fbb31976bc55..18e41609c89d 100644 --- a/fs/bcachefs/fs.h +++ b/fs/bcachefs/fs.h @@ -66,6 +66,27 @@ static inline unsigned nlink_bias(umode_t mode) 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; #ifndef NO_BCACHEFS_FS @@ -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 *, inode_set_fn, void *, unsigned); +int bch2_reinherit_attrs_fn(struct bch_inode_info *, + struct bch_inode_unpacked *, + void *); + void bch2_vfs_exit(void); int bch2_vfs_init(void); |