aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Kent Overstreet <kent.overstreet@gmail.com> 2018-12-17 06:11:14 -0500
committerGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-10-22 17:08:13 -0400
commit8095708fce72a911e20799078639e95c1a008176 (patch)
treea21d5c3f36448d5d98e117c3f7a0190bb8a977ee
parentbcachefs: rename keeps inheritable inode opts consistent (diff)
downloadlinux-8095708fce72a911e20799078639e95c1a008176.tar.gz
linux-8095708fce72a911e20799078639e95c1a008176.tar.bz2
linux-8095708fce72a911e20799078639e95c1a008176.zip
bcachefs: bch2_ioc_reinherit_attrs()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bcachefs_ioctl.h2
-rw-r--r--fs/bcachefs/fs-ioctl.c77
-rw-r--r--fs/bcachefs/fs.c31
-rw-r--r--fs/bcachefs/fs.h26
-rw-r--r--fs/bcachefs/inode.c3
5 files changed, 109 insertions, 30 deletions
diff --git a/fs/bcachefs/bcachefs_ioctl.h b/fs/bcachefs/bcachefs_ioctl.h
index c65104ed454a..2dca4bb0362b 100644
--- a/fs/bcachefs/bcachefs_ioctl.h
+++ b/fs/bcachefs/bcachefs_ioctl.h
@@ -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 */
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index d6563370bec4..92939befe507 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -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;
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 033582a87852..d23a82d94c5e 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -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);
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index 18e41609c89d..4c584d3a27c3 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -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 *);
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 23d3668b4567..6acb487312a8 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -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;