161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy * CDDL HEADER START
4eda14cbcSMatt Macy *
5eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy *
9eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy * See the License for the specific language governing permissions
12eda14cbcSMatt Macy * and limitations under the License.
13eda14cbcSMatt Macy *
14eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy *
20eda14cbcSMatt Macy * CDDL HEADER END
21eda14cbcSMatt Macy */
22eda14cbcSMatt Macy /*
23eda14cbcSMatt Macy * Copyright (c) 2011, Lawrence Livermore National Security, LLC.
24eda14cbcSMatt Macy *
25eda14cbcSMatt Macy * Extended attributes (xattr) on Solaris are implemented as files
26eda14cbcSMatt Macy * which exist in a hidden xattr directory. These extended attributes
27eda14cbcSMatt Macy * can be accessed using the attropen() system call which opens
28eda14cbcSMatt Macy * the extended attribute. It can then be manipulated just like
29eda14cbcSMatt Macy * a standard file descriptor. This has a couple advantages such
30eda14cbcSMatt Macy * as practically no size limit on the file, and the extended
31eda14cbcSMatt Macy * attributes permissions may differ from those of the parent file.
32eda14cbcSMatt Macy * This interface is really quite clever, but it's also completely
33eda14cbcSMatt Macy * different than what is supported on Linux. It also comes with a
34eda14cbcSMatt Macy * steep performance penalty when accessing small xattrs because they
35eda14cbcSMatt Macy * are not stored with the parent file.
36eda14cbcSMatt Macy *
37eda14cbcSMatt Macy * Under Linux extended attributes are manipulated by the system
38eda14cbcSMatt Macy * calls getxattr(2), setxattr(2), and listxattr(2). They consider
39eda14cbcSMatt Macy * extended attributes to be name/value pairs where the name is a
40eda14cbcSMatt Macy * NULL terminated string. The name must also include one of the
41eda14cbcSMatt Macy * following namespace prefixes:
42eda14cbcSMatt Macy *
43eda14cbcSMatt Macy * user - No restrictions and is available to user applications.
44eda14cbcSMatt Macy * trusted - Restricted to kernel and root (CAP_SYS_ADMIN) use.
45eda14cbcSMatt Macy * system - Used for access control lists (system.nfs4_acl, etc).
46eda14cbcSMatt Macy * security - Used by SELinux to store a files security context.
47eda14cbcSMatt Macy *
48eda14cbcSMatt Macy * The value under Linux to limited to 65536 bytes of binary data.
49eda14cbcSMatt Macy * In practice, individual xattrs tend to be much smaller than this
50eda14cbcSMatt Macy * and are typically less than 100 bytes. A good example of this
51eda14cbcSMatt Macy * are the security.selinux xattrs which are less than 100 bytes and
52eda14cbcSMatt Macy * exist for every file when xattr labeling is enabled.
53eda14cbcSMatt Macy *
54eda14cbcSMatt Macy * The Linux xattr implementation has been written to take advantage of
55eda14cbcSMatt Macy * this typical usage. When the dataset property 'xattr=sa' is set,
56eda14cbcSMatt Macy * then xattrs will be preferentially stored as System Attributes (SA).
57eda14cbcSMatt Macy * This allows tiny xattrs (~100 bytes) to be stored with the dnode and
58eda14cbcSMatt Macy * up to 64k of xattrs to be stored in the spill block. If additional
59eda14cbcSMatt Macy * xattr space is required, which is unlikely under Linux, they will
60eda14cbcSMatt Macy * be stored using the traditional directory approach.
61eda14cbcSMatt Macy *
62eda14cbcSMatt Macy * This optimization results in roughly a 3x performance improvement
63eda14cbcSMatt Macy * when accessing xattrs because it avoids the need to perform a seek
64eda14cbcSMatt Macy * for every xattr value. When multiple xattrs are stored per-file
65eda14cbcSMatt Macy * the performance improvements are even greater because all of the
66eda14cbcSMatt Macy * xattrs stored in the spill block will be cached.
67eda14cbcSMatt Macy *
68eda14cbcSMatt Macy * However, by default SA based xattrs are disabled in the Linux port
69eda14cbcSMatt Macy * to maximize compatibility with other implementations. If you do
70eda14cbcSMatt Macy * enable SA based xattrs then they will not be visible on platforms
71eda14cbcSMatt Macy * which do not support this feature.
72eda14cbcSMatt Macy *
73eda14cbcSMatt Macy * NOTE: One additional consequence of the xattr directory implementation
74eda14cbcSMatt Macy * is that when an extended attribute is manipulated an inode is created.
75eda14cbcSMatt Macy * This inode will exist in the Linux inode cache but there will be no
76eda14cbcSMatt Macy * associated entry in the dentry cache which references it. This is
77eda14cbcSMatt Macy * safe but it may result in some confusion. Enabling SA based xattrs
78eda14cbcSMatt Macy * largely avoids the issue except in the overflow case.
79eda14cbcSMatt Macy */
80eda14cbcSMatt Macy
81eda14cbcSMatt Macy #include <sys/zfs_znode.h>
82eda14cbcSMatt Macy #include <sys/zfs_vfsops.h>
83eda14cbcSMatt Macy #include <sys/zfs_vnops.h>
84eda14cbcSMatt Macy #include <sys/zap.h>
85eda14cbcSMatt Macy #include <sys/vfs.h>
86eda14cbcSMatt Macy #include <sys/zpl.h>
871f1e2261SMartin Matuska #include <linux/vfs_compat.h>
88eda14cbcSMatt Macy
89c03c5b1cSMartin Matuska enum xattr_permission {
90c03c5b1cSMartin Matuska XAPERM_DENY,
91c03c5b1cSMartin Matuska XAPERM_ALLOW,
92c03c5b1cSMartin Matuska XAPERM_COMPAT,
93c03c5b1cSMartin Matuska };
94c03c5b1cSMartin Matuska
95eda14cbcSMatt Macy typedef struct xattr_filldir {
96eda14cbcSMatt Macy size_t size;
97eda14cbcSMatt Macy size_t offset;
98eda14cbcSMatt Macy char *buf;
99eda14cbcSMatt Macy struct dentry *dentry;
100eda14cbcSMatt Macy } xattr_filldir_t;
101eda14cbcSMatt Macy
102c03c5b1cSMartin Matuska static enum xattr_permission zpl_xattr_permission(xattr_filldir_t *,
103c03c5b1cSMartin Matuska const char *, int);
104eda14cbcSMatt Macy
105c03c5b1cSMartin Matuska static int zfs_xattr_compat = 0;
106eda14cbcSMatt Macy
107eda14cbcSMatt Macy /*
108eda14cbcSMatt Macy * Determine is a given xattr name should be visible and if so copy it
109eda14cbcSMatt Macy * in to the provided buffer (xf->buf).
110eda14cbcSMatt Macy */
111eda14cbcSMatt Macy static int
zpl_xattr_filldir(xattr_filldir_t * xf,const char * name,int name_len)112eda14cbcSMatt Macy zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len)
113eda14cbcSMatt Macy {
114c03c5b1cSMartin Matuska enum xattr_permission perm;
115c03c5b1cSMartin Matuska
116eda14cbcSMatt Macy /* Check permissions using the per-namespace list xattr handler. */
117c03c5b1cSMartin Matuska perm = zpl_xattr_permission(xf, name, name_len);
118c03c5b1cSMartin Matuska if (perm == XAPERM_DENY)
119eda14cbcSMatt Macy return (0);
120eda14cbcSMatt Macy
121c03c5b1cSMartin Matuska /* Prefix the name with "user." if it does not have a namespace. */
122c03c5b1cSMartin Matuska if (perm == XAPERM_COMPAT) {
123c03c5b1cSMartin Matuska if (xf->buf) {
124c03c5b1cSMartin Matuska if (xf->offset + XATTR_USER_PREFIX_LEN + 1 > xf->size)
125c03c5b1cSMartin Matuska return (-ERANGE);
126c03c5b1cSMartin Matuska
127c03c5b1cSMartin Matuska memcpy(xf->buf + xf->offset, XATTR_USER_PREFIX,
128c03c5b1cSMartin Matuska XATTR_USER_PREFIX_LEN);
129c03c5b1cSMartin Matuska xf->buf[xf->offset + XATTR_USER_PREFIX_LEN] = '\0';
130c03c5b1cSMartin Matuska }
131c03c5b1cSMartin Matuska
132c03c5b1cSMartin Matuska xf->offset += XATTR_USER_PREFIX_LEN;
133c03c5b1cSMartin Matuska }
134c03c5b1cSMartin Matuska
135eda14cbcSMatt Macy /* When xf->buf is NULL only calculate the required size. */
136eda14cbcSMatt Macy if (xf->buf) {
137eda14cbcSMatt Macy if (xf->offset + name_len + 1 > xf->size)
138eda14cbcSMatt Macy return (-ERANGE);
139eda14cbcSMatt Macy
140eda14cbcSMatt Macy memcpy(xf->buf + xf->offset, name, name_len);
141eda14cbcSMatt Macy xf->buf[xf->offset + name_len] = '\0';
142eda14cbcSMatt Macy }
143eda14cbcSMatt Macy
144eda14cbcSMatt Macy xf->offset += (name_len + 1);
145eda14cbcSMatt Macy
146eda14cbcSMatt Macy return (0);
147eda14cbcSMatt Macy }
148eda14cbcSMatt Macy
149eda14cbcSMatt Macy /*
150eda14cbcSMatt Macy * Read as many directory entry names as will fit in to the provided buffer,
151eda14cbcSMatt Macy * or when no buffer is provided calculate the required buffer size.
152eda14cbcSMatt Macy */
153eda14cbcSMatt Macy static int
zpl_xattr_readdir(struct inode * dxip,xattr_filldir_t * xf)154eda14cbcSMatt Macy zpl_xattr_readdir(struct inode *dxip, xattr_filldir_t *xf)
155eda14cbcSMatt Macy {
156eda14cbcSMatt Macy zap_cursor_t zc;
1577a7741afSMartin Matuska zap_attribute_t *zap = zap_attribute_alloc();
158eda14cbcSMatt Macy int error;
159eda14cbcSMatt Macy
160eda14cbcSMatt Macy zap_cursor_init(&zc, ITOZSB(dxip)->z_os, ITOZ(dxip)->z_id);
161eda14cbcSMatt Macy
1627a7741afSMartin Matuska while ((error = -zap_cursor_retrieve(&zc, zap)) == 0) {
163eda14cbcSMatt Macy
1647a7741afSMartin Matuska if (zap->za_integer_length != 8 || zap->za_num_integers != 1) {
165eda14cbcSMatt Macy error = -ENXIO;
166eda14cbcSMatt Macy break;
167eda14cbcSMatt Macy }
168eda14cbcSMatt Macy
1697a7741afSMartin Matuska error = zpl_xattr_filldir(xf, zap->za_name,
1707a7741afSMartin Matuska strlen(zap->za_name));
171eda14cbcSMatt Macy if (error)
172eda14cbcSMatt Macy break;
173eda14cbcSMatt Macy
174eda14cbcSMatt Macy zap_cursor_advance(&zc);
175eda14cbcSMatt Macy }
176eda14cbcSMatt Macy
177eda14cbcSMatt Macy zap_cursor_fini(&zc);
1787a7741afSMartin Matuska zap_attribute_free(zap);
179eda14cbcSMatt Macy
180eda14cbcSMatt Macy if (error == -ENOENT)
181eda14cbcSMatt Macy error = 0;
182eda14cbcSMatt Macy
183eda14cbcSMatt Macy return (error);
184eda14cbcSMatt Macy }
185eda14cbcSMatt Macy
186eda14cbcSMatt Macy static ssize_t
zpl_xattr_list_dir(xattr_filldir_t * xf,cred_t * cr)187eda14cbcSMatt Macy zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
188eda14cbcSMatt Macy {
189eda14cbcSMatt Macy struct inode *ip = xf->dentry->d_inode;
190eda14cbcSMatt Macy struct inode *dxip = NULL;
191eda14cbcSMatt Macy znode_t *dxzp;
192eda14cbcSMatt Macy int error;
193eda14cbcSMatt Macy
194eda14cbcSMatt Macy /* Lookup the xattr directory */
195eda14cbcSMatt Macy error = -zfs_lookup(ITOZ(ip), NULL, &dxzp, LOOKUP_XATTR,
196eda14cbcSMatt Macy cr, NULL, NULL);
197eda14cbcSMatt Macy if (error) {
198eda14cbcSMatt Macy if (error == -ENOENT)
199eda14cbcSMatt Macy error = 0;
200eda14cbcSMatt Macy
201eda14cbcSMatt Macy return (error);
202eda14cbcSMatt Macy }
203eda14cbcSMatt Macy
204eda14cbcSMatt Macy dxip = ZTOI(dxzp);
205eda14cbcSMatt Macy error = zpl_xattr_readdir(dxip, xf);
206eda14cbcSMatt Macy iput(dxip);
207eda14cbcSMatt Macy
208eda14cbcSMatt Macy return (error);
209eda14cbcSMatt Macy }
210eda14cbcSMatt Macy
211eda14cbcSMatt Macy static ssize_t
zpl_xattr_list_sa(xattr_filldir_t * xf)212eda14cbcSMatt Macy zpl_xattr_list_sa(xattr_filldir_t *xf)
213eda14cbcSMatt Macy {
214eda14cbcSMatt Macy znode_t *zp = ITOZ(xf->dentry->d_inode);
215eda14cbcSMatt Macy nvpair_t *nvp = NULL;
216eda14cbcSMatt Macy int error = 0;
217eda14cbcSMatt Macy
218eda14cbcSMatt Macy mutex_enter(&zp->z_lock);
219eda14cbcSMatt Macy if (zp->z_xattr_cached == NULL)
220eda14cbcSMatt Macy error = -zfs_sa_get_xattr(zp);
221eda14cbcSMatt Macy mutex_exit(&zp->z_lock);
222eda14cbcSMatt Macy
223eda14cbcSMatt Macy if (error)
224eda14cbcSMatt Macy return (error);
225eda14cbcSMatt Macy
226eda14cbcSMatt Macy ASSERT(zp->z_xattr_cached);
227eda14cbcSMatt Macy
228eda14cbcSMatt Macy while ((nvp = nvlist_next_nvpair(zp->z_xattr_cached, nvp)) != NULL) {
229eda14cbcSMatt Macy ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY);
230eda14cbcSMatt Macy
231eda14cbcSMatt Macy error = zpl_xattr_filldir(xf, nvpair_name(nvp),
232eda14cbcSMatt Macy strlen(nvpair_name(nvp)));
233eda14cbcSMatt Macy if (error)
234eda14cbcSMatt Macy return (error);
235eda14cbcSMatt Macy }
236eda14cbcSMatt Macy
237eda14cbcSMatt Macy return (0);
238eda14cbcSMatt Macy }
239eda14cbcSMatt Macy
240eda14cbcSMatt Macy ssize_t
zpl_xattr_list(struct dentry * dentry,char * buffer,size_t buffer_size)241eda14cbcSMatt Macy zpl_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
242eda14cbcSMatt Macy {
243eda14cbcSMatt Macy znode_t *zp = ITOZ(dentry->d_inode);
244eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ZTOZSB(zp);
245eda14cbcSMatt Macy xattr_filldir_t xf = { buffer_size, 0, buffer, dentry };
246eda14cbcSMatt Macy cred_t *cr = CRED();
247eda14cbcSMatt Macy fstrans_cookie_t cookie;
248eda14cbcSMatt Macy int error = 0;
249eda14cbcSMatt Macy
250eda14cbcSMatt Macy crhold(cr);
251eda14cbcSMatt Macy cookie = spl_fstrans_mark();
252c7046f76SMartin Matuska if ((error = zpl_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
253c7046f76SMartin Matuska goto out1;
254eda14cbcSMatt Macy rw_enter(&zp->z_xattr_lock, RW_READER);
255eda14cbcSMatt Macy
256eda14cbcSMatt Macy if (zfsvfs->z_use_sa && zp->z_is_sa) {
257eda14cbcSMatt Macy error = zpl_xattr_list_sa(&xf);
258eda14cbcSMatt Macy if (error)
259eda14cbcSMatt Macy goto out;
260eda14cbcSMatt Macy }
261eda14cbcSMatt Macy
262eda14cbcSMatt Macy error = zpl_xattr_list_dir(&xf, cr);
263eda14cbcSMatt Macy if (error)
264eda14cbcSMatt Macy goto out;
265eda14cbcSMatt Macy
266eda14cbcSMatt Macy error = xf.offset;
267eda14cbcSMatt Macy out:
268eda14cbcSMatt Macy
269eda14cbcSMatt Macy rw_exit(&zp->z_xattr_lock);
270c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG);
271c7046f76SMartin Matuska out1:
272eda14cbcSMatt Macy spl_fstrans_unmark(cookie);
273eda14cbcSMatt Macy crfree(cr);
274eda14cbcSMatt Macy
275eda14cbcSMatt Macy return (error);
276eda14cbcSMatt Macy }
277eda14cbcSMatt Macy
278eda14cbcSMatt Macy static int
zpl_xattr_get_dir(struct inode * ip,const char * name,void * value,size_t size,cred_t * cr)279eda14cbcSMatt Macy zpl_xattr_get_dir(struct inode *ip, const char *name, void *value,
280eda14cbcSMatt Macy size_t size, cred_t *cr)
281eda14cbcSMatt Macy {
2827877fdebSMatt Macy fstrans_cookie_t cookie;
283eda14cbcSMatt Macy struct inode *xip = NULL;
284eda14cbcSMatt Macy znode_t *dxzp = NULL;
285eda14cbcSMatt Macy znode_t *xzp = NULL;
286eda14cbcSMatt Macy int error;
287eda14cbcSMatt Macy
288eda14cbcSMatt Macy /* Lookup the xattr directory */
289eda14cbcSMatt Macy error = -zfs_lookup(ITOZ(ip), NULL, &dxzp, LOOKUP_XATTR,
290eda14cbcSMatt Macy cr, NULL, NULL);
291eda14cbcSMatt Macy if (error)
292eda14cbcSMatt Macy goto out;
293eda14cbcSMatt Macy
294eda14cbcSMatt Macy /* Lookup a specific xattr name in the directory */
295eda14cbcSMatt Macy error = -zfs_lookup(dxzp, (char *)name, &xzp, 0, cr, NULL, NULL);
296eda14cbcSMatt Macy if (error)
297eda14cbcSMatt Macy goto out;
298eda14cbcSMatt Macy
299eda14cbcSMatt Macy xip = ZTOI(xzp);
300eda14cbcSMatt Macy if (!size) {
301eda14cbcSMatt Macy error = i_size_read(xip);
302eda14cbcSMatt Macy goto out;
303eda14cbcSMatt Macy }
304eda14cbcSMatt Macy
305eda14cbcSMatt Macy if (size < i_size_read(xip)) {
306eda14cbcSMatt Macy error = -ERANGE;
307eda14cbcSMatt Macy goto out;
308eda14cbcSMatt Macy }
309eda14cbcSMatt Macy
3107877fdebSMatt Macy struct iovec iov;
3117877fdebSMatt Macy iov.iov_base = (void *)value;
3127877fdebSMatt Macy iov.iov_len = size;
3137877fdebSMatt Macy
314184c1b94SMartin Matuska zfs_uio_t uio;
315184c1b94SMartin Matuska zfs_uio_iovec_init(&uio, &iov, 1, 0, UIO_SYSSPACE, size, 0);
3167877fdebSMatt Macy
3177877fdebSMatt Macy cookie = spl_fstrans_mark();
3187877fdebSMatt Macy error = -zfs_read(ITOZ(xip), &uio, 0, cr);
3197877fdebSMatt Macy spl_fstrans_unmark(cookie);
3207877fdebSMatt Macy
3217877fdebSMatt Macy if (error == 0)
322184c1b94SMartin Matuska error = size - zfs_uio_resid(&uio);
323eda14cbcSMatt Macy out:
324eda14cbcSMatt Macy if (xzp)
325eda14cbcSMatt Macy zrele(xzp);
326eda14cbcSMatt Macy
327eda14cbcSMatt Macy if (dxzp)
328eda14cbcSMatt Macy zrele(dxzp);
329eda14cbcSMatt Macy
330eda14cbcSMatt Macy return (error);
331eda14cbcSMatt Macy }
332eda14cbcSMatt Macy
333eda14cbcSMatt Macy static int
zpl_xattr_get_sa(struct inode * ip,const char * name,void * value,size_t size)334eda14cbcSMatt Macy zpl_xattr_get_sa(struct inode *ip, const char *name, void *value, size_t size)
335eda14cbcSMatt Macy {
336eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
337eda14cbcSMatt Macy uchar_t *nv_value;
338eda14cbcSMatt Macy uint_t nv_size;
339eda14cbcSMatt Macy int error = 0;
340eda14cbcSMatt Macy
341eda14cbcSMatt Macy ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
342eda14cbcSMatt Macy
343eda14cbcSMatt Macy mutex_enter(&zp->z_lock);
344eda14cbcSMatt Macy if (zp->z_xattr_cached == NULL)
345eda14cbcSMatt Macy error = -zfs_sa_get_xattr(zp);
346eda14cbcSMatt Macy mutex_exit(&zp->z_lock);
347eda14cbcSMatt Macy
348eda14cbcSMatt Macy if (error)
349eda14cbcSMatt Macy return (error);
350eda14cbcSMatt Macy
351eda14cbcSMatt Macy ASSERT(zp->z_xattr_cached);
352eda14cbcSMatt Macy error = -nvlist_lookup_byte_array(zp->z_xattr_cached, name,
353eda14cbcSMatt Macy &nv_value, &nv_size);
354eda14cbcSMatt Macy if (error)
355eda14cbcSMatt Macy return (error);
356eda14cbcSMatt Macy
357eda14cbcSMatt Macy if (size == 0 || value == NULL)
358eda14cbcSMatt Macy return (nv_size);
359eda14cbcSMatt Macy
360eda14cbcSMatt Macy if (size < nv_size)
361eda14cbcSMatt Macy return (-ERANGE);
362eda14cbcSMatt Macy
363eda14cbcSMatt Macy memcpy(value, nv_value, nv_size);
364eda14cbcSMatt Macy
365eda14cbcSMatt Macy return (nv_size);
366eda14cbcSMatt Macy }
367eda14cbcSMatt Macy
368eda14cbcSMatt Macy static int
__zpl_xattr_get(struct inode * ip,const char * name,void * value,size_t size,cred_t * cr)369eda14cbcSMatt Macy __zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size,
370eda14cbcSMatt Macy cred_t *cr)
371eda14cbcSMatt Macy {
372eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
373eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ZTOZSB(zp);
374eda14cbcSMatt Macy int error;
375eda14cbcSMatt Macy
376eda14cbcSMatt Macy ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
377eda14cbcSMatt Macy
378eda14cbcSMatt Macy if (zfsvfs->z_use_sa && zp->z_is_sa) {
379eda14cbcSMatt Macy error = zpl_xattr_get_sa(ip, name, value, size);
380eda14cbcSMatt Macy if (error != -ENOENT)
381eda14cbcSMatt Macy goto out;
382eda14cbcSMatt Macy }
383eda14cbcSMatt Macy
384eda14cbcSMatt Macy error = zpl_xattr_get_dir(ip, name, value, size, cr);
385eda14cbcSMatt Macy out:
386eda14cbcSMatt Macy if (error == -ENOENT)
387eda14cbcSMatt Macy error = -ENODATA;
388eda14cbcSMatt Macy
389eda14cbcSMatt Macy return (error);
390eda14cbcSMatt Macy }
391eda14cbcSMatt Macy
392eda14cbcSMatt Macy #define XATTR_NOENT 0x0
393eda14cbcSMatt Macy #define XATTR_IN_SA 0x1
394eda14cbcSMatt Macy #define XATTR_IN_DIR 0x2
395eda14cbcSMatt Macy /* check where the xattr resides */
396eda14cbcSMatt Macy static int
__zpl_xattr_where(struct inode * ip,const char * name,int * where,cred_t * cr)397eda14cbcSMatt Macy __zpl_xattr_where(struct inode *ip, const char *name, int *where, cred_t *cr)
398eda14cbcSMatt Macy {
399eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
400eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ZTOZSB(zp);
401eda14cbcSMatt Macy int error;
402eda14cbcSMatt Macy
403eda14cbcSMatt Macy ASSERT(where);
404eda14cbcSMatt Macy ASSERT(RW_LOCK_HELD(&zp->z_xattr_lock));
405eda14cbcSMatt Macy
406eda14cbcSMatt Macy *where = XATTR_NOENT;
407eda14cbcSMatt Macy if (zfsvfs->z_use_sa && zp->z_is_sa) {
408eda14cbcSMatt Macy error = zpl_xattr_get_sa(ip, name, NULL, 0);
409eda14cbcSMatt Macy if (error >= 0)
410eda14cbcSMatt Macy *where |= XATTR_IN_SA;
411eda14cbcSMatt Macy else if (error != -ENOENT)
412eda14cbcSMatt Macy return (error);
413eda14cbcSMatt Macy }
414eda14cbcSMatt Macy
415eda14cbcSMatt Macy error = zpl_xattr_get_dir(ip, name, NULL, 0, cr);
416eda14cbcSMatt Macy if (error >= 0)
417eda14cbcSMatt Macy *where |= XATTR_IN_DIR;
418eda14cbcSMatt Macy else if (error != -ENOENT)
419eda14cbcSMatt Macy return (error);
420eda14cbcSMatt Macy
421eda14cbcSMatt Macy if (*where == (XATTR_IN_SA|XATTR_IN_DIR))
422eda14cbcSMatt Macy cmn_err(CE_WARN, "ZFS: inode %p has xattr \"%s\""
423eda14cbcSMatt Macy " in both SA and dir", ip, name);
424eda14cbcSMatt Macy if (*where == XATTR_NOENT)
425eda14cbcSMatt Macy error = -ENODATA;
426eda14cbcSMatt Macy else
427eda14cbcSMatt Macy error = 0;
428eda14cbcSMatt Macy return (error);
429eda14cbcSMatt Macy }
430eda14cbcSMatt Macy
431eda14cbcSMatt Macy static int
zpl_xattr_get(struct inode * ip,const char * name,void * value,size_t size)432eda14cbcSMatt Macy zpl_xattr_get(struct inode *ip, const char *name, void *value, size_t size)
433eda14cbcSMatt Macy {
434eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
435eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ZTOZSB(zp);
436eda14cbcSMatt Macy cred_t *cr = CRED();
437eda14cbcSMatt Macy fstrans_cookie_t cookie;
438eda14cbcSMatt Macy int error;
439eda14cbcSMatt Macy
440eda14cbcSMatt Macy crhold(cr);
441eda14cbcSMatt Macy cookie = spl_fstrans_mark();
442c7046f76SMartin Matuska if ((error = zpl_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
443c7046f76SMartin Matuska goto out;
444eda14cbcSMatt Macy rw_enter(&zp->z_xattr_lock, RW_READER);
445eda14cbcSMatt Macy error = __zpl_xattr_get(ip, name, value, size, cr);
446eda14cbcSMatt Macy rw_exit(&zp->z_xattr_lock);
447c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG);
448c7046f76SMartin Matuska out:
449eda14cbcSMatt Macy spl_fstrans_unmark(cookie);
450eda14cbcSMatt Macy crfree(cr);
451eda14cbcSMatt Macy
452eda14cbcSMatt Macy return (error);
453eda14cbcSMatt Macy }
454eda14cbcSMatt Macy
455eda14cbcSMatt Macy static int
zpl_xattr_set_dir(struct inode * ip,const char * name,const void * value,size_t size,int flags,cred_t * cr)456eda14cbcSMatt Macy zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value,
457eda14cbcSMatt Macy size_t size, int flags, cred_t *cr)
458eda14cbcSMatt Macy {
459eda14cbcSMatt Macy znode_t *dxzp = NULL;
460eda14cbcSMatt Macy znode_t *xzp = NULL;
461eda14cbcSMatt Macy vattr_t *vap = NULL;
462eda14cbcSMatt Macy int lookup_flags, error;
463eda14cbcSMatt Macy const int xattr_mode = S_IFREG | 0644;
464eda14cbcSMatt Macy loff_t pos = 0;
465eda14cbcSMatt Macy
466eda14cbcSMatt Macy /*
467eda14cbcSMatt Macy * Lookup the xattr directory. When we're adding an entry pass
468eda14cbcSMatt Macy * CREATE_XATTR_DIR to ensure the xattr directory is created.
469eda14cbcSMatt Macy * When removing an entry this flag is not passed to avoid
470eda14cbcSMatt Macy * unnecessarily creating a new xattr directory.
471eda14cbcSMatt Macy */
472eda14cbcSMatt Macy lookup_flags = LOOKUP_XATTR;
473eda14cbcSMatt Macy if (value != NULL)
474eda14cbcSMatt Macy lookup_flags |= CREATE_XATTR_DIR;
475eda14cbcSMatt Macy
476eda14cbcSMatt Macy error = -zfs_lookup(ITOZ(ip), NULL, &dxzp, lookup_flags,
477eda14cbcSMatt Macy cr, NULL, NULL);
478eda14cbcSMatt Macy if (error)
479eda14cbcSMatt Macy goto out;
480eda14cbcSMatt Macy
481eda14cbcSMatt Macy /* Lookup a specific xattr name in the directory */
482eda14cbcSMatt Macy error = -zfs_lookup(dxzp, (char *)name, &xzp, 0, cr, NULL, NULL);
483eda14cbcSMatt Macy if (error && (error != -ENOENT))
484eda14cbcSMatt Macy goto out;
485eda14cbcSMatt Macy
486eda14cbcSMatt Macy error = 0;
487eda14cbcSMatt Macy
488eda14cbcSMatt Macy /* Remove a specific name xattr when value is set to NULL. */
489eda14cbcSMatt Macy if (value == NULL) {
490eda14cbcSMatt Macy if (xzp)
491eda14cbcSMatt Macy error = -zfs_remove(dxzp, (char *)name, cr, 0);
492eda14cbcSMatt Macy
493eda14cbcSMatt Macy goto out;
494eda14cbcSMatt Macy }
495eda14cbcSMatt Macy
496eda14cbcSMatt Macy /* Lookup failed create a new xattr. */
497eda14cbcSMatt Macy if (xzp == NULL) {
498eda14cbcSMatt Macy vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
499eda14cbcSMatt Macy vap->va_mode = xattr_mode;
500eda14cbcSMatt Macy vap->va_mask = ATTR_MODE;
501da5137abSMartin Matuska vap->va_uid = crgetuid(cr);
502da5137abSMartin Matuska vap->va_gid = crgetgid(cr);
503eda14cbcSMatt Macy
504eda14cbcSMatt Macy error = -zfs_create(dxzp, (char *)name, vap, 0, 0644, &xzp,
505d411c1d6SMartin Matuska cr, ATTR_NOACLCHECK, NULL, zfs_init_idmap);
506eda14cbcSMatt Macy if (error)
507eda14cbcSMatt Macy goto out;
508eda14cbcSMatt Macy }
509eda14cbcSMatt Macy
510eda14cbcSMatt Macy ASSERT(xzp != NULL);
511eda14cbcSMatt Macy
512eda14cbcSMatt Macy error = -zfs_freesp(xzp, 0, 0, xattr_mode, TRUE);
513eda14cbcSMatt Macy if (error)
514eda14cbcSMatt Macy goto out;
515eda14cbcSMatt Macy
5167877fdebSMatt Macy error = -zfs_write_simple(xzp, value, size, pos, NULL);
517eda14cbcSMatt Macy out:
518eda14cbcSMatt Macy if (error == 0) {
519abcdc1b9SMartin Matuska zpl_inode_set_ctime_to_ts(ip, current_time(ip));
520eda14cbcSMatt Macy zfs_mark_inode_dirty(ip);
521eda14cbcSMatt Macy }
522eda14cbcSMatt Macy
523eda14cbcSMatt Macy if (vap)
524eda14cbcSMatt Macy kmem_free(vap, sizeof (vattr_t));
525eda14cbcSMatt Macy
526eda14cbcSMatt Macy if (xzp)
527eda14cbcSMatt Macy zrele(xzp);
528eda14cbcSMatt Macy
529eda14cbcSMatt Macy if (dxzp)
530eda14cbcSMatt Macy zrele(dxzp);
531eda14cbcSMatt Macy
532eda14cbcSMatt Macy if (error == -ENOENT)
533eda14cbcSMatt Macy error = -ENODATA;
534eda14cbcSMatt Macy
535eda14cbcSMatt Macy ASSERT3S(error, <=, 0);
536eda14cbcSMatt Macy
537eda14cbcSMatt Macy return (error);
538eda14cbcSMatt Macy }
539eda14cbcSMatt Macy
540eda14cbcSMatt Macy static int
zpl_xattr_set_sa(struct inode * ip,const char * name,const void * value,size_t size,int flags,cred_t * cr)541eda14cbcSMatt Macy zpl_xattr_set_sa(struct inode *ip, const char *name, const void *value,
542eda14cbcSMatt Macy size_t size, int flags, cred_t *cr)
543eda14cbcSMatt Macy {
544eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
545eda14cbcSMatt Macy nvlist_t *nvl;
546eda14cbcSMatt Macy size_t sa_size;
547eda14cbcSMatt Macy int error = 0;
548eda14cbcSMatt Macy
549eda14cbcSMatt Macy mutex_enter(&zp->z_lock);
550eda14cbcSMatt Macy if (zp->z_xattr_cached == NULL)
551eda14cbcSMatt Macy error = -zfs_sa_get_xattr(zp);
552eda14cbcSMatt Macy mutex_exit(&zp->z_lock);
553eda14cbcSMatt Macy
554eda14cbcSMatt Macy if (error)
555eda14cbcSMatt Macy return (error);
556eda14cbcSMatt Macy
557eda14cbcSMatt Macy ASSERT(zp->z_xattr_cached);
558eda14cbcSMatt Macy nvl = zp->z_xattr_cached;
559eda14cbcSMatt Macy
560eda14cbcSMatt Macy if (value == NULL) {
561eda14cbcSMatt Macy error = -nvlist_remove(nvl, name, DATA_TYPE_BYTE_ARRAY);
562eda14cbcSMatt Macy if (error == -ENOENT)
563eda14cbcSMatt Macy error = zpl_xattr_set_dir(ip, name, NULL, 0, flags, cr);
564eda14cbcSMatt Macy } else {
565eda14cbcSMatt Macy /* Limited to 32k to keep nvpair memory allocations small */
566eda14cbcSMatt Macy if (size > DXATTR_MAX_ENTRY_SIZE)
567eda14cbcSMatt Macy return (-EFBIG);
568eda14cbcSMatt Macy
569eda14cbcSMatt Macy /* Prevent the DXATTR SA from consuming the entire SA region */
570eda14cbcSMatt Macy error = -nvlist_size(nvl, &sa_size, NV_ENCODE_XDR);
571eda14cbcSMatt Macy if (error)
572eda14cbcSMatt Macy return (error);
573eda14cbcSMatt Macy
574eda14cbcSMatt Macy if (sa_size > DXATTR_MAX_SA_SIZE)
575eda14cbcSMatt Macy return (-EFBIG);
576eda14cbcSMatt Macy
577eda14cbcSMatt Macy error = -nvlist_add_byte_array(nvl, name,
578eda14cbcSMatt Macy (uchar_t *)value, size);
579eda14cbcSMatt Macy }
580eda14cbcSMatt Macy
581eda14cbcSMatt Macy /*
582eda14cbcSMatt Macy * Update the SA for additions, modifications, and removals. On
583eda14cbcSMatt Macy * error drop the inconsistent cached version of the nvlist, it
584eda14cbcSMatt Macy * will be reconstructed from the ARC when next accessed.
585eda14cbcSMatt Macy */
586eda14cbcSMatt Macy if (error == 0)
587c03c5b1cSMartin Matuska error = -zfs_sa_set_xattr(zp, name, value, size);
588eda14cbcSMatt Macy
589eda14cbcSMatt Macy if (error) {
590eda14cbcSMatt Macy nvlist_free(nvl);
591eda14cbcSMatt Macy zp->z_xattr_cached = NULL;
592eda14cbcSMatt Macy }
593eda14cbcSMatt Macy
594eda14cbcSMatt Macy ASSERT3S(error, <=, 0);
595eda14cbcSMatt Macy
596eda14cbcSMatt Macy return (error);
597eda14cbcSMatt Macy }
598eda14cbcSMatt Macy
599eda14cbcSMatt Macy static int
zpl_xattr_set(struct inode * ip,const char * name,const void * value,size_t size,int flags)600eda14cbcSMatt Macy zpl_xattr_set(struct inode *ip, const char *name, const void *value,
601eda14cbcSMatt Macy size_t size, int flags)
602eda14cbcSMatt Macy {
603eda14cbcSMatt Macy znode_t *zp = ITOZ(ip);
604eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ZTOZSB(zp);
605eda14cbcSMatt Macy cred_t *cr = CRED();
606eda14cbcSMatt Macy fstrans_cookie_t cookie;
607eda14cbcSMatt Macy int where;
608eda14cbcSMatt Macy int error;
609eda14cbcSMatt Macy
610eda14cbcSMatt Macy crhold(cr);
611eda14cbcSMatt Macy cookie = spl_fstrans_mark();
612c7046f76SMartin Matuska if ((error = zpl_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
613c7046f76SMartin Matuska goto out1;
61416038816SMartin Matuska rw_enter(&zp->z_xattr_lock, RW_WRITER);
615eda14cbcSMatt Macy
616eda14cbcSMatt Macy /*
617eda14cbcSMatt Macy * Before setting the xattr check to see if it already exists.
618eda14cbcSMatt Macy * This is done to ensure the following optional flags are honored.
619eda14cbcSMatt Macy *
620eda14cbcSMatt Macy * XATTR_CREATE: fail if xattr already exists
621eda14cbcSMatt Macy * XATTR_REPLACE: fail if xattr does not exist
622eda14cbcSMatt Macy *
623eda14cbcSMatt Macy * We also want to know if it resides in sa or dir, so we can make
624eda14cbcSMatt Macy * sure we don't end up with duplicate in both places.
625eda14cbcSMatt Macy */
626eda14cbcSMatt Macy error = __zpl_xattr_where(ip, name, &where, cr);
627eda14cbcSMatt Macy if (error < 0) {
628eda14cbcSMatt Macy if (error != -ENODATA)
629eda14cbcSMatt Macy goto out;
630eda14cbcSMatt Macy if (flags & XATTR_REPLACE)
631eda14cbcSMatt Macy goto out;
632eda14cbcSMatt Macy
633eda14cbcSMatt Macy /* The xattr to be removed already doesn't exist */
634eda14cbcSMatt Macy error = 0;
635eda14cbcSMatt Macy if (value == NULL)
636eda14cbcSMatt Macy goto out;
637eda14cbcSMatt Macy } else {
638eda14cbcSMatt Macy error = -EEXIST;
639eda14cbcSMatt Macy if (flags & XATTR_CREATE)
640eda14cbcSMatt Macy goto out;
641eda14cbcSMatt Macy }
642eda14cbcSMatt Macy
643eda14cbcSMatt Macy /* Preferentially store the xattr as a SA for better performance */
644eda14cbcSMatt Macy if (zfsvfs->z_use_sa && zp->z_is_sa &&
645eda14cbcSMatt Macy (zfsvfs->z_xattr_sa || (value == NULL && where & XATTR_IN_SA))) {
646eda14cbcSMatt Macy error = zpl_xattr_set_sa(ip, name, value, size, flags, cr);
647eda14cbcSMatt Macy if (error == 0) {
648eda14cbcSMatt Macy /*
649eda14cbcSMatt Macy * Successfully put into SA, we need to clear the one
650eda14cbcSMatt Macy * in dir.
651eda14cbcSMatt Macy */
652eda14cbcSMatt Macy if (where & XATTR_IN_DIR)
653eda14cbcSMatt Macy zpl_xattr_set_dir(ip, name, NULL, 0, 0, cr);
654eda14cbcSMatt Macy goto out;
655eda14cbcSMatt Macy }
656eda14cbcSMatt Macy }
657eda14cbcSMatt Macy
658eda14cbcSMatt Macy error = zpl_xattr_set_dir(ip, name, value, size, flags, cr);
659eda14cbcSMatt Macy /*
660eda14cbcSMatt Macy * Successfully put into dir, we need to clear the one in SA.
661eda14cbcSMatt Macy */
662eda14cbcSMatt Macy if (error == 0 && (where & XATTR_IN_SA))
663eda14cbcSMatt Macy zpl_xattr_set_sa(ip, name, NULL, 0, 0, cr);
664eda14cbcSMatt Macy out:
66516038816SMartin Matuska rw_exit(&zp->z_xattr_lock);
666c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG);
667c7046f76SMartin Matuska out1:
668eda14cbcSMatt Macy spl_fstrans_unmark(cookie);
669eda14cbcSMatt Macy crfree(cr);
670eda14cbcSMatt Macy ASSERT3S(error, <=, 0);
671eda14cbcSMatt Macy
672eda14cbcSMatt Macy return (error);
673eda14cbcSMatt Macy }
674eda14cbcSMatt Macy
675eda14cbcSMatt Macy /*
676eda14cbcSMatt Macy * Extended user attributes
677eda14cbcSMatt Macy *
678eda14cbcSMatt Macy * "Extended user attributes may be assigned to files and directories for
679eda14cbcSMatt Macy * storing arbitrary additional information such as the mime type,
680eda14cbcSMatt Macy * character set or encoding of a file. The access permissions for user
681eda14cbcSMatt Macy * attributes are defined by the file permission bits: read permission
682eda14cbcSMatt Macy * is required to retrieve the attribute value, and writer permission is
683eda14cbcSMatt Macy * required to change it.
684eda14cbcSMatt Macy *
685eda14cbcSMatt Macy * The file permission bits of regular files and directories are
686eda14cbcSMatt Macy * interpreted differently from the file permission bits of special
687eda14cbcSMatt Macy * files and symbolic links. For regular files and directories the file
688eda14cbcSMatt Macy * permission bits define access to the file's contents, while for
689eda14cbcSMatt Macy * device special files they define access to the device described by
690eda14cbcSMatt Macy * the special file. The file permissions of symbolic links are not
691eda14cbcSMatt Macy * used in access checks. These differences would allow users to
692eda14cbcSMatt Macy * consume filesystem resources in a way not controllable by disk quotas
693eda14cbcSMatt Macy * for group or world writable special files and directories.
694eda14cbcSMatt Macy *
695eda14cbcSMatt Macy * For this reason, extended user attributes are allowed only for
696eda14cbcSMatt Macy * regular files and directories, and access to extended user attributes
697eda14cbcSMatt Macy * is restricted to the owner and to users with appropriate capabilities
698eda14cbcSMatt Macy * for directories with the sticky bit set (see the chmod(1) manual page
699eda14cbcSMatt Macy * for an explanation of the sticky bit)." - xattr(7)
700eda14cbcSMatt Macy *
701eda14cbcSMatt Macy * ZFS allows extended user attributes to be disabled administratively
702eda14cbcSMatt Macy * by setting the 'xattr=off' property on the dataset.
703eda14cbcSMatt Macy */
704eda14cbcSMatt Macy static int
__zpl_xattr_user_list(struct inode * ip,char * list,size_t list_size,const char * name,size_t name_len)705eda14cbcSMatt Macy __zpl_xattr_user_list(struct inode *ip, char *list, size_t list_size,
706eda14cbcSMatt Macy const char *name, size_t name_len)
707eda14cbcSMatt Macy {
708eda14cbcSMatt Macy return (ITOZSB(ip)->z_flags & ZSB_XATTR);
709eda14cbcSMatt Macy }
710eda14cbcSMatt Macy ZPL_XATTR_LIST_WRAPPER(zpl_xattr_user_list);
711eda14cbcSMatt Macy
712eda14cbcSMatt Macy static int
__zpl_xattr_user_get(struct inode * ip,const char * name,void * value,size_t size)713eda14cbcSMatt Macy __zpl_xattr_user_get(struct inode *ip, const char *name,
714eda14cbcSMatt Macy void *value, size_t size)
715eda14cbcSMatt Macy {
716eda14cbcSMatt Macy int error;
717eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
718c03c5b1cSMartin Matuska if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
719c03c5b1cSMartin Matuska return (-EINVAL);
720eda14cbcSMatt Macy if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
721eda14cbcSMatt Macy return (-EOPNOTSUPP);
722eda14cbcSMatt Macy
723c03c5b1cSMartin Matuska /*
724c03c5b1cSMartin Matuska * Try to look up the name with the namespace prefix first for
725c03c5b1cSMartin Matuska * compatibility with xattrs from this platform. If that fails,
726c03c5b1cSMartin Matuska * try again without the namespace prefix for compatibility with
727c03c5b1cSMartin Matuska * other platforms.
728c03c5b1cSMartin Matuska */
729c03c5b1cSMartin Matuska char *xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
730eda14cbcSMatt Macy error = zpl_xattr_get(ip, xattr_name, value, size);
731eda14cbcSMatt Macy kmem_strfree(xattr_name);
732c03c5b1cSMartin Matuska if (error == -ENODATA)
733c03c5b1cSMartin Matuska error = zpl_xattr_get(ip, name, value, size);
734eda14cbcSMatt Macy
735eda14cbcSMatt Macy return (error);
736eda14cbcSMatt Macy }
737eda14cbcSMatt Macy ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get);
738eda14cbcSMatt Macy
739eda14cbcSMatt Macy static int
__zpl_xattr_user_set(zidmap_t * user_ns,struct inode * ip,const char * name,const void * value,size_t size,int flags)740d411c1d6SMartin Matuska __zpl_xattr_user_set(zidmap_t *user_ns,
741dbd5678dSMartin Matuska struct inode *ip, const char *name,
742eda14cbcSMatt Macy const void *value, size_t size, int flags)
743eda14cbcSMatt Macy {
744dbd5678dSMartin Matuska (void) user_ns;
745c03c5b1cSMartin Matuska int error = 0;
746eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
747c03c5b1cSMartin Matuska if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
748c03c5b1cSMartin Matuska return (-EINVAL);
749eda14cbcSMatt Macy if (!(ITOZSB(ip)->z_flags & ZSB_XATTR))
750eda14cbcSMatt Macy return (-EOPNOTSUPP);
751eda14cbcSMatt Macy
752c03c5b1cSMartin Matuska /*
753c03c5b1cSMartin Matuska * Remove alternate compat version of the xattr so we only set the
754c03c5b1cSMartin Matuska * version specified by the zfs_xattr_compat tunable.
755c03c5b1cSMartin Matuska *
756c03c5b1cSMartin Matuska * The following flags must be handled correctly:
757c03c5b1cSMartin Matuska *
758c03c5b1cSMartin Matuska * XATTR_CREATE: fail if xattr already exists
759c03c5b1cSMartin Matuska * XATTR_REPLACE: fail if xattr does not exist
760c03c5b1cSMartin Matuska */
761c03c5b1cSMartin Matuska char *prefixed_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
762c03c5b1cSMartin Matuska const char *clear_name, *set_name;
763c03c5b1cSMartin Matuska if (zfs_xattr_compat) {
764c03c5b1cSMartin Matuska clear_name = prefixed_name;
765c03c5b1cSMartin Matuska set_name = name;
766c03c5b1cSMartin Matuska } else {
767c03c5b1cSMartin Matuska clear_name = name;
768c03c5b1cSMartin Matuska set_name = prefixed_name;
769c03c5b1cSMartin Matuska }
770c03c5b1cSMartin Matuska /*
771c03c5b1cSMartin Matuska * Clear the old value with the alternative name format, if it exists.
772c03c5b1cSMartin Matuska */
773c03c5b1cSMartin Matuska error = zpl_xattr_set(ip, clear_name, NULL, 0, flags);
774c03c5b1cSMartin Matuska /*
775c03c5b1cSMartin Matuska * XATTR_CREATE was specified and we failed to clear the xattr
776c03c5b1cSMartin Matuska * because it already exists. Stop here.
777c03c5b1cSMartin Matuska */
778c03c5b1cSMartin Matuska if (error == -EEXIST)
779c03c5b1cSMartin Matuska goto out;
780c03c5b1cSMartin Matuska /*
781c03c5b1cSMartin Matuska * If XATTR_REPLACE was specified and we succeeded to clear
782c03c5b1cSMartin Matuska * an xattr, we don't need to replace anything when setting
783c03c5b1cSMartin Matuska * the new value. If we failed with -ENODATA that's fine,
784c03c5b1cSMartin Matuska * there was nothing to be cleared and we can ignore the error.
785c03c5b1cSMartin Matuska */
786c03c5b1cSMartin Matuska if (error == 0)
787c03c5b1cSMartin Matuska flags &= ~XATTR_REPLACE;
788c03c5b1cSMartin Matuska /*
789c03c5b1cSMartin Matuska * Set the new value with the configured name format.
790c03c5b1cSMartin Matuska */
791c03c5b1cSMartin Matuska error = zpl_xattr_set(ip, set_name, value, size, flags);
792c03c5b1cSMartin Matuska out:
793c03c5b1cSMartin Matuska kmem_strfree(prefixed_name);
794eda14cbcSMatt Macy return (error);
795eda14cbcSMatt Macy }
796eda14cbcSMatt Macy ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set);
797eda14cbcSMatt Macy
798e92ffd9bSMartin Matuska static xattr_handler_t zpl_xattr_user_handler =
799eda14cbcSMatt Macy {
800eda14cbcSMatt Macy .prefix = XATTR_USER_PREFIX,
801eda14cbcSMatt Macy .list = zpl_xattr_user_list,
802eda14cbcSMatt Macy .get = zpl_xattr_user_get,
803eda14cbcSMatt Macy .set = zpl_xattr_user_set,
804eda14cbcSMatt Macy };
805eda14cbcSMatt Macy
806eda14cbcSMatt Macy /*
807eda14cbcSMatt Macy * Trusted extended attributes
808eda14cbcSMatt Macy *
809eda14cbcSMatt Macy * "Trusted extended attributes are visible and accessible only to
810eda14cbcSMatt Macy * processes that have the CAP_SYS_ADMIN capability. Attributes in this
811eda14cbcSMatt Macy * class are used to implement mechanisms in user space (i.e., outside
812eda14cbcSMatt Macy * the kernel) which keep information in extended attributes to which
813eda14cbcSMatt Macy * ordinary processes should not have access." - xattr(7)
814eda14cbcSMatt Macy */
815eda14cbcSMatt Macy static int
__zpl_xattr_trusted_list(struct inode * ip,char * list,size_t list_size,const char * name,size_t name_len)816eda14cbcSMatt Macy __zpl_xattr_trusted_list(struct inode *ip, char *list, size_t list_size,
817eda14cbcSMatt Macy const char *name, size_t name_len)
818eda14cbcSMatt Macy {
819eda14cbcSMatt Macy return (capable(CAP_SYS_ADMIN));
820eda14cbcSMatt Macy }
821eda14cbcSMatt Macy ZPL_XATTR_LIST_WRAPPER(zpl_xattr_trusted_list);
822eda14cbcSMatt Macy
823eda14cbcSMatt Macy static int
__zpl_xattr_trusted_get(struct inode * ip,const char * name,void * value,size_t size)824eda14cbcSMatt Macy __zpl_xattr_trusted_get(struct inode *ip, const char *name,
825eda14cbcSMatt Macy void *value, size_t size)
826eda14cbcSMatt Macy {
827eda14cbcSMatt Macy char *xattr_name;
828eda14cbcSMatt Macy int error;
829eda14cbcSMatt Macy
830eda14cbcSMatt Macy if (!capable(CAP_SYS_ADMIN))
831eda14cbcSMatt Macy return (-EACCES);
832eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
833eda14cbcSMatt Macy xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
834eda14cbcSMatt Macy error = zpl_xattr_get(ip, xattr_name, value, size);
835eda14cbcSMatt Macy kmem_strfree(xattr_name);
836eda14cbcSMatt Macy
837eda14cbcSMatt Macy return (error);
838eda14cbcSMatt Macy }
839eda14cbcSMatt Macy ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get);
840eda14cbcSMatt Macy
841eda14cbcSMatt Macy static int
__zpl_xattr_trusted_set(zidmap_t * user_ns,struct inode * ip,const char * name,const void * value,size_t size,int flags)842d411c1d6SMartin Matuska __zpl_xattr_trusted_set(zidmap_t *user_ns,
843dbd5678dSMartin Matuska struct inode *ip, const char *name,
844eda14cbcSMatt Macy const void *value, size_t size, int flags)
845eda14cbcSMatt Macy {
846dbd5678dSMartin Matuska (void) user_ns;
847eda14cbcSMatt Macy char *xattr_name;
848eda14cbcSMatt Macy int error;
849eda14cbcSMatt Macy
850eda14cbcSMatt Macy if (!capable(CAP_SYS_ADMIN))
851eda14cbcSMatt Macy return (-EACCES);
852eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
853eda14cbcSMatt Macy xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
854eda14cbcSMatt Macy error = zpl_xattr_set(ip, xattr_name, value, size, flags);
855eda14cbcSMatt Macy kmem_strfree(xattr_name);
856eda14cbcSMatt Macy
857eda14cbcSMatt Macy return (error);
858eda14cbcSMatt Macy }
859eda14cbcSMatt Macy ZPL_XATTR_SET_WRAPPER(zpl_xattr_trusted_set);
860eda14cbcSMatt Macy
861e92ffd9bSMartin Matuska static xattr_handler_t zpl_xattr_trusted_handler = {
862eda14cbcSMatt Macy .prefix = XATTR_TRUSTED_PREFIX,
863eda14cbcSMatt Macy .list = zpl_xattr_trusted_list,
864eda14cbcSMatt Macy .get = zpl_xattr_trusted_get,
865eda14cbcSMatt Macy .set = zpl_xattr_trusted_set,
866eda14cbcSMatt Macy };
867eda14cbcSMatt Macy
868eda14cbcSMatt Macy /*
869eda14cbcSMatt Macy * Extended security attributes
870eda14cbcSMatt Macy *
871eda14cbcSMatt Macy * "The security attribute namespace is used by kernel security modules,
872eda14cbcSMatt Macy * such as Security Enhanced Linux, and also to implement file
873eda14cbcSMatt Macy * capabilities (see capabilities(7)). Read and write access
874eda14cbcSMatt Macy * permissions to security attributes depend on the policy implemented
875eda14cbcSMatt Macy * for each security attribute by the security module. When no security
876eda14cbcSMatt Macy * module is loaded, all processes have read access to extended security
877eda14cbcSMatt Macy * attributes, and write access is limited to processes that have the
878eda14cbcSMatt Macy * CAP_SYS_ADMIN capability." - xattr(7)
879eda14cbcSMatt Macy */
880eda14cbcSMatt Macy static int
__zpl_xattr_security_list(struct inode * ip,char * list,size_t list_size,const char * name,size_t name_len)881eda14cbcSMatt Macy __zpl_xattr_security_list(struct inode *ip, char *list, size_t list_size,
882eda14cbcSMatt Macy const char *name, size_t name_len)
883eda14cbcSMatt Macy {
884eda14cbcSMatt Macy return (1);
885eda14cbcSMatt Macy }
886eda14cbcSMatt Macy ZPL_XATTR_LIST_WRAPPER(zpl_xattr_security_list);
887eda14cbcSMatt Macy
888eda14cbcSMatt Macy static int
__zpl_xattr_security_get(struct inode * ip,const char * name,void * value,size_t size)889eda14cbcSMatt Macy __zpl_xattr_security_get(struct inode *ip, const char *name,
890eda14cbcSMatt Macy void *value, size_t size)
891eda14cbcSMatt Macy {
892eda14cbcSMatt Macy char *xattr_name;
893eda14cbcSMatt Macy int error;
894eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
895eda14cbcSMatt Macy xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
896eda14cbcSMatt Macy error = zpl_xattr_get(ip, xattr_name, value, size);
897eda14cbcSMatt Macy kmem_strfree(xattr_name);
898eda14cbcSMatt Macy
899eda14cbcSMatt Macy return (error);
900eda14cbcSMatt Macy }
901eda14cbcSMatt Macy ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get);
902eda14cbcSMatt Macy
903eda14cbcSMatt Macy static int
__zpl_xattr_security_set(zidmap_t * user_ns,struct inode * ip,const char * name,const void * value,size_t size,int flags)904d411c1d6SMartin Matuska __zpl_xattr_security_set(zidmap_t *user_ns,
905dbd5678dSMartin Matuska struct inode *ip, const char *name,
906eda14cbcSMatt Macy const void *value, size_t size, int flags)
907eda14cbcSMatt Macy {
908dbd5678dSMartin Matuska (void) user_ns;
909eda14cbcSMatt Macy char *xattr_name;
910eda14cbcSMatt Macy int error;
911eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
912eda14cbcSMatt Macy xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
913eda14cbcSMatt Macy error = zpl_xattr_set(ip, xattr_name, value, size, flags);
914eda14cbcSMatt Macy kmem_strfree(xattr_name);
915eda14cbcSMatt Macy
916eda14cbcSMatt Macy return (error);
917eda14cbcSMatt Macy }
918eda14cbcSMatt Macy ZPL_XATTR_SET_WRAPPER(zpl_xattr_security_set);
919eda14cbcSMatt Macy
920eda14cbcSMatt Macy static int
zpl_xattr_security_init_impl(struct inode * ip,const struct xattr * xattrs,void * fs_info)921eda14cbcSMatt Macy zpl_xattr_security_init_impl(struct inode *ip, const struct xattr *xattrs,
922eda14cbcSMatt Macy void *fs_info)
923eda14cbcSMatt Macy {
924eda14cbcSMatt Macy const struct xattr *xattr;
925eda14cbcSMatt Macy int error = 0;
926eda14cbcSMatt Macy
927eda14cbcSMatt Macy for (xattr = xattrs; xattr->name != NULL; xattr++) {
928dbd5678dSMartin Matuska error = __zpl_xattr_security_set(NULL, ip,
929eda14cbcSMatt Macy xattr->name, xattr->value, xattr->value_len, 0);
930eda14cbcSMatt Macy
931eda14cbcSMatt Macy if (error < 0)
932eda14cbcSMatt Macy break;
933eda14cbcSMatt Macy }
934eda14cbcSMatt Macy
935eda14cbcSMatt Macy return (error);
936eda14cbcSMatt Macy }
937eda14cbcSMatt Macy
938eda14cbcSMatt Macy int
zpl_xattr_security_init(struct inode * ip,struct inode * dip,const struct qstr * qstr)939eda14cbcSMatt Macy zpl_xattr_security_init(struct inode *ip, struct inode *dip,
940eda14cbcSMatt Macy const struct qstr *qstr)
941eda14cbcSMatt Macy {
942eda14cbcSMatt Macy return security_inode_init_security(ip, dip, qstr,
943eda14cbcSMatt Macy &zpl_xattr_security_init_impl, NULL);
944eda14cbcSMatt Macy }
945eda14cbcSMatt Macy
946eda14cbcSMatt Macy /*
947eda14cbcSMatt Macy * Security xattr namespace handlers.
948eda14cbcSMatt Macy */
949e92ffd9bSMartin Matuska static xattr_handler_t zpl_xattr_security_handler = {
950eda14cbcSMatt Macy .prefix = XATTR_SECURITY_PREFIX,
951eda14cbcSMatt Macy .list = zpl_xattr_security_list,
952eda14cbcSMatt Macy .get = zpl_xattr_security_get,
953eda14cbcSMatt Macy .set = zpl_xattr_security_set,
954eda14cbcSMatt Macy };
955eda14cbcSMatt Macy
956eda14cbcSMatt Macy /*
957eda14cbcSMatt Macy * Extended system attributes
958eda14cbcSMatt Macy *
959eda14cbcSMatt Macy * "Extended system attributes are used by the kernel to store system
960eda14cbcSMatt Macy * objects such as Access Control Lists. Read and write access permissions
961eda14cbcSMatt Macy * to system attributes depend on the policy implemented for each system
962eda14cbcSMatt Macy * attribute implemented by filesystems in the kernel." - xattr(7)
963eda14cbcSMatt Macy */
964eda14cbcSMatt Macy #ifdef CONFIG_FS_POSIX_ACL
96516038816SMartin Matuska static int
zpl_set_acl_impl(struct inode * ip,struct posix_acl * acl,int type)96616038816SMartin Matuska zpl_set_acl_impl(struct inode *ip, struct posix_acl *acl, int type)
967eda14cbcSMatt Macy {
968eda14cbcSMatt Macy char *name, *value = NULL;
969eda14cbcSMatt Macy int error = 0;
970eda14cbcSMatt Macy size_t size = 0;
971eda14cbcSMatt Macy
972eda14cbcSMatt Macy if (S_ISLNK(ip->i_mode))
973eda14cbcSMatt Macy return (-EOPNOTSUPP);
974eda14cbcSMatt Macy
975eda14cbcSMatt Macy switch (type) {
976eda14cbcSMatt Macy case ACL_TYPE_ACCESS:
977eda14cbcSMatt Macy name = XATTR_NAME_POSIX_ACL_ACCESS;
978eda14cbcSMatt Macy if (acl) {
979eda14cbcSMatt Macy umode_t mode = ip->i_mode;
980eda14cbcSMatt Macy error = posix_acl_equiv_mode(acl, &mode);
981eda14cbcSMatt Macy if (error < 0) {
982eda14cbcSMatt Macy return (error);
983eda14cbcSMatt Macy } else {
984eda14cbcSMatt Macy /*
985eda14cbcSMatt Macy * The mode bits will have been set by
986eda14cbcSMatt Macy * ->zfs_setattr()->zfs_acl_chmod_setattr()
987eda14cbcSMatt Macy * using the ZFS ACL conversion. If they
988eda14cbcSMatt Macy * differ from the Posix ACL conversion dirty
989eda14cbcSMatt Macy * the inode to write the Posix mode bits.
990eda14cbcSMatt Macy */
991eda14cbcSMatt Macy if (ip->i_mode != mode) {
992a0b956f5SMartin Matuska ip->i_mode = ITOZ(ip)->z_mode = mode;
993abcdc1b9SMartin Matuska zpl_inode_set_ctime_to_ts(ip,
994abcdc1b9SMartin Matuska current_time(ip));
995eda14cbcSMatt Macy zfs_mark_inode_dirty(ip);
996eda14cbcSMatt Macy }
997eda14cbcSMatt Macy
998eda14cbcSMatt Macy if (error == 0)
999eda14cbcSMatt Macy acl = NULL;
1000eda14cbcSMatt Macy }
1001eda14cbcSMatt Macy }
1002eda14cbcSMatt Macy break;
1003eda14cbcSMatt Macy
1004eda14cbcSMatt Macy case ACL_TYPE_DEFAULT:
1005eda14cbcSMatt Macy name = XATTR_NAME_POSIX_ACL_DEFAULT;
1006eda14cbcSMatt Macy if (!S_ISDIR(ip->i_mode))
1007eda14cbcSMatt Macy return (acl ? -EACCES : 0);
1008eda14cbcSMatt Macy break;
1009eda14cbcSMatt Macy
1010eda14cbcSMatt Macy default:
1011eda14cbcSMatt Macy return (-EINVAL);
1012eda14cbcSMatt Macy }
1013eda14cbcSMatt Macy
1014eda14cbcSMatt Macy if (acl) {
1015eda14cbcSMatt Macy size = posix_acl_xattr_size(acl->a_count);
1016eda14cbcSMatt Macy value = kmem_alloc(size, KM_SLEEP);
1017eda14cbcSMatt Macy
1018eda14cbcSMatt Macy error = zpl_acl_to_xattr(acl, value, size);
1019eda14cbcSMatt Macy if (error < 0) {
1020eda14cbcSMatt Macy kmem_free(value, size);
1021eda14cbcSMatt Macy return (error);
1022eda14cbcSMatt Macy }
1023eda14cbcSMatt Macy }
1024eda14cbcSMatt Macy
1025eda14cbcSMatt Macy error = zpl_xattr_set(ip, name, value, size, 0);
1026eda14cbcSMatt Macy if (value)
1027eda14cbcSMatt Macy kmem_free(value, size);
1028eda14cbcSMatt Macy
1029eda14cbcSMatt Macy if (!error) {
1030eda14cbcSMatt Macy if (acl)
10317a7741afSMartin Matuska set_cached_acl(ip, type, acl);
1032eda14cbcSMatt Macy else
10337a7741afSMartin Matuska forget_cached_acl(ip, type);
1034eda14cbcSMatt Macy }
1035eda14cbcSMatt Macy
1036eda14cbcSMatt Macy return (error);
1037eda14cbcSMatt Macy }
1038eda14cbcSMatt Macy
103916038816SMartin Matuska int
104016038816SMartin Matuska #ifdef HAVE_SET_ACL_USERNS
zpl_set_acl(struct user_namespace * userns,struct inode * ip,struct posix_acl * acl,int type)104116038816SMartin Matuska zpl_set_acl(struct user_namespace *userns, struct inode *ip,
104216038816SMartin Matuska struct posix_acl *acl, int type)
1043d411c1d6SMartin Matuska #elif defined(HAVE_SET_ACL_IDMAP_DENTRY)
1044d411c1d6SMartin Matuska zpl_set_acl(struct mnt_idmap *userns, struct dentry *dentry,
1045d411c1d6SMartin Matuska struct posix_acl *acl, int type)
104615f0b8c3SMartin Matuska #elif defined(HAVE_SET_ACL_USERNS_DENTRY_ARG2)
104715f0b8c3SMartin Matuska zpl_set_acl(struct user_namespace *userns, struct dentry *dentry,
104815f0b8c3SMartin Matuska struct posix_acl *acl, int type)
104916038816SMartin Matuska #else
105016038816SMartin Matuska zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type)
105116038816SMartin Matuska #endif /* HAVE_SET_ACL_USERNS */
105216038816SMartin Matuska {
105315f0b8c3SMartin Matuska #ifdef HAVE_SET_ACL_USERNS_DENTRY_ARG2
105415f0b8c3SMartin Matuska return (zpl_set_acl_impl(d_inode(dentry), acl, type));
1055d411c1d6SMartin Matuska #elif defined(HAVE_SET_ACL_IDMAP_DENTRY)
1056d411c1d6SMartin Matuska return (zpl_set_acl_impl(d_inode(dentry), acl, type));
105715f0b8c3SMartin Matuska #else
105816038816SMartin Matuska return (zpl_set_acl_impl(ip, acl, type));
105915f0b8c3SMartin Matuska #endif /* HAVE_SET_ACL_USERNS_DENTRY_ARG2 */
106016038816SMartin Matuska }
106116038816SMartin Matuska
106253b70c86SMartin Matuska static struct posix_acl *
zpl_get_acl_impl(struct inode * ip,int type)106353b70c86SMartin Matuska zpl_get_acl_impl(struct inode *ip, int type)
1064eda14cbcSMatt Macy {
1065eda14cbcSMatt Macy struct posix_acl *acl;
1066eda14cbcSMatt Macy void *value = NULL;
1067eda14cbcSMatt Macy char *name;
1068eda14cbcSMatt Macy
1069eda14cbcSMatt Macy switch (type) {
1070eda14cbcSMatt Macy case ACL_TYPE_ACCESS:
1071eda14cbcSMatt Macy name = XATTR_NAME_POSIX_ACL_ACCESS;
1072eda14cbcSMatt Macy break;
1073eda14cbcSMatt Macy case ACL_TYPE_DEFAULT:
1074eda14cbcSMatt Macy name = XATTR_NAME_POSIX_ACL_DEFAULT;
1075eda14cbcSMatt Macy break;
1076eda14cbcSMatt Macy default:
1077eda14cbcSMatt Macy return (ERR_PTR(-EINVAL));
1078eda14cbcSMatt Macy }
1079eda14cbcSMatt Macy
108053b70c86SMartin Matuska int size = zpl_xattr_get(ip, name, NULL, 0);
1081eda14cbcSMatt Macy if (size > 0) {
1082eda14cbcSMatt Macy value = kmem_alloc(size, KM_SLEEP);
1083eda14cbcSMatt Macy size = zpl_xattr_get(ip, name, value, size);
1084eda14cbcSMatt Macy }
1085eda14cbcSMatt Macy
1086eda14cbcSMatt Macy if (size > 0) {
1087eda14cbcSMatt Macy acl = zpl_acl_from_xattr(value, size);
1088eda14cbcSMatt Macy } else if (size == -ENODATA || size == -ENOSYS) {
1089eda14cbcSMatt Macy acl = NULL;
1090eda14cbcSMatt Macy } else {
1091eda14cbcSMatt Macy acl = ERR_PTR(-EIO);
1092eda14cbcSMatt Macy }
1093eda14cbcSMatt Macy
1094eda14cbcSMatt Macy if (size > 0)
1095eda14cbcSMatt Macy kmem_free(value, size);
1096eda14cbcSMatt Macy
1097eda14cbcSMatt Macy return (acl);
1098eda14cbcSMatt Macy }
1099eda14cbcSMatt Macy
110015f0b8c3SMartin Matuska #if defined(HAVE_GET_ACL_RCU) || defined(HAVE_GET_INODE_ACL)
110153b70c86SMartin Matuska struct posix_acl *
zpl_get_acl(struct inode * ip,int type,bool rcu)110253b70c86SMartin Matuska zpl_get_acl(struct inode *ip, int type, bool rcu)
110353b70c86SMartin Matuska {
110453b70c86SMartin Matuska if (rcu)
110553b70c86SMartin Matuska return (ERR_PTR(-ECHILD));
110653b70c86SMartin Matuska
110753b70c86SMartin Matuska return (zpl_get_acl_impl(ip, type));
110853b70c86SMartin Matuska }
110953b70c86SMartin Matuska #elif defined(HAVE_GET_ACL)
111053b70c86SMartin Matuska struct posix_acl *
zpl_get_acl(struct inode * ip,int type)111153b70c86SMartin Matuska zpl_get_acl(struct inode *ip, int type)
111253b70c86SMartin Matuska {
111353b70c86SMartin Matuska return (zpl_get_acl_impl(ip, type));
111453b70c86SMartin Matuska }
111553b70c86SMartin Matuska #else
111653b70c86SMartin Matuska #error "Unsupported iops->get_acl() implementation"
111753b70c86SMartin Matuska #endif /* HAVE_GET_ACL_RCU */
111853b70c86SMartin Matuska
1119eda14cbcSMatt Macy int
zpl_init_acl(struct inode * ip,struct inode * dir)1120eda14cbcSMatt Macy zpl_init_acl(struct inode *ip, struct inode *dir)
1121eda14cbcSMatt Macy {
1122eda14cbcSMatt Macy struct posix_acl *acl = NULL;
1123eda14cbcSMatt Macy int error = 0;
1124eda14cbcSMatt Macy
11252c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1126eda14cbcSMatt Macy return (0);
1127eda14cbcSMatt Macy
1128eda14cbcSMatt Macy if (!S_ISLNK(ip->i_mode)) {
112953b70c86SMartin Matuska acl = zpl_get_acl_impl(dir, ACL_TYPE_DEFAULT);
1130eda14cbcSMatt Macy if (IS_ERR(acl))
1131eda14cbcSMatt Macy return (PTR_ERR(acl));
1132eda14cbcSMatt Macy if (!acl) {
1133a0b956f5SMartin Matuska ITOZ(ip)->z_mode = (ip->i_mode &= ~current_umask());
1134abcdc1b9SMartin Matuska zpl_inode_set_ctime_to_ts(ip, current_time(ip));
1135eda14cbcSMatt Macy zfs_mark_inode_dirty(ip);
1136eda14cbcSMatt Macy return (0);
1137eda14cbcSMatt Macy }
1138eda14cbcSMatt Macy }
1139eda14cbcSMatt Macy
1140eda14cbcSMatt Macy if (acl) {
1141eda14cbcSMatt Macy umode_t mode;
1142eda14cbcSMatt Macy
1143eda14cbcSMatt Macy if (S_ISDIR(ip->i_mode)) {
114416038816SMartin Matuska error = zpl_set_acl_impl(ip, acl, ACL_TYPE_DEFAULT);
1145eda14cbcSMatt Macy if (error)
1146eda14cbcSMatt Macy goto out;
1147eda14cbcSMatt Macy }
1148eda14cbcSMatt Macy
1149eda14cbcSMatt Macy mode = ip->i_mode;
1150eda14cbcSMatt Macy error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
1151eda14cbcSMatt Macy if (error >= 0) {
1152a0b956f5SMartin Matuska ip->i_mode = ITOZ(ip)->z_mode = mode;
1153eda14cbcSMatt Macy zfs_mark_inode_dirty(ip);
115416038816SMartin Matuska if (error > 0) {
115516038816SMartin Matuska error = zpl_set_acl_impl(ip, acl,
115616038816SMartin Matuska ACL_TYPE_ACCESS);
115716038816SMartin Matuska }
1158eda14cbcSMatt Macy }
1159eda14cbcSMatt Macy }
1160eda14cbcSMatt Macy out:
1161eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1162eda14cbcSMatt Macy
1163eda14cbcSMatt Macy return (error);
1164eda14cbcSMatt Macy }
1165eda14cbcSMatt Macy
1166eda14cbcSMatt Macy int
zpl_chmod_acl(struct inode * ip)1167eda14cbcSMatt Macy zpl_chmod_acl(struct inode *ip)
1168eda14cbcSMatt Macy {
1169eda14cbcSMatt Macy struct posix_acl *acl;
1170eda14cbcSMatt Macy int error;
1171eda14cbcSMatt Macy
11722c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1173eda14cbcSMatt Macy return (0);
1174eda14cbcSMatt Macy
1175eda14cbcSMatt Macy if (S_ISLNK(ip->i_mode))
1176eda14cbcSMatt Macy return (-EOPNOTSUPP);
1177eda14cbcSMatt Macy
117853b70c86SMartin Matuska acl = zpl_get_acl_impl(ip, ACL_TYPE_ACCESS);
1179eda14cbcSMatt Macy if (IS_ERR(acl) || !acl)
1180eda14cbcSMatt Macy return (PTR_ERR(acl));
1181eda14cbcSMatt Macy
1182eda14cbcSMatt Macy error = __posix_acl_chmod(&acl, GFP_KERNEL, ip->i_mode);
1183eda14cbcSMatt Macy if (!error)
118416038816SMartin Matuska error = zpl_set_acl_impl(ip, acl, ACL_TYPE_ACCESS);
1185eda14cbcSMatt Macy
1186eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1187eda14cbcSMatt Macy
1188eda14cbcSMatt Macy return (error);
1189eda14cbcSMatt Macy }
1190eda14cbcSMatt Macy
1191eda14cbcSMatt Macy static int
__zpl_xattr_acl_list_access(struct inode * ip,char * list,size_t list_size,const char * name,size_t name_len)1192eda14cbcSMatt Macy __zpl_xattr_acl_list_access(struct inode *ip, char *list, size_t list_size,
1193eda14cbcSMatt Macy const char *name, size_t name_len)
1194eda14cbcSMatt Macy {
1195eda14cbcSMatt Macy char *xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
1196eda14cbcSMatt Macy size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_ACCESS);
1197eda14cbcSMatt Macy
11982c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1199eda14cbcSMatt Macy return (0);
1200eda14cbcSMatt Macy
1201eda14cbcSMatt Macy if (list && xattr_size <= list_size)
1202eda14cbcSMatt Macy memcpy(list, xattr_name, xattr_size);
1203eda14cbcSMatt Macy
1204eda14cbcSMatt Macy return (xattr_size);
1205eda14cbcSMatt Macy }
1206eda14cbcSMatt Macy ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_access);
1207eda14cbcSMatt Macy
1208eda14cbcSMatt Macy static int
__zpl_xattr_acl_list_default(struct inode * ip,char * list,size_t list_size,const char * name,size_t name_len)1209eda14cbcSMatt Macy __zpl_xattr_acl_list_default(struct inode *ip, char *list, size_t list_size,
1210eda14cbcSMatt Macy const char *name, size_t name_len)
1211eda14cbcSMatt Macy {
1212eda14cbcSMatt Macy char *xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
1213eda14cbcSMatt Macy size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_DEFAULT);
1214eda14cbcSMatt Macy
12152c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1216eda14cbcSMatt Macy return (0);
1217eda14cbcSMatt Macy
1218eda14cbcSMatt Macy if (list && xattr_size <= list_size)
1219eda14cbcSMatt Macy memcpy(list, xattr_name, xattr_size);
1220eda14cbcSMatt Macy
1221eda14cbcSMatt Macy return (xattr_size);
1222eda14cbcSMatt Macy }
1223eda14cbcSMatt Macy ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_default);
1224eda14cbcSMatt Macy
1225eda14cbcSMatt Macy static int
__zpl_xattr_acl_get_access(struct inode * ip,const char * name,void * buffer,size_t size)1226eda14cbcSMatt Macy __zpl_xattr_acl_get_access(struct inode *ip, const char *name,
1227eda14cbcSMatt Macy void *buffer, size_t size)
1228eda14cbcSMatt Macy {
1229eda14cbcSMatt Macy struct posix_acl *acl;
1230eda14cbcSMatt Macy int type = ACL_TYPE_ACCESS;
1231eda14cbcSMatt Macy int error;
1232eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
12332c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1234eda14cbcSMatt Macy return (-EOPNOTSUPP);
1235eda14cbcSMatt Macy
123653b70c86SMartin Matuska acl = zpl_get_acl_impl(ip, type);
1237eda14cbcSMatt Macy if (IS_ERR(acl))
1238eda14cbcSMatt Macy return (PTR_ERR(acl));
1239eda14cbcSMatt Macy if (acl == NULL)
1240eda14cbcSMatt Macy return (-ENODATA);
1241eda14cbcSMatt Macy
1242eda14cbcSMatt Macy error = zpl_acl_to_xattr(acl, buffer, size);
1243eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1244eda14cbcSMatt Macy
1245eda14cbcSMatt Macy return (error);
1246eda14cbcSMatt Macy }
1247eda14cbcSMatt Macy ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_access);
1248eda14cbcSMatt Macy
1249eda14cbcSMatt Macy static int
__zpl_xattr_acl_get_default(struct inode * ip,const char * name,void * buffer,size_t size)1250eda14cbcSMatt Macy __zpl_xattr_acl_get_default(struct inode *ip, const char *name,
1251eda14cbcSMatt Macy void *buffer, size_t size)
1252eda14cbcSMatt Macy {
1253eda14cbcSMatt Macy struct posix_acl *acl;
1254eda14cbcSMatt Macy int type = ACL_TYPE_DEFAULT;
1255eda14cbcSMatt Macy int error;
1256eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
12572c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1258eda14cbcSMatt Macy return (-EOPNOTSUPP);
1259eda14cbcSMatt Macy
126053b70c86SMartin Matuska acl = zpl_get_acl_impl(ip, type);
1261eda14cbcSMatt Macy if (IS_ERR(acl))
1262eda14cbcSMatt Macy return (PTR_ERR(acl));
1263eda14cbcSMatt Macy if (acl == NULL)
1264eda14cbcSMatt Macy return (-ENODATA);
1265eda14cbcSMatt Macy
1266eda14cbcSMatt Macy error = zpl_acl_to_xattr(acl, buffer, size);
1267eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1268eda14cbcSMatt Macy
1269eda14cbcSMatt Macy return (error);
1270eda14cbcSMatt Macy }
1271eda14cbcSMatt Macy ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default);
1272eda14cbcSMatt Macy
1273eda14cbcSMatt Macy static int
__zpl_xattr_acl_set_access(zidmap_t * mnt_ns,struct inode * ip,const char * name,const void * value,size_t size,int flags)1274d411c1d6SMartin Matuska __zpl_xattr_acl_set_access(zidmap_t *mnt_ns,
1275dbd5678dSMartin Matuska struct inode *ip, const char *name,
1276eda14cbcSMatt Macy const void *value, size_t size, int flags)
1277eda14cbcSMatt Macy {
1278eda14cbcSMatt Macy struct posix_acl *acl;
1279eda14cbcSMatt Macy int type = ACL_TYPE_ACCESS;
1280eda14cbcSMatt Macy int error = 0;
1281eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
12822c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1283eda14cbcSMatt Macy return (-EOPNOTSUPP);
1284eda14cbcSMatt Macy
1285d411c1d6SMartin Matuska #if defined(HAVE_XATTR_SET_USERNS) || defined(HAVE_XATTR_SET_IDMAP)
1286dbd5678dSMartin Matuska if (!zpl_inode_owner_or_capable(mnt_ns, ip))
1287dbd5678dSMartin Matuska return (-EPERM);
1288dbd5678dSMartin Matuska #else
1289dbd5678dSMartin Matuska (void) mnt_ns;
1290d411c1d6SMartin Matuska if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip))
1291eda14cbcSMatt Macy return (-EPERM);
1292dbd5678dSMartin Matuska #endif
1293eda14cbcSMatt Macy
1294eda14cbcSMatt Macy if (value) {
1295eda14cbcSMatt Macy acl = zpl_acl_from_xattr(value, size);
1296eda14cbcSMatt Macy if (IS_ERR(acl))
1297eda14cbcSMatt Macy return (PTR_ERR(acl));
1298eda14cbcSMatt Macy else if (acl) {
12997a7741afSMartin Matuska error = posix_acl_valid(ip->i_sb->s_user_ns, acl);
1300eda14cbcSMatt Macy if (error) {
1301eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1302eda14cbcSMatt Macy return (error);
1303eda14cbcSMatt Macy }
1304eda14cbcSMatt Macy }
1305eda14cbcSMatt Macy } else {
1306eda14cbcSMatt Macy acl = NULL;
1307eda14cbcSMatt Macy }
130816038816SMartin Matuska error = zpl_set_acl_impl(ip, acl, type);
1309eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1310eda14cbcSMatt Macy
1311eda14cbcSMatt Macy return (error);
1312eda14cbcSMatt Macy }
1313eda14cbcSMatt Macy ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access);
1314eda14cbcSMatt Macy
1315eda14cbcSMatt Macy static int
__zpl_xattr_acl_set_default(zidmap_t * mnt_ns,struct inode * ip,const char * name,const void * value,size_t size,int flags)1316d411c1d6SMartin Matuska __zpl_xattr_acl_set_default(zidmap_t *mnt_ns,
1317dbd5678dSMartin Matuska struct inode *ip, const char *name,
1318eda14cbcSMatt Macy const void *value, size_t size, int flags)
1319eda14cbcSMatt Macy {
1320eda14cbcSMatt Macy struct posix_acl *acl;
1321eda14cbcSMatt Macy int type = ACL_TYPE_DEFAULT;
1322eda14cbcSMatt Macy int error = 0;
1323eda14cbcSMatt Macy /* xattr_resolve_name will do this for us if this is defined */
13242c48331dSMatt Macy if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
1325eda14cbcSMatt Macy return (-EOPNOTSUPP);
1326eda14cbcSMatt Macy
1327d411c1d6SMartin Matuska #if defined(HAVE_XATTR_SET_USERNS) || defined(HAVE_XATTR_SET_IDMAP)
1328dbd5678dSMartin Matuska if (!zpl_inode_owner_or_capable(mnt_ns, ip))
1329dbd5678dSMartin Matuska return (-EPERM);
1330dbd5678dSMartin Matuska #else
1331dbd5678dSMartin Matuska (void) mnt_ns;
1332d411c1d6SMartin Matuska if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip))
1333eda14cbcSMatt Macy return (-EPERM);
1334dbd5678dSMartin Matuska #endif
1335eda14cbcSMatt Macy
1336eda14cbcSMatt Macy if (value) {
1337eda14cbcSMatt Macy acl = zpl_acl_from_xattr(value, size);
1338eda14cbcSMatt Macy if (IS_ERR(acl))
1339eda14cbcSMatt Macy return (PTR_ERR(acl));
1340eda14cbcSMatt Macy else if (acl) {
13417a7741afSMartin Matuska error = posix_acl_valid(ip->i_sb->s_user_ns, acl);
1342eda14cbcSMatt Macy if (error) {
1343eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1344eda14cbcSMatt Macy return (error);
1345eda14cbcSMatt Macy }
1346eda14cbcSMatt Macy }
1347eda14cbcSMatt Macy } else {
1348eda14cbcSMatt Macy acl = NULL;
1349eda14cbcSMatt Macy }
1350eda14cbcSMatt Macy
135116038816SMartin Matuska error = zpl_set_acl_impl(ip, acl, type);
1352eda14cbcSMatt Macy zpl_posix_acl_release(acl);
1353eda14cbcSMatt Macy
1354eda14cbcSMatt Macy return (error);
1355eda14cbcSMatt Macy }
1356eda14cbcSMatt Macy ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_default);
1357eda14cbcSMatt Macy
1358eda14cbcSMatt Macy /*
1359eda14cbcSMatt Macy * ACL access xattr namespace handlers.
1360eda14cbcSMatt Macy *
1361eda14cbcSMatt Macy * Use .name instead of .prefix when available. xattr_resolve_name will match
1362eda14cbcSMatt Macy * whole name and reject anything that has .name only as prefix.
1363eda14cbcSMatt Macy */
1364e92ffd9bSMartin Matuska static xattr_handler_t zpl_xattr_acl_access_handler = {
1365eda14cbcSMatt Macy .name = XATTR_NAME_POSIX_ACL_ACCESS,
1366eda14cbcSMatt Macy .list = zpl_xattr_acl_list_access,
1367eda14cbcSMatt Macy .get = zpl_xattr_acl_get_access,
1368eda14cbcSMatt Macy .set = zpl_xattr_acl_set_access,
1369eda14cbcSMatt Macy .flags = ACL_TYPE_ACCESS,
1370eda14cbcSMatt Macy };
1371eda14cbcSMatt Macy
1372eda14cbcSMatt Macy /*
1373eda14cbcSMatt Macy * ACL default xattr namespace handlers.
1374eda14cbcSMatt Macy *
13757a7741afSMartin Matuska * Use .name instead of .prefix. xattr_resolve_name will match whole name and
13767a7741afSMartin Matuska * reject anything that has .name only as prefix.
1377eda14cbcSMatt Macy */
1378e92ffd9bSMartin Matuska static xattr_handler_t zpl_xattr_acl_default_handler = {
1379eda14cbcSMatt Macy .name = XATTR_NAME_POSIX_ACL_DEFAULT,
1380eda14cbcSMatt Macy .list = zpl_xattr_acl_list_default,
1381eda14cbcSMatt Macy .get = zpl_xattr_acl_get_default,
1382eda14cbcSMatt Macy .set = zpl_xattr_acl_set_default,
1383eda14cbcSMatt Macy .flags = ACL_TYPE_DEFAULT,
1384eda14cbcSMatt Macy };
1385eda14cbcSMatt Macy
1386eda14cbcSMatt Macy #endif /* CONFIG_FS_POSIX_ACL */
1387eda14cbcSMatt Macy
1388eda14cbcSMatt Macy xattr_handler_t *zpl_xattr_handlers[] = {
1389eda14cbcSMatt Macy &zpl_xattr_security_handler,
1390eda14cbcSMatt Macy &zpl_xattr_trusted_handler,
1391eda14cbcSMatt Macy &zpl_xattr_user_handler,
1392eda14cbcSMatt Macy #ifdef CONFIG_FS_POSIX_ACL
1393eda14cbcSMatt Macy &zpl_xattr_acl_access_handler,
1394eda14cbcSMatt Macy &zpl_xattr_acl_default_handler,
1395eda14cbcSMatt Macy #endif /* CONFIG_FS_POSIX_ACL */
1396eda14cbcSMatt Macy NULL
1397eda14cbcSMatt Macy };
1398eda14cbcSMatt Macy
1399eda14cbcSMatt Macy static const struct xattr_handler *
zpl_xattr_handler(const char * name)1400eda14cbcSMatt Macy zpl_xattr_handler(const char *name)
1401eda14cbcSMatt Macy {
1402eda14cbcSMatt Macy if (strncmp(name, XATTR_USER_PREFIX,
1403eda14cbcSMatt Macy XATTR_USER_PREFIX_LEN) == 0)
1404eda14cbcSMatt Macy return (&zpl_xattr_user_handler);
1405eda14cbcSMatt Macy
1406eda14cbcSMatt Macy if (strncmp(name, XATTR_TRUSTED_PREFIX,
1407eda14cbcSMatt Macy XATTR_TRUSTED_PREFIX_LEN) == 0)
1408eda14cbcSMatt Macy return (&zpl_xattr_trusted_handler);
1409eda14cbcSMatt Macy
1410eda14cbcSMatt Macy if (strncmp(name, XATTR_SECURITY_PREFIX,
1411eda14cbcSMatt Macy XATTR_SECURITY_PREFIX_LEN) == 0)
1412eda14cbcSMatt Macy return (&zpl_xattr_security_handler);
1413eda14cbcSMatt Macy
1414eda14cbcSMatt Macy #ifdef CONFIG_FS_POSIX_ACL
1415eda14cbcSMatt Macy if (strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
1416eda14cbcSMatt Macy sizeof (XATTR_NAME_POSIX_ACL_ACCESS)) == 0)
1417eda14cbcSMatt Macy return (&zpl_xattr_acl_access_handler);
1418eda14cbcSMatt Macy
1419eda14cbcSMatt Macy if (strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
1420eda14cbcSMatt Macy sizeof (XATTR_NAME_POSIX_ACL_DEFAULT)) == 0)
1421eda14cbcSMatt Macy return (&zpl_xattr_acl_default_handler);
1422eda14cbcSMatt Macy #endif /* CONFIG_FS_POSIX_ACL */
1423eda14cbcSMatt Macy
1424eda14cbcSMatt Macy return (NULL);
1425eda14cbcSMatt Macy }
1426eda14cbcSMatt Macy
1427c03c5b1cSMartin Matuska static enum xattr_permission
zpl_xattr_permission(xattr_filldir_t * xf,const char * name,int name_len)1428c03c5b1cSMartin Matuska zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
1429c03c5b1cSMartin Matuska {
1430c03c5b1cSMartin Matuska const struct xattr_handler *handler;
1431c03c5b1cSMartin Matuska struct dentry *d __maybe_unused = xf->dentry;
1432c03c5b1cSMartin Matuska enum xattr_permission perm = XAPERM_ALLOW;
1433c03c5b1cSMartin Matuska
1434c03c5b1cSMartin Matuska handler = zpl_xattr_handler(name);
1435c03c5b1cSMartin Matuska if (handler == NULL) {
1436c03c5b1cSMartin Matuska /* Do not expose FreeBSD system namespace xattrs. */
1437c03c5b1cSMartin Matuska if (ZFS_XA_NS_PREFIX_MATCH(FREEBSD, name))
1438c03c5b1cSMartin Matuska return (XAPERM_DENY);
1439c03c5b1cSMartin Matuska /*
1440c03c5b1cSMartin Matuska * Anything that doesn't match a known namespace gets put in the
1441c03c5b1cSMartin Matuska * user namespace for compatibility with other platforms.
1442c03c5b1cSMartin Matuska */
1443c03c5b1cSMartin Matuska perm = XAPERM_COMPAT;
1444c03c5b1cSMartin Matuska handler = &zpl_xattr_user_handler;
1445c03c5b1cSMartin Matuska }
1446c03c5b1cSMartin Matuska
1447c03c5b1cSMartin Matuska if (handler->list) {
1448c03c5b1cSMartin Matuska if (!handler->list(d))
1449c03c5b1cSMartin Matuska return (XAPERM_DENY);
1450c03c5b1cSMartin Matuska }
1451c03c5b1cSMartin Matuska
1452c03c5b1cSMartin Matuska return (perm);
1453c03c5b1cSMartin Matuska }
1454c03c5b1cSMartin Matuska
14557a7741afSMartin Matuska #ifdef CONFIG_FS_POSIX_ACL
14567a7741afSMartin Matuska
1457eda14cbcSMatt Macy struct acl_rel_struct {
1458eda14cbcSMatt Macy struct acl_rel_struct *next;
1459eda14cbcSMatt Macy struct posix_acl *acl;
1460eda14cbcSMatt Macy clock_t time;
1461eda14cbcSMatt Macy };
1462eda14cbcSMatt Macy
1463eda14cbcSMatt Macy #define ACL_REL_GRACE (60*HZ)
1464eda14cbcSMatt Macy #define ACL_REL_WINDOW (1*HZ)
1465eda14cbcSMatt Macy #define ACL_REL_SCHED (ACL_REL_GRACE+ACL_REL_WINDOW)
1466eda14cbcSMatt Macy
1467eda14cbcSMatt Macy /*
1468eda14cbcSMatt Macy * Lockless multi-producer single-consumer fifo list.
1469eda14cbcSMatt Macy * Nodes are added to tail and removed from head. Tail pointer is our
1470eda14cbcSMatt Macy * synchronization point. It always points to the next pointer of the last
1471eda14cbcSMatt Macy * node, or head if list is empty.
1472eda14cbcSMatt Macy */
1473eda14cbcSMatt Macy static struct acl_rel_struct *acl_rel_head = NULL;
1474eda14cbcSMatt Macy static struct acl_rel_struct **acl_rel_tail = &acl_rel_head;
1475eda14cbcSMatt Macy
1476eda14cbcSMatt Macy static void
zpl_posix_acl_free(void * arg)1477eda14cbcSMatt Macy zpl_posix_acl_free(void *arg)
1478eda14cbcSMatt Macy {
1479eda14cbcSMatt Macy struct acl_rel_struct *freelist = NULL;
1480eda14cbcSMatt Macy struct acl_rel_struct *a;
1481eda14cbcSMatt Macy clock_t new_time;
1482eda14cbcSMatt Macy boolean_t refire = B_FALSE;
1483eda14cbcSMatt Macy
1484eda14cbcSMatt Macy ASSERT3P(acl_rel_head, !=, NULL);
1485eda14cbcSMatt Macy while (acl_rel_head) {
1486eda14cbcSMatt Macy a = acl_rel_head;
1487eda14cbcSMatt Macy if (ddi_get_lbolt() - a->time >= ACL_REL_GRACE) {
1488eda14cbcSMatt Macy /*
1489eda14cbcSMatt Macy * If a is the last node we need to reset tail, but we
1490eda14cbcSMatt Macy * need to use cmpxchg to make sure it is still the
1491eda14cbcSMatt Macy * last node.
1492eda14cbcSMatt Macy */
1493eda14cbcSMatt Macy if (acl_rel_tail == &a->next) {
1494eda14cbcSMatt Macy acl_rel_head = NULL;
1495eda14cbcSMatt Macy if (cmpxchg(&acl_rel_tail, &a->next,
1496eda14cbcSMatt Macy &acl_rel_head) == &a->next) {
1497*d0abb9a6SMartin Matuska ASSERT0P(a->next);
1498eda14cbcSMatt Macy a->next = freelist;
1499eda14cbcSMatt Macy freelist = a;
1500eda14cbcSMatt Macy break;
1501eda14cbcSMatt Macy }
1502eda14cbcSMatt Macy }
1503eda14cbcSMatt Macy /*
1504eda14cbcSMatt Macy * a is not last node, make sure next pointer is set
1505eda14cbcSMatt Macy * by the adder and advance the head.
1506eda14cbcSMatt Macy */
1507eda14cbcSMatt Macy while (READ_ONCE(a->next) == NULL)
1508eda14cbcSMatt Macy cpu_relax();
1509eda14cbcSMatt Macy acl_rel_head = a->next;
1510eda14cbcSMatt Macy a->next = freelist;
1511eda14cbcSMatt Macy freelist = a;
1512eda14cbcSMatt Macy } else {
1513eda14cbcSMatt Macy /*
1514eda14cbcSMatt Macy * a is still in grace period. We are responsible to
1515eda14cbcSMatt Macy * reschedule the free task, since adder will only do
1516eda14cbcSMatt Macy * so if list is empty.
1517eda14cbcSMatt Macy */
1518eda14cbcSMatt Macy new_time = a->time + ACL_REL_SCHED;
1519eda14cbcSMatt Macy refire = B_TRUE;
1520eda14cbcSMatt Macy break;
1521eda14cbcSMatt Macy }
1522eda14cbcSMatt Macy }
1523eda14cbcSMatt Macy
1524eda14cbcSMatt Macy if (refire)
1525eda14cbcSMatt Macy taskq_dispatch_delay(system_delay_taskq, zpl_posix_acl_free,
1526eda14cbcSMatt Macy NULL, TQ_SLEEP, new_time);
1527eda14cbcSMatt Macy
1528eda14cbcSMatt Macy while (freelist) {
1529eda14cbcSMatt Macy a = freelist;
1530eda14cbcSMatt Macy freelist = a->next;
1531eda14cbcSMatt Macy kfree(a->acl);
1532eda14cbcSMatt Macy kmem_free(a, sizeof (struct acl_rel_struct));
1533eda14cbcSMatt Macy }
1534eda14cbcSMatt Macy }
1535eda14cbcSMatt Macy
1536eda14cbcSMatt Macy void
zpl_posix_acl_release_impl(struct posix_acl * acl)1537eda14cbcSMatt Macy zpl_posix_acl_release_impl(struct posix_acl *acl)
1538eda14cbcSMatt Macy {
1539eda14cbcSMatt Macy struct acl_rel_struct *a, **prev;
1540eda14cbcSMatt Macy
1541eda14cbcSMatt Macy a = kmem_alloc(sizeof (struct acl_rel_struct), KM_SLEEP);
1542eda14cbcSMatt Macy a->next = NULL;
1543eda14cbcSMatt Macy a->acl = acl;
1544eda14cbcSMatt Macy a->time = ddi_get_lbolt();
1545eda14cbcSMatt Macy /* atomically points tail to us and get the previous tail */
1546eda14cbcSMatt Macy prev = xchg(&acl_rel_tail, &a->next);
1547*d0abb9a6SMartin Matuska ASSERT0P(*prev);
1548eda14cbcSMatt Macy *prev = a;
1549eda14cbcSMatt Macy /* if it was empty before, schedule the free task */
1550eda14cbcSMatt Macy if (prev == &acl_rel_head)
1551eda14cbcSMatt Macy taskq_dispatch_delay(system_delay_taskq, zpl_posix_acl_free,
1552eda14cbcSMatt Macy NULL, TQ_SLEEP, ddi_get_lbolt() + ACL_REL_SCHED);
1553eda14cbcSMatt Macy }
1554eda14cbcSMatt Macy #endif
1555c03c5b1cSMartin Matuska
1556c03c5b1cSMartin Matuska ZFS_MODULE_PARAM(zfs, zfs_, xattr_compat, INT, ZMOD_RW,
1557c03c5b1cSMartin Matuska "Use legacy ZFS xattr naming for writing new user namespace xattrs");
1558