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 {
__u64 nbuckets;
};
#define BCHFS_IOC_REINHERIT_ATTRS _IOR(0xbc, 14, const char __user *)
#endif /* _BCACHEFS_IOCTL_H */
......@@ -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 @@ static int bch2_ioc_fssetxattr(struct bch_fs *c,
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;
......
......@@ -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);
......
......@@ -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 *);
......
......@@ -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;
......
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