diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-12-17 06:11:14 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:13 -0400 |
commit | 8095708fce72a911e20799078639e95c1a008176 (patch) | |
tree | a21d5c3f36448d5d98e117c3f7a0190bb8a977ee /fs | |
parent | 96012e143e699db1a7644e4c5903b63bdde33772 (diff) | |
download | lwn-8095708fce72a911e20799078639e95c1a008176.tar.gz lwn-8095708fce72a911e20799078639e95c1a008176.zip |
bcachefs: bch2_ioc_reinherit_attrs()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs_ioctl.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/fs-ioctl.c | 77 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 31 | ||||
-rw-r--r-- | fs/bcachefs/fs.h | 26 | ||||
-rw-r--r-- | fs/bcachefs/inode.c | 3 |
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; |