summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-12-17 06:11:14 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-12-27 11:38:38 -0500
commit162845a4a92ddd95ef155c5b1709bd06d123e169 (patch)
treee545191187b5d4b72f8d6007a8e6ee96cec0e0b4
parent67a657b457cac5ec07297c20e931de7db9c30cf6 (diff)
bcachefs: bch2_ioc_reinherit_attrs()
-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 73e5d887ccd8..7da11762fffe 100644
--- a/fs/bcachefs/bcachefs_ioctl.h
+++ b/fs/bcachefs/bcachefs_ioctl.h
@@ -306,4 +306,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 dc900e7b81da..7b9acafb9491 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -2,6 +2,7 @@
#include "bcachefs.h"
#include "chardev.h"
+#include "dirent.h"
#include "fs.h"
#include "fs-ioctl.h"
#include "quota.h"
@@ -176,6 +177,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);
@@ -192,7 +262,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 9b9edd148cfe..300348b6648b 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -47,30 +47,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__)
-
/*
* I_SIZE_DIRTY requires special handling:
*
@@ -257,7 +233,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;
@@ -334,14 +310,13 @@ __bch2_create(struct bch_inode_info *dir, struct dentry *dentry,
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 009d1a4cbf14..7dc0453af2db 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -29,6 +29,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));
@@ -80,6 +104,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 259602e2529b..f851e3b73170 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -259,7 +259,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;