Commit 8095708f authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: bch2_ioc_reinherit_attrs()

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 96012e14
...@@ -307,4 +307,6 @@ struct bch_ioctl_disk_resize { ...@@ -307,4 +307,6 @@ struct bch_ioctl_disk_resize {
__u64 nbuckets; __u64 nbuckets;
}; };
#define BCHFS_IOC_REINHERIT_ATTRS _IOR(0xbc, 14, const char __user *)
#endif /* _BCACHEFS_IOCTL_H */ #endif /* _BCACHEFS_IOCTL_H */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "bcachefs.h" #include "bcachefs.h"
#include "chardev.h" #include "chardev.h"
#include "dirent.h"
#include "fs.h" #include "fs.h"
#include "fs-ioctl.h" #include "fs-ioctl.h"
#include "quota.h" #include "quota.h"
...@@ -177,6 +178,75 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c, ...@@ -177,6 +178,75 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
return ret; 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) long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{ {
struct bch_inode_info *inode = file_bch_inode(file); 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) ...@@ -193,7 +263,12 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case FS_IOC_FSGETXATTR: case FS_IOC_FSGETXATTR:
return bch2_ioc_fsgetxattr(inode, (void __user *) arg); return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
case FS_IOC_FSSETXATTR: 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: case FS_IOC_GETVERSION:
return -ENOTTY; return -ENOTTY;
......
...@@ -51,30 +51,6 @@ static void journal_seq_copy(struct bch_inode_info *dst, ...@@ -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); } 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) static void __pagecache_lock_put(struct pagecache_lock *lock, long i)
{ {
BUG_ON(atomic_long_read(&lock->v) == 0); BUG_ON(atomic_long_read(&lock->v) == 0);
...@@ -308,7 +284,7 @@ int bch2_reinherit_attrs_fn(struct bch_inode_info *inode, ...@@ -308,7 +284,7 @@ int bch2_reinherit_attrs_fn(struct bch_inode_info *inode,
return ret; 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_unpacked inode_u;
struct bch_inode_info *inode; struct bch_inode_info *inode;
...@@ -393,14 +369,13 @@ __bch2_create(struct mnt_idmap *idmap, ...@@ -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(c, &inode_u, 0, 0, 0, rdev, &dir->ei_inode);
bch2_inode_init_owner(&inode_u, &dir->v, mode); 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); hash_info = bch2_hash_info_init(c, &inode_u);
if (tmpfile) if (tmpfile)
inode_u.bi_flags |= BCH_INODE_UNLINKED; 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) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -51,6 +51,30 @@ struct bch_inode_info { ...@@ -51,6 +51,30 @@ struct bch_inode_info {
#define to_bch_ei(_inode) \ #define to_bch_ei(_inode) \
container_of_or_null(_inode, struct bch_inode_info, v) 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) static inline struct bch_inode_info *file_bch_inode(struct file *file)
{ {
return to_bch_ei(file_inode(file)); return to_bch_ei(file_inode(file));
...@@ -97,6 +121,8 @@ int bch2_fs_quota_transfer(struct bch_fs *, ...@@ -97,6 +121,8 @@ int bch2_fs_quota_transfer(struct bch_fs *,
unsigned, unsigned,
enum quota_acct_mode); 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 */ /* returns 0 if we want to do the update, or error is passed up */
typedef int (*inode_set_fn)(struct bch_inode_info *, typedef int (*inode_set_fn)(struct bch_inode_info *,
struct bch_inode_unpacked *, void *); struct bch_inode_unpacked *, void *);
......
...@@ -258,7 +258,8 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, ...@@ -258,7 +258,8 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
/* ick */ /* ick */
inode_u->bi_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET; 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_mode = mode;
inode_u->bi_uid = uid; inode_u->bi_uid = uid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment