bcachefs: rename keeps inheritable inode opts consistent

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2018-12-17 05:31:49 -05:00 committed by Kent Overstreet
parent 4d269918ed
commit 96012e143e
2 changed files with 109 additions and 0 deletions

View file

@ -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 @@ static int bch2_rename2(struct mnt_idmap *idmap,
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,

View file

@ -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);