From f9ba96e16535a653b97f7f1f953fabf477737a96 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 17 Dec 2018 09:26:29 -0500 Subject: Update bcachefs sources to 57ea7773cb bcachefs: Fix duplicate ioctl nr --- .bcachefs_revision | 2 +- libbcachefs/bcachefs_format.h | 74 ++++++++------- libbcachefs/bcachefs_ioctl.h | 6 +- libbcachefs/fs-ioctl.c | 101 ++++++++++++++++++--- libbcachefs/fs.c | 182 +++++++++++++++++++++++++++---------- libbcachefs/fs.h | 57 ++++++++++++ libbcachefs/inode.c | 32 ++++--- libbcachefs/inode.h | 44 ++++----- libbcachefs/opts.c | 16 ++-- libbcachefs/opts.h | 23 ++--- libbcachefs/quota.c | 7 +- libbcachefs/quota.h | 8 +- libbcachefs/quota_types.h | 6 ++ libbcachefs/xattr.c | 203 ++++++++++++++++++++++++++++++++---------- 14 files changed, 552 insertions(+), 209 deletions(-) diff --git a/.bcachefs_revision b/.bcachefs_revision index 0779c530..d41e3b03 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -f7670cba39ead5fcc99da93b46024bd6355c0663 +57ea7773cb4368dc98ec68385c3d0941c246ad70 diff --git a/libbcachefs/bcachefs_format.h b/libbcachefs/bcachefs_format.h index efda901e..9245465d 100644 --- a/libbcachefs/bcachefs_format.h +++ b/libbcachefs/bcachefs_format.h @@ -689,38 +689,48 @@ struct bch_inode_generation { __le32 pad; } __attribute__((packed, aligned(8))); -#define BCH_INODE_FIELDS() \ - BCH_INODE_FIELD(bi_atime, 64) \ - BCH_INODE_FIELD(bi_ctime, 64) \ - BCH_INODE_FIELD(bi_mtime, 64) \ - BCH_INODE_FIELD(bi_otime, 64) \ - BCH_INODE_FIELD(bi_size, 64) \ - BCH_INODE_FIELD(bi_sectors, 64) \ - BCH_INODE_FIELD(bi_uid, 32) \ - BCH_INODE_FIELD(bi_gid, 32) \ - BCH_INODE_FIELD(bi_nlink, 32) \ - BCH_INODE_FIELD(bi_generation, 32) \ - BCH_INODE_FIELD(bi_dev, 32) \ - BCH_INODE_FIELD(bi_data_checksum, 8) \ - BCH_INODE_FIELD(bi_compression, 8) \ - BCH_INODE_FIELD(bi_project, 32) \ - BCH_INODE_FIELD(bi_background_compression, 8) \ - BCH_INODE_FIELD(bi_data_replicas, 8) \ - BCH_INODE_FIELD(bi_promote_target, 16) \ - BCH_INODE_FIELD(bi_foreground_target, 16) \ - BCH_INODE_FIELD(bi_background_target, 16) \ - BCH_INODE_FIELD(bi_erasure_code, 16) - -#define BCH_INODE_FIELDS_INHERIT() \ - BCH_INODE_FIELD(bi_data_checksum) \ - BCH_INODE_FIELD(bi_compression) \ - BCH_INODE_FIELD(bi_project) \ - BCH_INODE_FIELD(bi_background_compression) \ - BCH_INODE_FIELD(bi_data_replicas) \ - BCH_INODE_FIELD(bi_promote_target) \ - BCH_INODE_FIELD(bi_foreground_target) \ - BCH_INODE_FIELD(bi_background_target) \ - BCH_INODE_FIELD(bi_erasure_code) +#define BCH_INODE_FIELDS() \ + x(bi_atime, 64) \ + x(bi_ctime, 64) \ + x(bi_mtime, 64) \ + x(bi_otime, 64) \ + x(bi_size, 64) \ + x(bi_sectors, 64) \ + x(bi_uid, 32) \ + x(bi_gid, 32) \ + x(bi_nlink, 32) \ + x(bi_generation, 32) \ + x(bi_dev, 32) \ + x(bi_data_checksum, 8) \ + x(bi_compression, 8) \ + x(bi_project, 32) \ + x(bi_background_compression, 8) \ + x(bi_data_replicas, 8) \ + x(bi_promote_target, 16) \ + x(bi_foreground_target, 16) \ + x(bi_background_target, 16) \ + x(bi_erasure_code, 16) \ + x(bi_fields_set, 16) + +/* subset of BCH_INODE_FIELDS */ +#define BCH_INODE_OPTS() \ + x(data_checksum, 8) \ + x(compression, 8) \ + x(project, 32) \ + x(background_compression, 8) \ + x(data_replicas, 8) \ + x(promote_target, 16) \ + x(foreground_target, 16) \ + x(background_target, 16) \ + x(erasure_code, 16) + +enum inode_opt_id { +#define x(name, ...) \ + Inode_opt_##name, + BCH_INODE_OPTS() +#undef x + Inode_opt_nr, +}; enum { /* diff --git a/libbcachefs/bcachefs_ioctl.h b/libbcachefs/bcachefs_ioctl.h index 73e5d887..fb595dff 100644 --- a/libbcachefs/bcachefs_ioctl.h +++ b/libbcachefs/bcachefs_ioctl.h @@ -70,7 +70,11 @@ struct bch_ioctl_incremental { #define BCH_IOCTL_USAGE _IOWR(0xbc, 11, struct bch_ioctl_usage) #define BCH_IOCTL_READ_SUPER _IOW(0xbc, 12, struct bch_ioctl_read_super) #define BCH_IOCTL_DISK_GET_IDX _IOW(0xbc, 13, struct bch_ioctl_disk_get_idx) -#define BCH_IOCTL_DISK_RESIZE _IOW(0xbc, 13, struct bch_ioctl_disk_resize) +#define BCH_IOCTL_DISK_RESIZE _IOW(0xbc, 14, struct bch_ioctl_disk_resize) + +/* ioctl below act on a particular file, not the filesystem as a whole: */ + +#define BCHFS_IOC_REINHERIT_ATTRS _IOR(0xbc, 64, const char __user *) /* * BCH_IOCTL_QUERY_UUID: get filesystem UUID diff --git a/libbcachefs/fs-ioctl.c b/libbcachefs/fs-ioctl.c index 0eb0a011..7b9acafb 100644 --- a/libbcachefs/fs-ioctl.c +++ b/libbcachefs/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" @@ -107,21 +108,12 @@ static int bch2_set_projid(struct bch_fs *c, u32 projid) { struct bch_qid qid = inode->ei_qid; - int ret; - - if (projid == inode->ei_qid.q[QTYP_PRJ]) - return 0; qid.q[QTYP_PRJ] = projid; - return bch2_quota_transfer(c, 1 << QTYP_PRJ, qid, inode->ei_qid, - inode->v.i_blocks + - inode->ei_quota_reserved); - if (ret) - return ret; - - inode->ei_qid.q[QTYP_PRJ] = projid; - return 0; + return bch2_fs_quota_transfer(c, inode, qid, + 1 << QTYP_PRJ, + KEY_TYPE_QUOTA_PREALLOC); } static int fssetxattr_inode_update_fn(struct bch_inode_info *inode, @@ -130,7 +122,14 @@ static int fssetxattr_inode_update_fn(struct bch_inode_info *inode, { struct flags_set *s = p; - bi->bi_project = s->projid; + if (s->projid != bi->bi_project) { + if (s->projid) + bi->bi_fields_set |= 1U << Inode_opt_project; + else + bi->bi_fields_set &= ~(1U << Inode_opt_project); + + bi->bi_project = s->projid; + } return bch2_inode_flags_set(inode, bi, p); } @@ -178,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); @@ -194,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/libbcachefs/fs.c b/libbcachefs/fs.c index 13670a63..300348b6 100644 --- a/libbcachefs/fs.c +++ b/libbcachefs/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: * @@ -119,7 +95,6 @@ void bch2_inode_update_after_write(struct bch_fs *c, inode->v.i_ctime = bch2_time_to_timespec(c, bi->bi_ctime); inode->ei_inode = *bi; - inode->ei_qid = bch_qid(bi); bch2_inode_flags_to_vfs(inode); } @@ -197,7 +172,68 @@ retry: return ret < 0 ? ret : 0; } -static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum) +int bch2_fs_quota_transfer(struct bch_fs *c, + struct bch_inode_info *inode, + struct bch_qid new_qid, + unsigned qtypes, + enum quota_acct_mode mode) +{ + unsigned i; + int ret; + + qtypes &= enabled_qtypes(c); + + for (i = 0; i < QTYP_NR; i++) + if (new_qid.q[i] == inode->ei_qid.q[i]) + qtypes &= ~(1U << i); + + if (!qtypes) + return 0; + + mutex_lock(&inode->ei_quota_lock); + + ret = bch2_quota_transfer(c, qtypes, new_qid, + inode->ei_qid, + inode->v.i_blocks + + inode->ei_quota_reserved, + mode); + if (!ret) + for (i = 0; i < QTYP_NR; i++) + if (qtypes & (1 << i)) + inode->ei_qid.q[i] = new_qid.q[i]; + + mutex_unlock(&inode->ei_quota_lock); + + return ret; +} + +int bch2_reinherit_attrs_fn(struct bch_inode_info *inode, + struct bch_inode_unpacked *bi, + void *p) +{ + struct bch_inode_info *dir = p; + u64 src, dst; + unsigned id; + int ret = 1; + + for (id = 0; id < Inode_opt_nr; id++) { + if (bi->bi_fields_set & (1 << id)) + continue; + + src = bch2_inode_opt_get(&dir->ei_inode, id); + dst = bch2_inode_opt_get(bi, id); + + if (src == dst) + continue; + + bch2_inode_opt_set(bi, id, src); + ret = 0; + } + + return ret; +} + +struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum) { struct bch_inode_unpacked inode_u; struct bch_inode_info *inode; @@ -274,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); @@ -664,6 +699,7 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode, void *p) { struct rename_info *info = p; + int ret; if (inode == info->src_dir) { bi->bi_nlink -= S_ISDIR(info->src_inode->v.i_mode); @@ -678,6 +714,19 @@ static int inode_update_for_rename_fn(struct bch_inode_info *inode, S_ISDIR(info->dst_inode->v.i_mode); } + if (inode == info->src_inode) { + ret = bch2_reinherit_attrs_fn(inode, bi, info->dst_dir); + + BUG_ON(!ret && S_ISDIR(info->src_inode->v.i_mode)); + } + + if (inode == info->dst_inode && + info->mode == BCH_RENAME_EXCHANGE) { + ret = bch2_reinherit_attrs_fn(inode, bi, info->src_dir); + + BUG_ON(!ret && S_ISDIR(info->dst_inode->v.i_mode)); + } + if (inode == info->dst_inode && info->mode == BCH_RENAME_OVERWRITE) { BUG_ON(bi->bi_nlink && @@ -742,6 +791,39 @@ static int bch2_rename2(struct inode *src_vdir, struct dentry *src_dentry, i.dst_inode); bch2_trans_init(&trans, c); + + if (S_ISDIR(i.src_inode->v.i_mode) && + inode_attrs_changing(i.dst_dir, i.src_inode)) { + ret = -EXDEV; + goto err; + } + + if (i.mode == BCH_RENAME_EXCHANGE && + S_ISDIR(i.dst_inode->v.i_mode) && + inode_attrs_changing(i.src_dir, i.dst_inode)) { + ret = -EXDEV; + goto err; + } + + if (inode_attr_changing(i.dst_dir, i.src_inode, Inode_opt_project)) { + ret = bch2_fs_quota_transfer(c, i.src_inode, + i.dst_dir->ei_qid, + 1 << QTYP_PRJ, + KEY_TYPE_QUOTA_PREALLOC); + if (ret) + goto err; + } + + if (i.mode == BCH_RENAME_EXCHANGE && + inode_attr_changing(i.src_dir, i.dst_inode, Inode_opt_project)) { + ret = bch2_fs_quota_transfer(c, i.dst_inode, + i.src_dir->ei_qid, + 1 << QTYP_PRJ, + KEY_TYPE_QUOTA_PREALLOC); + if (ret) + goto err; + } + retry: bch2_trans_begin(&trans); i.now = bch2_current_time(c); @@ -792,6 +874,17 @@ retry: ATTR_CTIME); err: bch2_trans_exit(&trans); + + bch2_fs_quota_transfer(c, i.src_inode, + bch_qid(&i.src_inode->ei_inode), + 1 << QTYP_PRJ, + KEY_TYPE_QUOTA_NOCHECK); + if (i.dst_inode) + bch2_fs_quota_transfer(c, i.dst_inode, + bch_qid(&i.dst_inode->ei_inode), + 1 << QTYP_PRJ, + KEY_TYPE_QUOTA_NOCHECK); + bch2_unlock_inodes(i.src_dir, i.dst_dir, i.src_inode, @@ -838,36 +931,26 @@ static int inode_update_for_setattr_fn(struct bch_inode_info *inode, static int bch2_setattr_nonsize(struct bch_inode_info *inode, struct iattr *iattr) { struct bch_fs *c = inode->v.i_sb->s_fs_info; - struct bch_qid qid = inode->ei_qid; + struct bch_qid qid; struct btree_trans trans; struct bch_inode_unpacked inode_u; struct posix_acl *acl = NULL; - unsigned qtypes = 0; int ret; mutex_lock(&inode->ei_update_lock); - if (c->opts.usrquota && - (iattr->ia_valid & ATTR_UID) && - !uid_eq(iattr->ia_uid, inode->v.i_uid)) { - qid.q[QTYP_USR] = from_kuid(&init_user_ns, iattr->ia_uid), - qtypes |= 1 << QTYP_USR; - } + qid = inode->ei_qid; - if (c->opts.grpquota && - (iattr->ia_valid & ATTR_GID) && - !gid_eq(iattr->ia_gid, inode->v.i_gid)) { + if (iattr->ia_valid & ATTR_UID) + qid.q[QTYP_USR] = from_kuid(&init_user_ns, iattr->ia_uid); + + if (iattr->ia_valid & ATTR_GID) qid.q[QTYP_GRP] = from_kgid(&init_user_ns, iattr->ia_gid); - qtypes |= 1 << QTYP_GRP; - } - if (qtypes) { - ret = bch2_quota_transfer(c, qtypes, qid, inode->ei_qid, - inode->v.i_blocks + - inode->ei_quota_reserved); - if (ret) - goto err; - } + ret = bch2_fs_quota_transfer(c, inode, qid, ~0, + KEY_TYPE_QUOTA_PREALLOC); + if (ret) + goto err; bch2_trans_init(&trans, c); retry: @@ -1228,6 +1311,7 @@ static void bch2_vfs_inode_init(struct bch_fs *c, inode->ei_journal_seq = 0; inode->ei_quota_reserved = 0; inode->ei_str_hash = bch2_hash_info_init(c, bi); + inode->ei_qid = bch_qid(bi); inode->v.i_mapping->a_ops = &bch_address_space_operations; diff --git a/libbcachefs/fs.h b/libbcachefs/fs.h index a434c757..7dc0453a 100644 --- a/libbcachefs/fs.h +++ b/libbcachefs/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)); @@ -49,10 +73,39 @@ static inline u64 bch2_current_time(struct bch_fs *c) return timespec_to_bch2_time(c, current_kernel_time64()); } +static inline bool inode_attr_changing(struct bch_inode_info *dir, + struct bch_inode_info *inode, + enum inode_opt_id id) +{ + return !(inode->ei_inode.bi_fields_set & (1 << id)) && + bch2_inode_opt_get(&dir->ei_inode, id) != + bch2_inode_opt_get(&inode->ei_inode, id); +} + +static inline bool inode_attrs_changing(struct bch_inode_info *dir, + struct bch_inode_info *inode) +{ + unsigned id; + + for (id = 0; id < Inode_opt_nr; id++) + if (inode_attr_changing(dir, inode, id)) + return true; + + return false; +} + struct bch_inode_unpacked; #ifndef NO_BCACHEFS_FS +int bch2_fs_quota_transfer(struct bch_fs *, + struct bch_inode_info *, + struct bch_qid, + 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 *); @@ -68,6 +121,10 @@ int __must_check bch2_write_inode_trans(struct btree_trans *, int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *, inode_set_fn, void *, unsigned); +int bch2_reinherit_attrs_fn(struct bch_inode_info *, + struct bch_inode_unpacked *, + void *); + void bch2_vfs_exit(void); int bch2_vfs_init(void); diff --git a/libbcachefs/inode.c b/libbcachefs/inode.c index 8c3d4431..f851e3b7 100644 --- a/libbcachefs/inode.c +++ b/libbcachefs/inode.c @@ -12,7 +12,12 @@ #include -#define FIELD_BYTES() \ +const char * const bch2_inode_opts[] = { +#define x(name, ...) #name, + BCH_INODE_OPTS() +#undef x + NULL, +}; static const u8 byte_table[8] = { 1, 2, 3, 4, 6, 8, 10, 13 }; static const u8 bits_table[8] = { @@ -97,7 +102,7 @@ void bch2_inode_pack(struct bkey_inode_buf *packed, packed->inode.v.bi_flags = cpu_to_le32(inode->bi_flags); packed->inode.v.bi_mode = cpu_to_le16(inode->bi_mode); -#define BCH_INODE_FIELD(_name, _bits) \ +#define x(_name, _bits) \ out += inode_encode_field(out, end, 0, inode->_name); \ nr_fields++; \ \ @@ -107,7 +112,7 @@ void bch2_inode_pack(struct bkey_inode_buf *packed, } BCH_INODE_FIELDS() -#undef BCH_INODE_FIELD +#undef x out = last_nonzero_field; nr_fields = last_nonzero_fieldnr; @@ -129,9 +134,9 @@ void bch2_inode_pack(struct bkey_inode_buf *packed, BUG_ON(unpacked.bi_hash_seed != inode->bi_hash_seed); BUG_ON(unpacked.bi_mode != inode->bi_mode); -#define BCH_INODE_FIELD(_name, _bits) BUG_ON(unpacked._name != inode->_name); +#define x(_name, _bits) BUG_ON(unpacked._name != inode->_name); BCH_INODE_FIELDS() -#undef BCH_INODE_FIELD +#undef x } } @@ -149,7 +154,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode, unpacked->bi_flags = le32_to_cpu(inode.v->bi_flags); unpacked->bi_mode = le16_to_cpu(inode.v->bi_mode); -#define BCH_INODE_FIELD(_name, _bits) \ +#define x(_name, _bits) \ if (fieldnr++ == INODE_NR_FIELDS(inode.v)) { \ memset(&unpacked->_name, 0, \ sizeof(*unpacked) - \ @@ -168,7 +173,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode, in += ret; BCH_INODE_FIELDS() -#undef BCH_INODE_FIELD +#undef x /* XXX: signal if there were more fields than expected? */ @@ -219,10 +224,10 @@ void bch2_inode_to_text(struct printbuf *out, struct bch_fs *c, return; } -#define BCH_INODE_FIELD(_name, _bits) \ +#define x(_name, _bits) \ pr_buf(out, #_name ": %llu ", (u64) unpacked._name); BCH_INODE_FIELDS() -#undef BCH_INODE_FIELD +#undef x } const char *bch2_inode_generation_invalid(const struct bch_fs *c, @@ -254,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; @@ -266,9 +272,9 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, inode_u->bi_otime = now; if (parent) { -#define BCH_INODE_FIELD(_name) inode_u->_name = parent->_name; - BCH_INODE_FIELDS_INHERIT() -#undef BCH_INODE_FIELD +#define x(_name, ...) inode_u->bi_##_name = parent->bi_##_name; + BCH_INODE_OPTS() +#undef x } } diff --git a/libbcachefs/inode.h b/libbcachefs/inode.h index 44855e1a..0d609985 100644 --- a/libbcachefs/inode.h +++ b/libbcachefs/inode.h @@ -5,6 +5,8 @@ #include +extern const char * const bch2_inode_opts[]; + const char *bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c); void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); @@ -29,17 +31,17 @@ struct bch_inode_unpacked { u32 bi_flags; u16 bi_mode; -#define BCH_INODE_FIELD(_name, _bits) u##_bits _name; +#define x(_name, _bits) u##_bits _name; BCH_INODE_FIELDS() -#undef BCH_INODE_FIELD +#undef x }; struct bkey_inode_buf { struct bkey_i_inode inode; -#define BCH_INODE_FIELD(_name, _bits) + 8 + _bits / 8 +#define x(_name, _bits) + 8 + _bits / 8 u8 _pad[0 + BCH_INODE_FIELDS()]; -#undef BCH_INODE_FIELD +#undef x } __attribute__((packed, aligned(8))); void bch2_inode_pack(struct bkey_inode_buf *, const struct bch_inode_unpacked *); @@ -79,39 +81,41 @@ static inline struct bch_io_opts bch2_inode_opts_get(struct bch_inode_unpacked * { struct bch_io_opts ret = { 0 }; -#define BCH_INODE_OPT(_name, _bits) \ +#define x(_name, _bits) \ if (inode->bi_##_name) \ opt_set(ret, _name, inode->bi_##_name - 1); BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x return ret; } -static inline void __bch2_inode_opt_set(struct bch_inode_unpacked *inode, - enum bch_opt_id id, u64 v) +static inline void bch2_inode_opt_set(struct bch_inode_unpacked *inode, + enum inode_opt_id id, u64 v) { switch (id) { -#define BCH_INODE_OPT(_name, ...) \ - case Opt_##_name: \ +#define x(_name, ...) \ + case Inode_opt_##_name: \ inode->bi_##_name = v; \ break; BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x default: BUG(); } } -static inline void bch2_inode_opt_set(struct bch_inode_unpacked *inode, - enum bch_opt_id id, u64 v) -{ - return __bch2_inode_opt_set(inode, id, v + 1); -} - -static inline void bch2_inode_opt_clear(struct bch_inode_unpacked *inode, - enum bch_opt_id id) +static inline u64 bch2_inode_opt_get(struct bch_inode_unpacked *inode, + enum inode_opt_id id) { - return __bch2_inode_opt_set(inode, id, 0); + switch (id) { +#define x(_name, ...) \ + case Inode_opt_##_name: \ + return inode->bi_##_name; + BCH_INODE_OPTS() +#undef x + default: + BUG(); + } } #ifdef CONFIG_BCACHEFS_DEBUG diff --git a/libbcachefs/opts.c b/libbcachefs/opts.c index 449cd5bf..4739f782 100644 --- a/libbcachefs/opts.c +++ b/libbcachefs/opts.c @@ -376,40 +376,40 @@ no_val: struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src) { struct bch_io_opts ret = { 0 }; -#define BCH_INODE_OPT(_name, _bits) \ +#define x(_name, _bits) \ if (opt_defined(src, _name)) \ opt_set(ret, _name, src._name); BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x return ret; } struct bch_opts bch2_inode_opts_to_opts(struct bch_io_opts src) { struct bch_opts ret = { 0 }; -#define BCH_INODE_OPT(_name, _bits) \ +#define x(_name, _bits) \ if (opt_defined(src, _name)) \ opt_set(ret, _name, src._name); BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x return ret; } void bch2_io_opts_apply(struct bch_io_opts *dst, struct bch_io_opts src) { -#define BCH_INODE_OPT(_name, _bits) \ +#define x(_name, _bits) \ if (opt_defined(src, _name)) \ opt_set(*dst, _name, src._name); BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x } bool bch2_opt_is_inode_opt(enum bch_opt_id id) { static const enum bch_opt_id inode_opt_list[] = { -#define BCH_INODE_OPT(_name, _bits) Opt_##_name, +#define x(_name, _bits) Opt_##_name, BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x }; unsigned i; diff --git a/libbcachefs/opts.h b/libbcachefs/opts.h index 5c744018..8a4e2e50 100644 --- a/libbcachefs/opts.h +++ b/libbcachefs/opts.h @@ -184,7 +184,10 @@ enum opt_type { NO_SB_OPT, false) \ BCH_OPT(version_upgrade, u8, OPT_MOUNT, \ OPT_BOOL(), \ - NO_SB_OPT, false) + NO_SB_OPT, false) \ + BCH_OPT(project, u8, OPT_INTERNAL, \ + OPT_BOOL(), \ + NO_SB_OPT, false) \ struct bch_opts { #define BCH_OPT(_name, _bits, ...) unsigned _name##_defined:1; @@ -277,24 +280,14 @@ int bch2_parse_mount_opts(struct bch_opts *, char *); /* inode opts: */ -#define BCH_INODE_OPTS() \ - BCH_INODE_OPT(data_checksum, 8) \ - BCH_INODE_OPT(compression, 8) \ - BCH_INODE_OPT(background_compression, 8) \ - BCH_INODE_OPT(data_replicas, 8) \ - BCH_INODE_OPT(promote_target, 16) \ - BCH_INODE_OPT(foreground_target, 16) \ - BCH_INODE_OPT(background_target, 16) \ - BCH_INODE_OPT(erasure_code, 16) - struct bch_io_opts { -#define BCH_INODE_OPT(_name, _bits) unsigned _name##_defined:1; +#define x(_name, _bits) unsigned _name##_defined:1; BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x -#define BCH_INODE_OPT(_name, _bits) u##_bits _name; +#define x(_name, _bits) u##_bits _name; BCH_INODE_OPTS() -#undef BCH_INODE_OPT +#undef x }; struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts); diff --git a/libbcachefs/quota.c b/libbcachefs/quota.c index 95ff0cae..44aacd40 100644 --- a/libbcachefs/quota.c +++ b/libbcachefs/quota.c @@ -269,7 +269,8 @@ static void __bch2_quota_transfer(struct bch_memquota *src_q, int bch2_quota_transfer(struct bch_fs *c, unsigned qtypes, struct bch_qid dst, - struct bch_qid src, u64 space) + struct bch_qid src, u64 space, + enum quota_acct_mode mode) { struct bch_memquota_type *q; struct bch_memquota *src_q[3], *dst_q[3]; @@ -295,13 +296,13 @@ int bch2_quota_transfer(struct bch_fs *c, unsigned qtypes, ret = bch2_quota_check_limit(c, i, dst_q[i], &msgs, Q_SPC, dst_q[i]->c[Q_SPC].v + space, - KEY_TYPE_QUOTA_PREALLOC); + mode); if (ret) goto err; ret = bch2_quota_check_limit(c, i, dst_q[i], &msgs, Q_INO, dst_q[i]->c[Q_INO].v + 1, - KEY_TYPE_QUOTA_PREALLOC); + mode); if (ret) goto err; } diff --git a/libbcachefs/quota.h b/libbcachefs/quota.h index 0c3eb697..eabb94c1 100644 --- a/libbcachefs/quota.h +++ b/libbcachefs/quota.h @@ -14,12 +14,6 @@ void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); .val_to_text = bch2_quota_to_text, \ } -enum quota_acct_mode { - KEY_TYPE_QUOTA_PREALLOC, - KEY_TYPE_QUOTA_WARN, - KEY_TYPE_QUOTA_NOCHECK, -}; - static inline struct bch_qid bch_qid(struct bch_inode_unpacked *u) { return (struct bch_qid) { @@ -42,7 +36,7 @@ int bch2_quota_acct(struct bch_fs *, struct bch_qid, enum quota_counters, s64, enum quota_acct_mode); int bch2_quota_transfer(struct bch_fs *, unsigned, struct bch_qid, - struct bch_qid, u64); + struct bch_qid, u64, enum quota_acct_mode); void bch2_fs_quota_exit(struct bch_fs *); void bch2_fs_quota_init(struct bch_fs *); diff --git a/libbcachefs/quota_types.h b/libbcachefs/quota_types.h index bcaed4ea..e978dc54 100644 --- a/libbcachefs/quota_types.h +++ b/libbcachefs/quota_types.h @@ -7,6 +7,12 @@ struct bch_qid { u32 q[QTYP_NR]; }; +enum quota_acct_mode { + KEY_TYPE_QUOTA_PREALLOC, + KEY_TYPE_QUOTA_WARN, + KEY_TYPE_QUOTA_NOCHECK, +}; + struct memquota_counter { u64 v; u64 hardlimit; diff --git a/libbcachefs/xattr.c b/libbcachefs/xattr.c index 85d8bdd3..407177b2 100644 --- a/libbcachefs/xattr.c +++ b/libbcachefs/xattr.c @@ -197,40 +197,83 @@ int bch2_xattr_set(struct btree_trans *trans, u64 inum, return ret; } -static size_t bch2_xattr_emit(struct dentry *dentry, - const struct bch_xattr *xattr, - char *buffer, size_t buffer_size) +static void __bch2_xattr_emit(const char *prefix, + const char *name, size_t name_len, + char **buffer, size_t *buffer_size, + ssize_t *ret) +{ + const size_t prefix_len = strlen(prefix); + const size_t total_len = prefix_len + name_len + 1; + + if (*buffer) { + if (total_len > *buffer_size) { + *ret = -ERANGE; + return; + } + + memcpy(*buffer, prefix, prefix_len); + memcpy(*buffer + prefix_len, + name, name_len); + (*buffer)[prefix_len + name_len] = '\0'; + + *buffer += total_len; + *buffer_size -= total_len; + } + + *ret += total_len; +} + +static void bch2_xattr_emit(struct dentry *dentry, + const struct bch_xattr *xattr, + char **buffer, size_t *buffer_size, + ssize_t *ret) { const struct xattr_handler *handler = bch2_xattr_type_to_handler(xattr->x_type); - if (handler && (!handler->list || handler->list(dentry))) { - const char *prefix = handler->prefix ?: handler->name; - const size_t prefix_len = strlen(prefix); - const size_t total_len = prefix_len + xattr->x_name_len + 1; + if (handler && (!handler->list || handler->list(dentry))) + __bch2_xattr_emit(handler->prefix ?: handler->name, + xattr->x_name, xattr->x_name_len, + buffer, buffer_size, ret); +} - if (buffer && total_len <= buffer_size) { - memcpy(buffer, prefix, prefix_len); - memcpy(buffer + prefix_len, - xattr->x_name, xattr->x_name_len); - buffer[prefix_len + xattr->x_name_len] = '\0'; - } +static void bch2_xattr_list_bcachefs(struct bch_fs *c, + struct bch_inode_info *inode, + char **buffer, + size_t *buffer_size, + ssize_t *ret, + bool all) +{ + const char *prefix = all ? "bcachefs_effective." : "bcachefs."; + unsigned id; + u64 v; - return total_len; - } else { - return 0; + for (id = 0; id < Inode_opt_nr; id++) { + v = bch2_inode_opt_get(&inode->ei_inode, id); + if (!v) + continue; + + if (!all && + !(inode->ei_inode.bi_fields_set & (1 << id))) + continue; + + __bch2_xattr_emit(prefix, + bch2_inode_opts[id], + strlen(bch2_inode_opts[id]), + buffer, buffer_size, ret); + if (*ret < 0) + break; } } ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) { struct bch_fs *c = dentry->d_sb->s_fs_info; + struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); struct btree_iter iter; struct bkey_s_c k; - const struct bch_xattr *xattr; u64 inum = dentry->d_inode->i_ino; ssize_t ret = 0; - size_t len; for_each_btree_key(&iter, c, BTREE_ID_XATTRS, POS(inum, 0), 0, k) { BUG_ON(k.k->p.inode < inum); @@ -241,23 +284,25 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) if (k.k->type != KEY_TYPE_xattr) continue; - xattr = bkey_s_c_to_xattr(k).v; - - len = bch2_xattr_emit(dentry, xattr, buffer, buffer_size); - if (buffer) { - if (len > buffer_size) { - bch2_btree_iter_unlock(&iter); - return -ERANGE; - } + bch2_xattr_emit(dentry, bkey_s_c_to_xattr(k).v, + &buffer, &buffer_size, &ret); + if (ret < 0) + break; + } + bch2_btree_iter_unlock(&iter); - buffer += len; - buffer_size -= len; - } + if (ret < 0) + return ret; - ret += len; + bch2_xattr_list_bcachefs(c, inode, &buffer, + &buffer_size, &ret, false); + if (ret < 0) + return ret; - } - bch2_btree_iter_unlock(&iter); + bch2_xattr_list_bcachefs(c, inode, &buffer, + &buffer_size, &ret, true); + if (ret < 0) + return ret; return ret; } @@ -316,27 +361,48 @@ static const struct xattr_handler bch_xattr_security_handler = { #ifndef NO_BCACHEFS_FS -static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, - struct dentry *dentry, struct inode *vinode, - const char *name, void *buffer, size_t size) +static int opt_to_inode_opt(int id) +{ + switch (id) { +#define x(name, ...) \ + case Opt_##name: return Inode_opt_##name; + BCH_INODE_OPTS() +#undef x + default: + return -1; + } +} + +static int __bch2_xattr_bcachefs_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *vinode, + const char *name, void *buffer, size_t size, + bool all) { struct bch_inode_info *inode = to_bch_ei(vinode); struct bch_fs *c = inode->v.i_sb->s_fs_info; struct bch_opts opts = bch2_inode_opts_to_opts(bch2_inode_opts_get(&inode->ei_inode)); const struct bch_option *opt; - int id; + int id, inode_opt_id; u64 v; id = bch2_opt_lookup(name); if (id < 0 || !bch2_opt_is_inode_opt(id)) return -EINVAL; + inode_opt_id = opt_to_inode_opt(id); + if (inode_opt_id < 0) + return -EINVAL; + opt = bch2_opt_table + id; if (!bch2_opt_defined_by_id(&opts, id)) return -ENODATA; + if (!all && + !(inode->ei_inode.bi_fields_set & (1 << inode_opt_id))) + return -ENODATA; + v = bch2_opt_get_by_id(&opts, id); if (!buffer) { @@ -357,6 +423,14 @@ static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, } } +static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *vinode, + const char *name, void *buffer, size_t size) +{ + return __bch2_xattr_bcachefs_get(handler, dentry, vinode, + name, buffer, size, false); +} + struct inode_opt_set { int id; u64 v; @@ -370,9 +444,12 @@ static int inode_opt_set_fn(struct bch_inode_info *inode, struct inode_opt_set *s = p; if (s->defined) - bch2_inode_opt_set(bi, s->id, s->v); + bi->bi_fields_set |= 1U << s->id; else - bch2_inode_opt_clear(bi, s->id); + bi->bi_fields_set &= ~(1U << s->id); + + bch2_inode_opt_set(bi, s->id, s->v); + return 0; } @@ -386,33 +463,51 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler, const struct bch_option *opt; char *buf; struct inode_opt_set s; - int ret; + int opt_id, inode_opt_id, ret; + + opt_id = bch2_opt_lookup(name); + if (opt_id < 0) + return -EINVAL; - s.id = bch2_opt_lookup(name); - if (s.id < 0 || !bch2_opt_is_inode_opt(s.id)) + opt = bch2_opt_table + opt_id; + + inode_opt_id = opt_to_inode_opt(opt_id); + if (inode_opt_id < 0) return -EINVAL; - opt = bch2_opt_table + s.id; + s.id = inode_opt_id; if (value) { + u64 v = 0; + buf = kmalloc(size + 1, GFP_KERNEL); if (!buf) return -ENOMEM; memcpy(buf, value, size); buf[size] = '\0'; - ret = bch2_opt_parse(c, opt, buf, &s.v); + ret = bch2_opt_parse(c, opt, buf, &v); kfree(buf); if (ret < 0) return ret; - ret = bch2_opt_check_may_set(c, s.id, s.v); + ret = bch2_opt_check_may_set(c, opt_id, v); if (ret < 0) return ret; + s.v = v + 1; s.defined = true; } else { + if (!IS_ROOT(dentry)) { + struct bch_inode_info *dir = + to_bch_ei(d_inode(dentry->d_parent)); + + s.v = bch2_inode_opt_get(&dir->ei_inode, inode_opt_id); + } else { + s.v = 0; + } + s.defined = false; } @@ -421,8 +516,8 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler, mutex_unlock(&inode->ei_update_lock); if (value && - (s.id == Opt_background_compression || - s.id == Opt_background_target)) + (opt_id == Opt_background_compression || + opt_id == Opt_background_target)) bch2_rebalance_add_work(c, inode->v.i_blocks); return ret; @@ -434,6 +529,21 @@ static const struct xattr_handler bch_xattr_bcachefs_handler = { .set = bch2_xattr_bcachefs_set, }; +static int bch2_xattr_bcachefs_get_effective( + const struct xattr_handler *handler, + struct dentry *dentry, struct inode *vinode, + const char *name, void *buffer, size_t size) +{ + return __bch2_xattr_bcachefs_get(handler, dentry, vinode, + name, buffer, size, true); +} + +static const struct xattr_handler bch_xattr_bcachefs_effective_handler = { + .prefix = "bcachefs_effective.", + .get = bch2_xattr_bcachefs_get_effective, + .set = bch2_xattr_bcachefs_set, +}; + #endif /* NO_BCACHEFS_FS */ const struct xattr_handler *bch2_xattr_handlers[] = { @@ -444,6 +554,7 @@ const struct xattr_handler *bch2_xattr_handlers[] = { &bch_xattr_security_handler, #ifndef NO_BCACHEFS_FS &bch_xattr_bcachefs_handler, + &bch_xattr_bcachefs_effective_handler, #endif NULL }; -- cgit v1.2.3