summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-12-17 05:31:49 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-12-27 11:38:38 -0500
commit67a657b457cac5ec07297c20e931de7db9c30cf6 (patch)
tree9badec81b36c7110c40dca39d06e3c3521e3e22b
parented5b9b79aa02e7000c1ab7957d12f01c24dc1115 (diff)
bcachefs: rename keeps inheritable inode opts consistent
-rw-r--r--fs/bcachefs/fs.c84
-rw-r--r--fs/bcachefs/fs.h25
2 files changed, 109 insertions, 0 deletions
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 5c7d3f89959a..9b9edd148cfe 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -231,6 +231,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;
@@ -698,6 +724,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);
@@ -712,6 +739,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 &&
@@ -776,6 +816,39 @@ static int bch2_rename2(struct inode *src_vdir, struct dentry *src_dentry,
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);
@@ -826,6 +899,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 1a7bb7767c21..009d1a4cbf14 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -49,6 +49,27 @@ static inline u64 bch2_current_time(struct bch_fs *c)
return timespec_to_bch2_time(c, current_kernel_time64());
}
+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
@@ -74,6 +95,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);