diff --git a/fs/fs/xattr.c b/fs/fs/xattr.c index e2f34f433..61fa763a2 100644 --- a/fs/fs/xattr.c +++ b/fs/fs/xattr.c @@ -163,6 +163,36 @@ static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info return ret; } +int __bch2_xattr_set(struct btree_trans *trans, subvol_inum inum, + const struct bch_hash_info *hash_info, + const char *name, const void *value, size_t size, + int type, int flags) +{ + struct bkey_i_xattr *xattr; + unsigned namelen = strlen(name); + unsigned u64s = BKEY_U64s + xattr_val_u64s(namelen, size); + + if (u64s > U8_MAX) + return -ERANGE; + + xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64)); + if (IS_ERR(xattr)) + return PTR_ERR(xattr); + + bkey_xattr_init(&xattr->k_i); + xattr->k.u64s = u64s; + xattr->v.x_type = type; + xattr->v.x_name_len = namelen; + xattr->v.x_val_len = cpu_to_le16(size); + memcpy(xattr->v.x_name_and_value, name, namelen); + memcpy(xattr_val(&xattr->v), value, size); + + return bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info, + inum, &xattr->k_i, + (flags & XATTR_CREATE ? STR_HASH_must_create : 0)| + (flags & XATTR_REPLACE ? STR_HASH_must_replace : 0)); +} + int bch2_xattr_set(struct btree_trans *trans, subvol_inum inum, struct bch_inode_unpacked *inode_u, const char *name, const void *value, size_t size, @@ -190,30 +220,8 @@ int bch2_xattr_set(struct btree_trans *trans, subvol_inum inum, int ret; if (value) { - struct bkey_i_xattr *xattr; - unsigned namelen = strlen(name); - unsigned u64s = BKEY_U64s + - xattr_val_u64s(namelen, size); - - if (u64s > U8_MAX) - return -ERANGE; - - xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64)); - if (IS_ERR(xattr)) - return PTR_ERR(xattr); - - bkey_xattr_init(&xattr->k_i); - xattr->k.u64s = u64s; - xattr->v.x_type = type; - xattr->v.x_name_len = namelen; - xattr->v.x_val_len = cpu_to_le16(size); - memcpy(xattr->v.x_name_and_value, name, namelen); - memcpy(xattr_val(&xattr->v), value, size); - - ret = bch2_hash_set(trans, bch2_xattr_hash_desc, &hash_info, - inum, &xattr->k_i, - (flags & XATTR_CREATE ? STR_HASH_must_create : 0)| - (flags & XATTR_REPLACE ? STR_HASH_must_replace : 0)); + ret = __bch2_xattr_set(trans, inum, &hash_info, + name, value, size, type, flags); } else { struct xattr_search_key search = X_SEARCH(type, name, strlen(name)); diff --git a/fs/fs/xattr.h b/fs/fs/xattr.h index c57147651..ccb3504ff 100644 --- a/fs/fs/xattr.h +++ b/fs/fs/xattr.h @@ -38,6 +38,10 @@ struct xattr_handler; struct bch_hash_info; struct bch_inode_info; +int __bch2_xattr_set(struct btree_trans *, subvol_inum, + const struct bch_hash_info *, + const char *, const void *, size_t, int, int); + /* Exported for cmd_migrate.c in tools: */ int bch2_xattr_set(struct btree_trans *, subvol_inum, struct bch_inode_unpacked *, diff --git a/fs/vfs/fs.c b/fs/vfs/fs.c index 37df8f515..14f9f7bc3 100644 --- a/fs/vfs/fs.c +++ b/fs/vfs/fs.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -573,6 +574,55 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum, return ret ? ERR_PTR(ret) : &inode->v; } +struct bch2_initxattrs_ctx { + struct btree_trans *trans; + subvol_inum inum; + struct bch_hash_info hash; +}; + +static int bch2_initxattrs(struct inode *vinode, + const struct xattr *xattr_array, + void *fs_data) +{ + struct bch2_initxattrs_ctx *ctx = fs_data; + const struct xattr *xattr; + + for (xattr = xattr_array; xattr->name; xattr++) { + int ret = __bch2_xattr_set(ctx->trans, ctx->inum, &ctx->hash, + xattr->name, xattr->value, + xattr->value_len, + KEY_TYPE_XATTR_INDEX_SECURITY, + XATTR_CREATE); + if (ret) + return ret; + } + + return 0; +} + +static int bch2_inode_init_security(struct btree_trans *trans, + struct bch_inode_info *dir, + struct bch_inode_info *inode, + struct dentry *dentry, + subvol_inum inum, + struct bch_inode_unpacked *inode_u) +{ + struct bch2_initxattrs_ctx ctx = { + .trans = trans, + .inum = inum, + }; + + inode->v.i_ino = inum.inum; + inode->ei_inum = inum; + inode->ei_inode.bi_inum = inum.inum; + bch2_inode_update_after_write(trans, inode, inode_u, ~0); + + try(bch2_hash_info_init(trans->c, inode_u, &ctx.hash)); + + return security_inode_init_security(&inode->v, &dir->v, &dentry->d_name, + bch2_initxattrs, &ctx); +} + struct bch_inode_info * __bch2_create(struct mnt_idmap *idmap, struct bch_inode_info *dir, struct dentry *dentry, @@ -636,8 +686,13 @@ __bch2_create(struct mnt_idmap *idmap, inum.subvol = inode_u.bi_subvol ?: dir->ei_inum.subvol; inum.inum = inode_u.bi_inum; + ret = bch2_inode_init_security(trans, dir, inode, dentry, inum, &inode_u); + if (unlikely(ret)) + goto err_after_quota; + ret = bch2_trans_commit(trans, NULL, NULL, 0); if (unlikely(ret)) { +err_after_quota: bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1, KEY_TYPE_QUOTA_WARN); err_before_quota: