bcachefs: bch2_ioc_reinherit_attrs()
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 17 Dec 2018 11:11:14 +0000 (06:11 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:13 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs_ioctl.h
fs/bcachefs/fs-ioctl.c
fs/bcachefs/fs.c
fs/bcachefs/fs.h
fs/bcachefs/inode.c

index c65104ed454a6ad6083dfac2cab3d3a2f83227d3..2dca4bb0362b83421c63a95c158b6eff6cb30271 100644 (file)
@@ -307,4 +307,6 @@ struct bch_ioctl_disk_resize {
        __u64                   nbuckets;
 };
 
+#define BCHFS_IOC_REINHERIT_ATTRS      _IOR(0xbc, 14, const char __user *)
+
 #endif /* _BCACHEFS_IOCTL_H */
index d6563370bec4974c92e00c32d369f792aca51951..92939befe507558206bc560c09ec76f031300e48 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "bcachefs.h"
 #include "chardev.h"
+#include "dirent.h"
 #include "fs.h"
 #include "fs-ioctl.h"
 #include "quota.h"
@@ -177,6 +178,75 @@ err:
        return ret;
 }
 
+static int bch2_ioc_reinherit_attrs(struct bch_fs *c,
+                                   struct file *file,
+                                   struct bch_inode_info *src,
+                                   const char __user *name)
+{
+       struct bch_inode_info *dst;
+       struct inode *vinode = NULL;
+       char *kname = NULL;
+       struct qstr qstr;
+       int ret = 0;
+       u64 inum;
+
+       kname = kmalloc(BCH_NAME_MAX + 1, GFP_KERNEL);
+       if (!kname)
+               return -ENOMEM;
+
+       ret = strncpy_from_user(kname, name, BCH_NAME_MAX);
+       if (unlikely(ret < 0))
+               goto err1;
+
+       qstr.hash_len   = ret;
+       qstr.name       = kname;
+
+       ret = -ENOENT;
+       inum = bch2_dirent_lookup(c, src->v.i_ino,
+                                 &src->ei_str_hash,
+                                 &qstr);
+       if (!inum)
+               goto err1;
+
+       vinode = bch2_vfs_inode_get(c, inum);
+       ret = PTR_ERR_OR_ZERO(vinode);
+       if (ret)
+               goto err1;
+
+       dst = to_bch_ei(vinode);
+
+       ret = mnt_want_write_file(file);
+       if (ret)
+               goto err2;
+
+       bch2_lock_inodes(src, dst);
+
+       if (inode_attr_changing(src, dst, Inode_opt_project)) {
+               ret = bch2_fs_quota_transfer(c, dst,
+                                            src->ei_qid,
+                                            1 << QTYP_PRJ,
+                                            KEY_TYPE_QUOTA_PREALLOC);
+               if (ret)
+                       goto err3;
+       }
+
+       ret = bch2_write_inode(c, dst, bch2_reinherit_attrs_fn, src, 0);
+err3:
+       bch2_unlock_inodes(src, dst);
+
+       /* return true if we did work */
+       if (ret >= 0)
+               ret = !ret;
+
+       mnt_drop_write_file(file);
+err2:
+       iput(vinode);
+err1:
+       kfree(kname);
+
+       return ret;
+}
+
 long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
        struct bch_inode_info *inode = file_bch_inode(file);
@@ -193,7 +263,12 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case FS_IOC_FSGETXATTR:
                return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
        case FS_IOC_FSSETXATTR:
-               return bch2_ioc_fssetxattr(c, file, inode, (void __user *) arg);
+               return bch2_ioc_fssetxattr(c, file, inode,
+                                          (void __user *) arg);
+
+       case BCHFS_IOC_REINHERIT_ATTRS:
+               return bch2_ioc_reinherit_attrs(c, file, inode,
+                                               (void __user *) arg);
 
        case FS_IOC_GETVERSION:
                return -ENOTTY;
index 033582a878521978f95670a7fa2f109e2a77eef2..d23a82d94c5ec6e10b54be631597d8657741804c 100644 (file)
@@ -51,30 +51,6 @@ static void journal_seq_copy(struct bch_inode_info *dst,
        } while ((v = cmpxchg(&dst->ei_journal_seq, old, journal_seq)) != old);
 }
 
