1 // SPDX-License-Identifier: GPL-2.0
8 #include <linux/posix_acl.h>
10 static const char * const acl_types
[] = {
11 [ACL_USER_OBJ
] = "user_obj",
13 [ACL_GROUP_OBJ
] = "group_obj",
14 [ACL_GROUP
] = "group",
16 [ACL_OTHER
] = "other",
20 void bch2_acl_to_text(struct printbuf
*out
, const void *value
, size_t size
)
22 const void *p
, *end
= value
+ size
;
25 size
< sizeof(bch_acl_header
) ||
26 ((bch_acl_header
*)value
)->a_version
!= cpu_to_le32(BCH_ACL_VERSION
))
29 p
= value
+ sizeof(bch_acl_header
);
31 const bch_acl_entry
*in
= p
;
32 unsigned tag
= le16_to_cpu(in
->e_tag
);
34 prt_str(out
, acl_types
[tag
]);
41 p
+= sizeof(bch_acl_entry_short
);
44 prt_printf(out
, " uid %u", le32_to_cpu(in
->e_id
));
45 p
+= sizeof(bch_acl_entry
);
48 prt_printf(out
, " gid %u", le32_to_cpu(in
->e_id
));
49 p
+= sizeof(bch_acl_entry
);
53 prt_printf(out
, " %o", le16_to_cpu(in
->e_perm
));
60 #ifdef CONFIG_BCACHEFS_POSIX_ACL
65 #include <linux/posix_acl_xattr.h>
66 #include <linux/sched.h>
67 #include <linux/slab.h>
69 static inline size_t bch2_acl_size(unsigned nr_short
, unsigned nr_long
)
71 return sizeof(bch_acl_header
) +
72 sizeof(bch_acl_entry_short
) * nr_short
+
73 sizeof(bch_acl_entry
) * nr_long
;
76 static inline int acl_to_xattr_type(int type
)
80 return KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS
;
81 case ACL_TYPE_DEFAULT
:
82 return KEY_TYPE_XATTR_INDEX_POSIX_ACL_DEFAULT
;
89 * Convert from filesystem to in-memory representation.
91 static struct posix_acl
*bch2_acl_from_disk(struct btree_trans
*trans
,
92 const void *value
, size_t size
)
94 const void *p
, *end
= value
+ size
;
95 struct posix_acl
*acl
;
96 struct posix_acl_entry
*out
;
102 if (size
< sizeof(bch_acl_header
))
104 if (((bch_acl_header
*)value
)->a_version
!=
105 cpu_to_le32(BCH_ACL_VERSION
))
108 p
= value
+ sizeof(bch_acl_header
);
110 const bch_acl_entry
*entry
= p
;
112 if (p
+ sizeof(bch_acl_entry_short
) > end
)
115 switch (le16_to_cpu(entry
->e_tag
)) {
120 p
+= sizeof(bch_acl_entry_short
);
124 p
+= sizeof(bch_acl_entry
);
139 acl
= allocate_dropping_locks(trans
, ret
,
140 posix_acl_alloc(count
, _gfp
));
142 return ERR_PTR(-ENOMEM
);
148 out
= acl
->a_entries
;
150 p
= value
+ sizeof(bch_acl_header
);
152 const bch_acl_entry
*in
= p
;
154 out
->e_tag
= le16_to_cpu(in
->e_tag
);
155 out
->e_perm
= le16_to_cpu(in
->e_perm
);
157 switch (out
->e_tag
) {
162 p
+= sizeof(bch_acl_entry_short
);
165 out
->e_uid
= make_kuid(&init_user_ns
,
166 le32_to_cpu(in
->e_id
));
167 p
+= sizeof(bch_acl_entry
);
170 out
->e_gid
= make_kgid(&init_user_ns
,
171 le32_to_cpu(in
->e_id
));
172 p
+= sizeof(bch_acl_entry
);
179 BUG_ON(out
!= acl
->a_entries
+ acl
->a_count
);
183 pr_err("invalid acl entry");
184 return ERR_PTR(-EINVAL
);
187 #define acl_for_each_entry(acl, acl_e) \
188 for (acl_e = acl->a_entries; \
189 acl_e < acl->a_entries + acl->a_count; \
193 * Convert from in-memory to filesystem representation.
195 static struct bkey_i_xattr
*
196 bch2_acl_to_xattr(struct btree_trans
*trans
,
197 const struct posix_acl
*acl
,
200 struct bkey_i_xattr
*xattr
;
201 bch_acl_header
*acl_header
;
202 const struct posix_acl_entry
*acl_e
;
204 unsigned nr_short
= 0, nr_long
= 0, acl_len
, u64s
;
206 acl_for_each_entry(acl
, acl_e
) {
207 switch (acl_e
->e_tag
) {
219 return ERR_PTR(-EINVAL
);
223 acl_len
= bch2_acl_size(nr_short
, nr_long
);
224 u64s
= BKEY_U64s
+ xattr_val_u64s(0, acl_len
);
227 return ERR_PTR(-E2BIG
);
229 xattr
= bch2_trans_kmalloc(trans
, u64s
* sizeof(u64
));
233 bkey_xattr_init(&xattr
->k_i
);
234 xattr
->k
.u64s
= u64s
;
235 xattr
->v
.x_type
= acl_to_xattr_type(type
);
236 xattr
->v
.x_name_len
= 0;
237 xattr
->v
.x_val_len
= cpu_to_le16(acl_len
);
239 acl_header
= xattr_val(&xattr
->v
);
240 acl_header
->a_version
= cpu_to_le32(BCH_ACL_VERSION
);
242 outptr
= (void *) acl_header
+ sizeof(*acl_header
);
244 acl_for_each_entry(acl
, acl_e
) {
245 bch_acl_entry
*entry
= outptr
;
247 entry
->e_tag
= cpu_to_le16(acl_e
->e_tag
);
248 entry
->e_perm
= cpu_to_le16(acl_e
->e_perm
);
249 switch (acl_e
->e_tag
) {
251 entry
->e_id
= cpu_to_le32(
252 from_kuid(&init_user_ns
, acl_e
->e_uid
));
253 outptr
+= sizeof(bch_acl_entry
);
256 entry
->e_id
= cpu_to_le32(
257 from_kgid(&init_user_ns
, acl_e
->e_gid
));
258 outptr
+= sizeof(bch_acl_entry
);
265 outptr
+= sizeof(bch_acl_entry_short
);
270 BUG_ON(outptr
!= xattr_val(&xattr
->v
) + acl_len
);
275 struct posix_acl
*bch2_get_acl(struct inode
*vinode
, int type
, bool rcu
)
277 struct bch_inode_info
*inode
= to_bch_ei(vinode
);
278 struct bch_fs
*c
= inode
->v
.i_sb
->s_fs_info
;
279 struct bch_hash_info hash
= bch2_hash_info_init(c
, &inode
->ei_inode
);
280 struct xattr_search_key search
= X_SEARCH(acl_to_xattr_type(type
), "", 0);
281 struct btree_iter iter
= { NULL
};
282 struct posix_acl
*acl
= NULL
;
285 return ERR_PTR(-ECHILD
);
287 struct btree_trans
*trans
= bch2_trans_get(c
);
289 bch2_trans_begin(trans
);
291 struct bkey_s_c k
= bch2_hash_lookup(trans
, &iter
, bch2_xattr_hash_desc
,
292 &hash
, inode_inum(inode
), &search
, 0);
293 int ret
= bkey_err(k
);
297 struct bkey_s_c_xattr xattr
= bkey_s_c_to_xattr(k
);
298 acl
= bch2_acl_from_disk(trans
, xattr_val(xattr
.v
),
299 le16_to_cpu(xattr
.v
->x_val_len
));
300 ret
= PTR_ERR_OR_ZERO(acl
);
302 if (bch2_err_matches(ret
, BCH_ERR_transaction_restart
))
306 acl
= !bch2_err_matches(ret
, ENOENT
) ? ERR_PTR(ret
) : NULL
;
308 if (!IS_ERR_OR_NULL(acl
))
309 set_cached_acl(&inode
->v
, type
, acl
);
311 bch2_trans_iter_exit(trans
, &iter
);
312 bch2_trans_put(trans
);
316 int bch2_set_acl_trans(struct btree_trans
*trans
, subvol_inum inum
,
317 struct bch_inode_unpacked
*inode_u
,
318 struct posix_acl
*acl
, int type
)
320 struct bch_hash_info hash_info
= bch2_hash_info_init(trans
->c
, inode_u
);
323 if (type
== ACL_TYPE_DEFAULT
&&
324 !S_ISDIR(inode_u
->bi_mode
))
325 return acl
? -EACCES
: 0;
328 struct bkey_i_xattr
*xattr
=
329 bch2_acl_to_xattr(trans
, acl
, type
);
331 return PTR_ERR(xattr
);
333 ret
= bch2_hash_set(trans
, bch2_xattr_hash_desc
, &hash_info
,
334 inum
, &xattr
->k_i
, 0);
336 struct xattr_search_key search
=
337 X_SEARCH(acl_to_xattr_type(type
), "", 0);
339 ret
= bch2_hash_delete(trans
, bch2_xattr_hash_desc
, &hash_info
,
343 return bch2_err_matches(ret
, ENOENT
) ? 0 : ret
;
346 int bch2_set_acl(struct mnt_idmap
*idmap
,
347 struct dentry
*dentry
,
348 struct posix_acl
*_acl
, int type
)
350 struct bch_inode_info
*inode
= to_bch_ei(dentry
->d_inode
);
351 struct bch_fs
*c
= inode
->v
.i_sb
->s_fs_info
;
352 struct btree_iter inode_iter
= { NULL
};
353 struct bch_inode_unpacked inode_u
;
354 struct posix_acl
*acl
;
358 mutex_lock(&inode
->ei_update_lock
);
359 struct btree_trans
*trans
= bch2_trans_get(c
);
361 bch2_trans_begin(trans
);
364 ret
= bch2_subvol_is_ro_trans(trans
, inode
->ei_inum
.subvol
) ?:
365 bch2_inode_peek(trans
, &inode_iter
, &inode_u
, inode_inum(inode
),
370 mode
= inode_u
.bi_mode
;
372 if (type
== ACL_TYPE_ACCESS
) {
373 ret
= posix_acl_update_mode(idmap
, &inode
->v
, &mode
, &acl
);
378 ret
= bch2_set_acl_trans(trans
, inode_inum(inode
), &inode_u
, acl
, type
);
382 inode_u
.bi_ctime
= bch2_current_time(c
);
383 inode_u
.bi_mode
= mode
;
385 ret
= bch2_inode_write(trans
, &inode_iter
, &inode_u
) ?:
386 bch2_trans_commit(trans
, NULL
, NULL
, 0);
388 bch2_trans_iter_exit(trans
, &inode_iter
);
390 if (bch2_err_matches(ret
, BCH_ERR_transaction_restart
))
395 bch2_inode_update_after_write(trans
, inode
, &inode_u
,
396 ATTR_CTIME
|ATTR_MODE
);
398 set_cached_acl(&inode
->v
, type
, acl
);
400 bch2_trans_put(trans
);
401 mutex_unlock(&inode
->ei_update_lock
);
406 int bch2_acl_chmod(struct btree_trans
*trans
, subvol_inum inum
,
407 struct bch_inode_unpacked
*inode
,
409 struct posix_acl
**new_acl
)
411 struct bch_hash_info hash_info
= bch2_hash_info_init(trans
->c
, inode
);
412 struct xattr_search_key search
= X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS
, "", 0);
413 struct btree_iter iter
;
414 struct posix_acl
*acl
= NULL
;
416 struct bkey_s_c k
= bch2_hash_lookup(trans
, &iter
, bch2_xattr_hash_desc
,
417 &hash_info
, inum
, &search
, BTREE_ITER_intent
);
418 int ret
= bkey_err(k
);
420 return bch2_err_matches(ret
, ENOENT
) ? 0 : ret
;
422 struct bkey_s_c_xattr xattr
= bkey_s_c_to_xattr(k
);
424 acl
= bch2_acl_from_disk(trans
, xattr_val(xattr
.v
),
425 le16_to_cpu(xattr
.v
->x_val_len
));
426 ret
= PTR_ERR_OR_ZERO(acl
);
430 ret
= allocate_dropping_locks_errcode(trans
, __posix_acl_chmod(&acl
, _gfp
, mode
));
434 struct bkey_i_xattr
*new = bch2_acl_to_xattr(trans
, acl
, ACL_TYPE_ACCESS
);
435 ret
= PTR_ERR_OR_ZERO(new);
440 ret
= bch2_trans_update(trans
, &iter
, &new->k_i
, 0);
444 bch2_trans_iter_exit(trans
, &iter
);
445 if (!IS_ERR_OR_NULL(acl
))
450 #endif /* CONFIG_BCACHEFS_POSIX_ACL */