1 #ifdef CONFIG_BCACHEFS_POSIX_ACL
6 #include <linux/posix_acl.h>
7 #include <linux/posix_acl_xattr.h>
8 #include <linux/sched.h>
9 #include <linux/slab.h>
15 static inline size_t bch2_acl_size(unsigned nr_short, unsigned nr_long)
17 return sizeof(bch_acl_header) +
18 sizeof(bch_acl_entry_short) * nr_short +
19 sizeof(bch_acl_entry) * nr_long;
22 static inline int acl_to_xattr_type(int type)
26 return BCH_XATTR_INDEX_POSIX_ACL_ACCESS;
27 case ACL_TYPE_DEFAULT:
28 return BCH_XATTR_INDEX_POSIX_ACL_DEFAULT;
35 * Convert from filesystem to in-memory representation.
37 static struct posix_acl *bch2_acl_from_disk(const void *value, size_t size)
39 const void *p, *end = value + size;
40 struct posix_acl *acl;
41 struct posix_acl_entry *out;
46 if (size < sizeof(bch_acl_header))
48 if (((bch_acl_header *)value)->a_version !=
49 cpu_to_le32(BCH_ACL_VERSION))
52 p = value + sizeof(bch_acl_header);
54 const bch_acl_entry *entry = p;
56 if (p + sizeof(bch_acl_entry_short) > end)
59 switch (le16_to_cpu(entry->e_tag)) {
64 p += sizeof(bch_acl_entry_short);
68 p += sizeof(bch_acl_entry);
83 acl = posix_acl_alloc(count, GFP_KERNEL);
85 return ERR_PTR(-ENOMEM);
89 p = value + sizeof(bch_acl_header);
91 const bch_acl_entry *in = p;
93 out->e_tag = le16_to_cpu(in->e_tag);
94 out->e_perm = le16_to_cpu(in->e_perm);
101 p += sizeof(bch_acl_entry_short);
104 out->e_uid = make_kuid(&init_user_ns,
105 le32_to_cpu(in->e_id));
106 p += sizeof(bch_acl_entry);
109 out->e_gid = make_kgid(&init_user_ns,
110 le32_to_cpu(in->e_id));
111 p += sizeof(bch_acl_entry);
118 BUG_ON(out != acl->a_entries + acl->a_count);
122 pr_err("invalid acl entry");
123 return ERR_PTR(-EINVAL);
126 #define acl_for_each_entry(acl, acl_e) \
127 for (acl_e = acl->a_entries; \
128 acl_e < acl->a_entries + acl->a_count; \
132 * Convert from in-memory to filesystem representation.
134 static struct bkey_i_xattr *
135 bch2_acl_to_xattr(struct btree_trans *trans,
136 const struct posix_acl *acl,
139 struct bkey_i_xattr *xattr;
140 bch_acl_header *acl_header;
141 const struct posix_acl_entry *acl_e;
143 unsigned nr_short = 0, nr_long = 0, acl_len, u64s;
145 acl_for_each_entry(acl, acl_e) {
146 switch (acl_e->e_tag) {
158 return ERR_PTR(-EINVAL);
162 acl_len = bch2_acl_size(nr_short, nr_long);
163 u64s = BKEY_U64s + xattr_val_u64s(0, acl_len);
166 return ERR_PTR(-E2BIG);
168 xattr = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
172 bkey_xattr_init(&xattr->k_i);
173 xattr->k.u64s = u64s;
174 xattr->v.x_type = acl_to_xattr_type(type);
175 xattr->v.x_name_len = 0,
176 xattr->v.x_val_len = cpu_to_le16(acl_len);
178 acl_header = xattr_val(&xattr->v);
179 acl_header->a_version = cpu_to_le32(BCH_ACL_VERSION);
181 outptr = (void *) acl_header + sizeof(*acl_header);
183 acl_for_each_entry(acl, acl_e) {
184 bch_acl_entry *entry = outptr;
186 entry->e_tag = cpu_to_le16(acl_e->e_tag);
187 entry->e_perm = cpu_to_le16(acl_e->e_perm);
188 switch (acl_e->e_tag) {
190 entry->e_id = cpu_to_le32(
191 from_kuid(&init_user_ns, acl_e->e_uid));
192 outptr += sizeof(bch_acl_entry);
195 entry->e_id = cpu_to_le32(
196 from_kgid(&init_user_ns, acl_e->e_gid));
197 outptr += sizeof(bch_acl_entry);
204 outptr += sizeof(bch_acl_entry_short);
209 BUG_ON(outptr != xattr_val(&xattr->v) + acl_len);
214 struct posix_acl *bch2_get_acl(struct inode *vinode, int type)
216 struct bch_inode_info *inode = to_bch_ei(vinode);
217 struct bch_fs *c = inode->v.i_sb->s_fs_info;
218 struct btree_trans trans;
219 struct btree_iter *iter;
220 struct bkey_s_c_xattr xattr;
221 struct posix_acl *acl = NULL;
223 bch2_trans_init(&trans, c);
225 bch2_trans_begin(&trans);
227 iter = bch2_hash_lookup(&trans, bch2_xattr_hash_desc,
228 &inode->ei_str_hash, inode->v.i_ino,
229 &X_SEARCH(acl_to_xattr_type(type), "", 0),
232 if (PTR_ERR(iter) == -EINTR)
235 if (PTR_ERR(iter) != -ENOENT)
236 acl = ERR_CAST(iter);
240 xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
242 acl = bch2_acl_from_disk(xattr_val(xattr.v),
243 le16_to_cpu(xattr.v->x_val_len));
246 set_cached_acl(&inode->v, type, acl);
248 bch2_trans_exit(&trans);
252 int bch2_set_acl_trans(struct btree_trans *trans,
253 struct bch_inode_unpacked *inode_u,
254 const struct bch_hash_info *hash_info,
255 struct posix_acl *acl, int type)
259 if (type == ACL_TYPE_DEFAULT &&
260 !S_ISDIR(inode_u->bi_mode))
261 return acl ? -EACCES : 0;
264 struct bkey_i_xattr *xattr =
265 bch2_acl_to_xattr(trans, acl, type);
267 return PTR_ERR(xattr);
269 ret = __bch2_hash_set(trans, bch2_xattr_hash_desc, hash_info,
270 inode_u->bi_inum, &xattr->k_i, 0);
272 struct xattr_search_key search =
273 X_SEARCH(acl_to_xattr_type(type), "", 0);
275 ret = bch2_hash_delete(trans, bch2_xattr_hash_desc, hash_info,
276 inode_u->bi_inum, &search);
279 return ret == -ENOENT ? 0 : ret;
282 static int inode_update_for_set_acl_fn(struct bch_inode_info *inode,
283 struct bch_inode_unpacked *bi,
286 struct bch_fs *c = inode->v.i_sb->s_fs_info;
287 struct timespec now = current_time(&inode->v);
288 umode_t mode = (unsigned long) p;
290 bi->bi_ctime = timespec_to_bch2_time(c, now);
295 int bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type)
297 struct bch_inode_info *inode = to_bch_ei(vinode);
298 struct bch_fs *c = inode->v.i_sb->s_fs_info;
299 struct btree_trans trans;
300 struct bch_inode_unpacked inode_u;
301 umode_t mode = inode->v.i_mode;
304 if (type == ACL_TYPE_ACCESS && acl) {
305 ret = posix_acl_update_mode(&inode->v, &mode, &acl);
310 bch2_trans_init(&trans, c);
312 bch2_trans_begin(&trans);
314 ret = bch2_set_acl_trans(&trans,
318 bch2_write_inode_trans(&trans, inode, &inode_u,
319 inode_update_for_set_acl_fn,
320 (void *)(unsigned long) mode) ?:
321 bch2_trans_commit(&trans, NULL, NULL,
322 &inode->ei_journal_seq,
324 BTREE_INSERT_NOUNLOCK);
330 bch2_inode_update_after_write(c, inode, &inode_u,
331 ATTR_CTIME|ATTR_MODE);
333 set_cached_acl(&inode->v, type, acl);
335 bch2_trans_exit(&trans);
340 int bch2_acl_chmod(struct btree_trans *trans,
341 struct bch_inode_info *inode,
343 struct posix_acl **new_acl)
345 struct btree_iter *iter;
346 struct bkey_s_c_xattr xattr;
347 struct bkey_i_xattr *new;
348 struct posix_acl *acl;
351 iter = bch2_hash_lookup(trans, bch2_xattr_hash_desc,
352 &inode->ei_str_hash, inode->v.i_ino,
353 &X_SEARCH(BCH_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0),
356 return PTR_ERR(iter) != -ENOENT ? PTR_ERR(iter) : 0;
358 xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
360 acl = bch2_acl_from_disk(xattr_val(xattr.v),
361 le16_to_cpu(xattr.v->x_val_len));
362 if (IS_ERR_OR_NULL(acl))
365 ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
369 new = bch2_acl_to_xattr(trans, acl, ACL_TYPE_ACCESS);
375 bch2_trans_update(trans, iter, &new->k_i, 0);
383 #endif /* CONFIG_BCACHEFS_POSIX_ACL */