-static inline int ptrcmp(void *l, void *r)
-{
-       return (l > r) - (l < r);
-}
-
-#define __bch2_lock_inodes(_lock, ...)                                 \
-do {                                                                   \
-       struct bch_inode_info *a[] = { NULL, __VA_ARGS__ };             \
-       unsigned i;                                                     \
-                                                                       \
-       bubble_sort(&a[1], ARRAY_SIZE(a) - 1 , ptrcmp);                 \
-                                                                       \
-       for (i = ARRAY_SIZE(a) - 1; a[i]; --i)                          \
-               if (a[i] != a[i - 1]) {                                 \
-                       if (_lock)                                      \
-                               mutex_lock_nested(&a[i]->ei_update_lock, i);\
-                       else                                            \
-                               mutex_unlock(&a[i]->ei_update_lock);    \
-               }                                                       \
-} while (0)
-
-#define bch2_lock_inodes(...)  __bch2_lock_inodes(true, __VA_ARGS__)
-#define bch2_unlock_inodes(...)        __bch2_lock_inodes(false, __VA_ARGS__)
-
 static void __pagecache_lock_put(struct pagecache_lock *lock, long i)
 {
        BUG_ON(atomic_long_read(&lock->v) == 0);
@@ -308,7 +284,7 @@ int bch2_reinherit_attrs_fn(struct bch_inode_info *inode,
        return ret;
 }
 
-static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
+struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
 {
        struct bch_inode_unpacked inode_u;
        struct bch_inode_info *inode;
@@ -393,14 +369,13 @@ __bch2_create(struct mnt_idmap *idmap,
        bch2_inode_init(c, &inode_u, 0, 0, 0, rdev, &dir->ei_inode);
        bch2_inode_init_owner(&inode_u, &dir->v, mode);
 
-       inode_u.bi_project = dir->ei_qid.q[QTYP_PRJ];
-
        hash_info = bch2_hash_info_init(c, &inode_u);
 
        if (tmpfile)
                inode_u.bi_flags |= BCH_INODE_UNLINKED;
 
-       ret = bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1, KEY_TYPE_QUOTA_PREALLOC);
+       ret = bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
+                             KEY_TYPE_QUOTA_PREALLOC);
        if (ret)
                return ERR_PTR(ret);
 
index 18e41609c89de76cbfd3dc963f8cd0dc59ad7a28..4c584d3a27c3ff2126f418ce6ef0a63d9cbec3fc 100644 (file)
@@ -51,6 +51,30 @@ struct bch_inode_info {
 #define to_bch_ei(_inode)                                      \
        container_of_or_null(_inode, struct bch_inode_info, v)
 
+static inline int ptrcmp(void *l, void *r)
+{
+       return (l > r) - (l < r);
+}
+
+#define __bch2_lock_inodes(_lock, ...)                                 \
+do {                                                                   \
+       struct bch_inode_info *a[] = { NULL, __VA_ARGS__ };             \
+       unsigned i;                                                     \
+                                                                       \
+       bubble_sort(&a[1], ARRAY_SIZE(a) - 1 , ptrcmp);                 \
+                                                                       \
+       for (i = ARRAY_SIZE(a) - 1; a[i]; --i)                          \
+               if (a[i] != a[i - 1]) {                                 \
+                       if (_lock)                                      \
+                               mutex_lock_nested(&a[i]->ei_update_lock, i);\
+                       else                                            \
+                               mutex_unlock(&a[i]->ei_update_lock);    \
+               }                                                       \
+} while (0)
+
+#define bch2_lock_inodes(...)  __bch2_lock_inodes(true, __VA_ARGS__)
+#define bch2_unlock_inodes(...)        __bch2_lock_inodes(false, __VA_ARGS__)
+
 static inline struct bch_inode_info *file_bch_inode(struct file *file)
 {
        return to_bch_ei(file_inode(file));
@@ -97,6 +121,8 @@ int bch2_fs_quota_transfer(struct bch_fs *,
                           unsigned,
                           enum quota_acct_mode);
 
+struct inode *bch2_vfs_inode_get(struct bch_fs *, u64);
+
 /* returns 0 if we want to do the update, or error is passed up */
 typedef int (*inode_set_fn)(struct bch_inode_info *,
                            struct bch_inode_unpacked *, void *);
index 23d3668b45673b1e5ee736dc41c2e1a385b4c2d3..6acb487312a8d50562ca0b5627f29333798db0fd 100644 (file)
@@ -258,7 +258,8 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
 
        /* ick */
        inode_u->bi_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET;
-       get_random_bytes(&inode_u->bi_hash_seed, sizeof(inode_u->bi_hash_seed));
+       get_random_bytes(&inode_u->bi_hash_seed,
+                        sizeof(inode_u->bi_hash_seed));
 
        inode_u->bi_mode        = mode;
        inode_u->bi_uid         = uid;