mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 23:58:05 +00:00
bcachefs: bch2_ioc_reinherit_attrs()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
96012e143e
commit
8095708fce
5 changed files with 109 additions and 30 deletions
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue