X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Facl.c;h=f3809897f00a7d5c98c7f33f36bc2fd587939dcc;hb=8d8a9f3e9bdd1d84fbbe0531e81977cc9044654a;hp=e1c7b87d61897364a66757bf74069c382ea7cf50;hpb=ddb58076ef4fe4572ab8537785fc67052f47bf5b;p=bcachefs-tools-debian diff --git a/libbcachefs/acl.c b/libbcachefs/acl.c index e1c7b87..f380989 100644 --- a/libbcachefs/acl.c +++ b/libbcachefs/acl.c @@ -1,17 +1,71 @@ -#ifdef CONFIG_BCACHEFS_POSIX_ACL +// SPDX-License-Identifier: GPL-2.0 #include "bcachefs.h" -#include +#include "acl.h" +#include "xattr.h" + #include + +static const char * const acl_types[] = { + [ACL_USER_OBJ] = "user_obj", + [ACL_USER] = "user", + [ACL_GROUP_OBJ] = "group_obj", + [ACL_GROUP] = "group", + [ACL_MASK] = "mask", + [ACL_OTHER] = "other", + NULL, +}; + +void bch2_acl_to_text(struct printbuf *out, const void *value, size_t size) +{ + const void *p, *end = value + size; + + if (!value || + size < sizeof(bch_acl_header) || + ((bch_acl_header *)value)->a_version != cpu_to_le32(BCH_ACL_VERSION)) + return; + + p = value + sizeof(bch_acl_header); + while (p < end) { + const bch_acl_entry *in = p; + unsigned tag = le16_to_cpu(in->e_tag); + + prt_str(out, acl_types[tag]); + + switch (tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + p += sizeof(bch_acl_entry_short); + break; + case ACL_USER: + prt_printf(out, " uid %u", le32_to_cpu(in->e_id)); + p += sizeof(bch_acl_entry); + break; + case ACL_GROUP: + prt_printf(out, " gid %u", le32_to_cpu(in->e_id)); + p += sizeof(bch_acl_entry); + break; + } + + prt_printf(out, " %o", le16_to_cpu(in->e_perm)); + + if (p != end) + prt_char(out, ' '); + } +} + +#ifdef CONFIG_BCACHEFS_POSIX_ACL + +#include "fs.h" + +#include #include #include #include -#include "acl.h" -#include "fs.h" -#include "xattr.h" - static inline size_t bch2_acl_size(unsigned nr_short, unsigned nr_long) { return sizeof(bch_acl_header) + @@ -34,12 +88,14 @@ static inline int acl_to_xattr_type(int type) /* * Convert from filesystem to in-memory representation. */ -static struct posix_acl *bch2_acl_from_disk(const void *value, size_t size) +static struct posix_acl *bch2_acl_from_disk(struct btree_trans *trans, + const void *value, size_t size) { const void *p, *end = value + size; struct posix_acl *acl; struct posix_acl_entry *out; unsigned count = 0; + int ret; if (!value) return NULL; @@ -80,9 +136,14 @@ static struct posix_acl *bch2_acl_from_disk(const void *value, size_t size) if (!count) return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); + acl = allocate_dropping_locks(trans, ret, + posix_acl_alloc(count, _gfp)); if (!acl) return ERR_PTR(-ENOMEM); + if (ret) { + kfree(acl); + return ERR_PTR(ret); + } out = acl->a_entries; @@ -172,7 +233,7 @@ bch2_acl_to_xattr(struct btree_trans *trans, bkey_xattr_init(&xattr->k_i); xattr->k.u64s = u64s; xattr->v.x_type = acl_to_xattr_type(type); - xattr->v.x_name_len = 0, + xattr->v.x_name_len = 0; xattr->v.x_val_len = cpu_to_le16(acl_len); acl_header = xattr_val(&xattr->v); @@ -211,49 +272,57 @@ bch2_acl_to_xattr(struct btree_trans *trans, return xattr; } -struct posix_acl *bch2_get_acl(struct inode *vinode, int type) +struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap, + struct dentry *dentry, int type) { - struct bch_inode_info *inode = to_bch_ei(vinode); + struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); struct bch_fs *c = inode->v.i_sb->s_fs_info; - struct btree_trans trans; - struct btree_iter *iter; + struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode); + struct xattr_search_key search = X_SEARCH(acl_to_xattr_type(type), "", 0); + struct btree_trans *trans = bch2_trans_get(c); + struct btree_iter iter = { NULL }; struct bkey_s_c_xattr xattr; struct posix_acl *acl = NULL; - - bch2_trans_init(&trans, c); + struct bkey_s_c k; + int ret; retry: - bch2_trans_begin(&trans); - - iter = bch2_hash_lookup(&trans, bch2_xattr_hash_desc, - &inode->ei_str_hash, inode->v.i_ino, - &X_SEARCH(acl_to_xattr_type(type), "", 0), - 0); - if (IS_ERR(iter)) { - if (PTR_ERR(iter) == -EINTR) - goto retry; - - if (PTR_ERR(iter) != -ENOENT) - acl = ERR_CAST(iter); + bch2_trans_begin(trans); + + ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, + &hash, inode_inum(inode), &search, 0); + if (ret) { + if (!bch2_err_matches(ret, ENOENT)) + acl = ERR_PTR(ret); goto out; } - xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter)); + k = bch2_btree_iter_peek_slot(&iter); + ret = bkey_err(k); + if (ret) { + acl = ERR_PTR(ret); + goto out; + } - acl = bch2_acl_from_disk(xattr_val(xattr.v), + xattr = bkey_s_c_to_xattr(k); + acl = bch2_acl_from_disk(trans, xattr_val(xattr.v), le16_to_cpu(xattr.v->x_val_len)); if (!IS_ERR(acl)) set_cached_acl(&inode->v, type, acl); out: - bch2_trans_exit(&trans); + if (bch2_err_matches(PTR_ERR_OR_ZERO(acl), BCH_ERR_transaction_restart)) + goto retry; + + bch2_trans_iter_exit(trans, &iter); + bch2_trans_put(trans); return acl; } -int bch2_set_acl_trans(struct btree_trans *trans, +int bch2_set_acl_trans(struct btree_trans *trans, subvol_inum inum, struct bch_inode_unpacked *inode_u, - const struct bch_hash_info *hash_info, struct posix_acl *acl, int type) { + struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode_u); int ret; if (type == ACL_TYPE_DEFAULT && @@ -266,104 +335,111 @@ int bch2_set_acl_trans(struct btree_trans *trans, if (IS_ERR(xattr)) return PTR_ERR(xattr); - ret = bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info, - inode_u->bi_inum, &xattr->k_i, 0); + ret = bch2_hash_set(trans, bch2_xattr_hash_desc, &hash_info, + inum, &xattr->k_i, 0); } else { struct xattr_search_key search = X_SEARCH(acl_to_xattr_type(type), "", 0); - ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info, - inode_u->bi_inum, &search); + ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, &hash_info, + inum, &search); } - return ret == -ENOENT ? 0 : ret; -} - -static int inode_update_for_set_acl_fn(struct bch_inode_info *inode, - struct bch_inode_unpacked *bi, - void *p) -{ - struct bch_fs *c = inode->v.i_sb->s_fs_info; - umode_t mode = (unsigned long) p; - - bi->bi_ctime = bch2_current_time(c); - bi->bi_mode = mode; - return 0; + return bch2_err_matches(ret, ENOENT) ? 0 : ret; } -int bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type) +int bch2_set_acl(struct mnt_idmap *idmap, + struct dentry *dentry, + struct posix_acl *_acl, int type) { - struct bch_inode_info *inode = to_bch_ei(vinode); + struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); struct bch_fs *c = inode->v.i_sb->s_fs_info; - struct btree_trans trans; + struct btree_trans *trans = bch2_trans_get(c); + struct btree_iter inode_iter = { NULL }; struct bch_inode_unpacked inode_u; - umode_t mode = inode->v.i_mode; + struct posix_acl *acl; + umode_t mode; int ret; mutex_lock(&inode->ei_update_lock); - bch2_trans_init(&trans, c); +retry: + bch2_trans_begin(trans); + acl = _acl; + + ret = bch2_inode_peek(trans, &inode_iter, &inode_u, inode_inum(inode), + BTREE_ITER_INTENT); + if (ret) + goto btree_err; + + mode = inode_u.bi_mode; - if (type == ACL_TYPE_ACCESS && acl) { - ret = posix_acl_update_mode(&inode->v, &mode, &acl); + if (type == ACL_TYPE_ACCESS) { + ret = posix_acl_update_mode(idmap, &inode->v, &mode, &acl); if (ret) - goto err; + goto btree_err; } -retry: - bch2_trans_begin(&trans); - - ret = bch2_set_acl_trans(&trans, - &inode->ei_inode, - &inode->ei_str_hash, - acl, type) ?: - bch2_write_inode_trans(&trans, inode, &inode_u, - inode_update_for_set_acl_fn, - (void *)(unsigned long) mode) ?: - bch2_trans_commit(&trans, NULL, - &inode->ei_journal_seq, - BTREE_INSERT_ATOMIC| - BTREE_INSERT_NOUNLOCK); - if (ret == -EINTR) + + ret = bch2_set_acl_trans(trans, inode_inum(inode), &inode_u, acl, type); + if (ret) + goto btree_err; + + inode_u.bi_ctime = bch2_current_time(c); + inode_u.bi_mode = mode; + + ret = bch2_inode_write(trans, &inode_iter, &inode_u) ?: + bch2_trans_commit(trans, NULL, NULL, 0); +btree_err: + bch2_trans_iter_exit(trans, &inode_iter); + + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; if (unlikely(ret)) goto err; - bch2_inode_update_after_write(c, inode, &inode_u, + bch2_inode_update_after_write(trans, inode, &inode_u, ATTR_CTIME|ATTR_MODE); set_cached_acl(&inode->v, type, acl); err: - bch2_trans_exit(&trans); mutex_unlock(&inode->ei_update_lock); + bch2_trans_put(trans); return ret; } -int bch2_acl_chmod(struct btree_trans *trans, - struct bch_inode_info *inode, +int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum, + struct bch_inode_unpacked *inode, umode_t mode, struct posix_acl **new_acl) { - struct btree_iter *iter; + struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode); + struct xattr_search_key search = X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0); + struct btree_iter iter; struct bkey_s_c_xattr xattr; struct bkey_i_xattr *new; - struct posix_acl *acl; - int ret = 0; + struct posix_acl *acl = NULL; + struct bkey_s_c k; + int ret; - iter = bch2_hash_lookup(trans, bch2_xattr_hash_desc, - &inode->ei_str_hash, inode->v.i_ino, - &X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0), - BTREE_ITER_INTENT); - if (IS_ERR(iter)) - return PTR_ERR(iter) != -ENOENT ? PTR_ERR(iter) : 0; + ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, + &hash_info, inum, &search, BTREE_ITER_INTENT); + if (ret) + return bch2_err_matches(ret, ENOENT) ? 0 : ret; - xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter)); + k = bch2_btree_iter_peek_slot(&iter); + ret = bkey_err(k); + if (ret) + goto err; + xattr = bkey_s_c_to_xattr(k); - acl = bch2_acl_from_disk(xattr_val(xattr.v), + acl = bch2_acl_from_disk(trans, xattr_val(xattr.v), le16_to_cpu(xattr.v->x_val_len)); + ret = PTR_ERR_OR_ZERO(acl); if (IS_ERR_OR_NULL(acl)) - return PTR_ERR(acl); + goto err; - ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode); + ret = allocate_dropping_locks_errcode(trans, + __posix_acl_chmod(&acl, _gfp, mode)); if (ret) goto err; @@ -373,12 +449,14 @@ int bch2_acl_chmod(struct btree_trans *trans, goto err; } - new->k.p = iter->pos; - bch2_trans_update(trans, BTREE_INSERT_ENTRY(iter, &new->k_i)); + new->k.p = iter.pos; + ret = bch2_trans_update(trans, &iter, &new->k_i, 0); *new_acl = acl; acl = NULL; err: - kfree(acl); + bch2_trans_iter_exit(trans, &iter); + if (!IS_ERR_OR_NULL(acl)) + kfree(acl); return ret; }