xref: /openbmc/linux/fs/nfs/nfs3acl.c (revision df561f66)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2b7fa0554SAndreas Gruenbacher #include <linux/fs.h>
35a0e3ad6STejun Heo #include <linux/gfp.h>
4b7fa0554SAndreas Gruenbacher #include <linux/nfs.h>
5b7fa0554SAndreas Gruenbacher #include <linux/nfs3.h>
6b7fa0554SAndreas Gruenbacher #include <linux/nfs_fs.h>
7334a13ecSChristoph Hellwig #include <linux/posix_acl_xattr.h>
8b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h>
9b7fa0554SAndreas Gruenbacher 
10f41f7418STrond Myklebust #include "internal.h"
113fc3edf1STrond Myklebust #include "nfs3_fs.h"
12f41f7418STrond Myklebust 
13b7fa0554SAndreas Gruenbacher #define NFSDBG_FACILITY	NFSDBG_PROC
14b7fa0554SAndreas Gruenbacher 
15b8a7a3a6SAndreas Gruenbacher /*
16b8a7a3a6SAndreas Gruenbacher  * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for
17b8a7a3a6SAndreas Gruenbacher  * caching get_acl results in a race-free way.  See fs/posix_acl.c:get_acl()
18b8a7a3a6SAndreas Gruenbacher  * for explanations.
19b8a7a3a6SAndreas Gruenbacher  */
20b8a7a3a6SAndreas Gruenbacher static void nfs3_prepare_get_acl(struct posix_acl **p)
21b8a7a3a6SAndreas Gruenbacher {
22b8a7a3a6SAndreas Gruenbacher 	struct posix_acl *sentinel = uncached_acl_sentinel(current);
23b8a7a3a6SAndreas Gruenbacher 
24b8a7a3a6SAndreas Gruenbacher 	if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) {
25b8a7a3a6SAndreas Gruenbacher 		/* Not the first reader or sentinel already in place. */
26b8a7a3a6SAndreas Gruenbacher 	}
27b8a7a3a6SAndreas Gruenbacher }
28b8a7a3a6SAndreas Gruenbacher 
29b8a7a3a6SAndreas Gruenbacher static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
30b8a7a3a6SAndreas Gruenbacher {
31b8a7a3a6SAndreas Gruenbacher 	struct posix_acl *sentinel = uncached_acl_sentinel(current);
32b8a7a3a6SAndreas Gruenbacher 
33b8a7a3a6SAndreas Gruenbacher 	/* Only cache the ACL if our sentinel is still in place. */
34b8a7a3a6SAndreas Gruenbacher 	posix_acl_dup(acl);
35b8a7a3a6SAndreas Gruenbacher 	if (cmpxchg(p, sentinel, acl) != sentinel)
36b8a7a3a6SAndreas Gruenbacher 		posix_acl_release(acl);
37b8a7a3a6SAndreas Gruenbacher }
38b8a7a3a6SAndreas Gruenbacher 
39b8a7a3a6SAndreas Gruenbacher static void nfs3_abort_get_acl(struct posix_acl **p)
40b8a7a3a6SAndreas Gruenbacher {
41b8a7a3a6SAndreas Gruenbacher 	struct posix_acl *sentinel = uncached_acl_sentinel(current);
42b8a7a3a6SAndreas Gruenbacher 
43b8a7a3a6SAndreas Gruenbacher 	/* Remove our sentinel upon failure. */
44b8a7a3a6SAndreas Gruenbacher 	cmpxchg(p, sentinel, ACL_NOT_CACHED);
45b8a7a3a6SAndreas Gruenbacher }
46b8a7a3a6SAndreas Gruenbacher 
47013cdf10SChristoph Hellwig struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
48b7fa0554SAndreas Gruenbacher {
49b7fa0554SAndreas Gruenbacher 	struct nfs_server *server = NFS_SERVER(inode);
50b7fa0554SAndreas Gruenbacher 	struct page *pages[NFSACL_MAXPAGES] = { };
51b7fa0554SAndreas Gruenbacher 	struct nfs3_getaclargs args = {
52b7fa0554SAndreas Gruenbacher 		.fh = NFS_FH(inode),
53b7fa0554SAndreas Gruenbacher 		/* The xdr layer may allocate pages here. */
54b7fa0554SAndreas Gruenbacher 		.pages = pages,
55b7fa0554SAndreas Gruenbacher 	};
56b7fa0554SAndreas Gruenbacher 	struct nfs3_getaclres res = {
5717280175STrond Myklebust 		NULL,
58b7fa0554SAndreas Gruenbacher 	};
59dead28daSChuck Lever 	struct rpc_message msg = {
60dead28daSChuck Lever 		.rpc_argp	= &args,
61dead28daSChuck Lever 		.rpc_resp	= &res,
62dead28daSChuck Lever 	};
63b7fa0554SAndreas Gruenbacher 	int status, count;
64b7fa0554SAndreas Gruenbacher 
65b7fa0554SAndreas Gruenbacher 	if (!nfs_server_capable(inode, NFS_CAP_ACLS))
66b7fa0554SAndreas Gruenbacher 		return ERR_PTR(-EOPNOTSUPP);
67b7fa0554SAndreas Gruenbacher 
685c6a9f7dSAndreas Gruenbacher 	status = nfs_revalidate_inode(server, inode);
695c6a9f7dSAndreas Gruenbacher 	if (status < 0)
705c6a9f7dSAndreas Gruenbacher 		return ERR_PTR(status);
71b7fa0554SAndreas Gruenbacher 
725c6a9f7dSAndreas Gruenbacher 	/*
735c6a9f7dSAndreas Gruenbacher 	 * Only get the access acl when explicitly requested: We don't
745c6a9f7dSAndreas Gruenbacher 	 * need it for access decisions, and only some applications use
755c6a9f7dSAndreas Gruenbacher 	 * it. Applications which request the access acl first are not
765c6a9f7dSAndreas Gruenbacher 	 * penalized from this optimization.
775c6a9f7dSAndreas Gruenbacher 	 */
785c6a9f7dSAndreas Gruenbacher 	if (type == ACL_TYPE_ACCESS)
795c6a9f7dSAndreas Gruenbacher 		args.mask |= NFS_ACLCNT|NFS_ACL;
805c6a9f7dSAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode))
815c6a9f7dSAndreas Gruenbacher 		args.mask |= NFS_DFACLCNT|NFS_DFACL;
825c6a9f7dSAndreas Gruenbacher 	if (args.mask == 0)
83b7fa0554SAndreas Gruenbacher 		return NULL;
84b7fa0554SAndreas Gruenbacher 
85b7fa0554SAndreas Gruenbacher 	dprintk("NFS call getacl\n");
86dead28daSChuck Lever 	msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
876e94d629STrond Myklebust 	res.fattr = nfs_alloc_fattr();
886e94d629STrond Myklebust 	if (res.fattr == NULL)
896e94d629STrond Myklebust 		return ERR_PTR(-ENOMEM);
906e94d629STrond Myklebust 
91b8a7a3a6SAndreas Gruenbacher 	if (args.mask & NFS_ACL)
92b8a7a3a6SAndreas Gruenbacher 		nfs3_prepare_get_acl(&inode->i_acl);
93b8a7a3a6SAndreas Gruenbacher 	if (args.mask & NFS_DFACL)
94b8a7a3a6SAndreas Gruenbacher 		nfs3_prepare_get_acl(&inode->i_default_acl);
95b8a7a3a6SAndreas Gruenbacher 
96dead28daSChuck Lever 	status = rpc_call_sync(server->client_acl, &msg, 0);
97b7fa0554SAndreas Gruenbacher 	dprintk("NFS reply getacl: %d\n", status);
98b7fa0554SAndreas Gruenbacher 
99b7fa0554SAndreas Gruenbacher 	/* pages may have been allocated at the xdr layer. */
100b7fa0554SAndreas Gruenbacher 	for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
101b7fa0554SAndreas Gruenbacher 		__free_page(args.pages[count]);
102b7fa0554SAndreas Gruenbacher 
103b7fa0554SAndreas Gruenbacher 	switch (status) {
104b7fa0554SAndreas Gruenbacher 		case 0:
1056e94d629STrond Myklebust 			status = nfs_refresh_inode(inode, res.fattr);
106b7fa0554SAndreas Gruenbacher 			break;
107b7fa0554SAndreas Gruenbacher 		case -EPFNOSUPPORT:
108b7fa0554SAndreas Gruenbacher 		case -EPROTONOSUPPORT:
109b7fa0554SAndreas Gruenbacher 			dprintk("NFS_V3_ACL extension not supported; disabling\n");
110b7fa0554SAndreas Gruenbacher 			server->caps &= ~NFS_CAP_ACLS;
111df561f66SGustavo A. R. Silva 			fallthrough;
112b7fa0554SAndreas Gruenbacher 		case -ENOTSUPP:
113b7fa0554SAndreas Gruenbacher 			status = -EOPNOTSUPP;
114b7fa0554SAndreas Gruenbacher 		default:
115b7fa0554SAndreas Gruenbacher 			goto getout;
116b7fa0554SAndreas Gruenbacher 	}
117b7fa0554SAndreas Gruenbacher 	if ((args.mask & res.mask) != args.mask) {
118b7fa0554SAndreas Gruenbacher 		status = -EIO;
119b7fa0554SAndreas Gruenbacher 		goto getout;
120b7fa0554SAndreas Gruenbacher 	}
121b7fa0554SAndreas Gruenbacher 
122b7fa0554SAndreas Gruenbacher 	if (res.acl_access != NULL) {
123718360c5SNoah Massey 		if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
124013cdf10SChristoph Hellwig 		    res.acl_access->a_count == 0) {
125b7fa0554SAndreas Gruenbacher 			posix_acl_release(res.acl_access);
126b7fa0554SAndreas Gruenbacher 			res.acl_access = NULL;
127b7fa0554SAndreas Gruenbacher 		}
128b7fa0554SAndreas Gruenbacher 	}
129b7fa0554SAndreas Gruenbacher 
130013cdf10SChristoph Hellwig 	if (res.mask & NFS_ACL)
131b8a7a3a6SAndreas Gruenbacher 		nfs3_complete_get_acl(&inode->i_acl, res.acl_access);
132013cdf10SChristoph Hellwig 	else
133013cdf10SChristoph Hellwig 		forget_cached_acl(inode, ACL_TYPE_ACCESS);
134b7fa0554SAndreas Gruenbacher 
135013cdf10SChristoph Hellwig 	if (res.mask & NFS_DFACL)
136b8a7a3a6SAndreas Gruenbacher 		nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default);
137013cdf10SChristoph Hellwig 	else
138013cdf10SChristoph Hellwig 		forget_cached_acl(inode, ACL_TYPE_DEFAULT);
139013cdf10SChristoph Hellwig 
140013cdf10SChristoph Hellwig 	nfs_free_fattr(res.fattr);
141013cdf10SChristoph Hellwig 	if (type == ACL_TYPE_ACCESS) {
142013cdf10SChristoph Hellwig 		posix_acl_release(res.acl_default);
143013cdf10SChristoph Hellwig 		return res.acl_access;
144013cdf10SChristoph Hellwig 	} else {
145013cdf10SChristoph Hellwig 		posix_acl_release(res.acl_access);
146013cdf10SChristoph Hellwig 		return res.acl_default;
147b7fa0554SAndreas Gruenbacher 	}
148b7fa0554SAndreas Gruenbacher 
149b7fa0554SAndreas Gruenbacher getout:
150b8a7a3a6SAndreas Gruenbacher 	nfs3_abort_get_acl(&inode->i_acl);
151b8a7a3a6SAndreas Gruenbacher 	nfs3_abort_get_acl(&inode->i_default_acl);
152b7fa0554SAndreas Gruenbacher 	posix_acl_release(res.acl_access);
153b7fa0554SAndreas Gruenbacher 	posix_acl_release(res.acl_default);
1546e94d629STrond Myklebust 	nfs_free_fattr(res.fattr);
155013cdf10SChristoph Hellwig 	return ERR_PTR(status);
156b7fa0554SAndreas Gruenbacher }
157b7fa0554SAndreas Gruenbacher 
1588f493b9cSTrond Myklebust static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
159b7fa0554SAndreas Gruenbacher 		struct posix_acl *dfacl)
160b7fa0554SAndreas Gruenbacher {
161b7fa0554SAndreas Gruenbacher 	struct nfs_server *server = NFS_SERVER(inode);
1626e94d629STrond Myklebust 	struct nfs_fattr *fattr;
163ae46141fSTrond Myklebust 	struct page *pages[NFSACL_MAXPAGES];
164b7fa0554SAndreas Gruenbacher 	struct nfs3_setaclargs args = {
165b7fa0554SAndreas Gruenbacher 		.inode = inode,
166b7fa0554SAndreas Gruenbacher 		.mask = NFS_ACL,
167b7fa0554SAndreas Gruenbacher 		.acl_access = acl,
168b7fa0554SAndreas Gruenbacher 		.pages = pages,
169b7fa0554SAndreas Gruenbacher 	};
170dead28daSChuck Lever 	struct rpc_message msg = {
171dead28daSChuck Lever 		.rpc_argp	= &args,
172dead28daSChuck Lever 		.rpc_resp	= &fattr,
173dead28daSChuck Lever 	};
174f87d928fSTrond Myklebust 	int status = 0;
175f87d928fSTrond Myklebust 
176f87d928fSTrond Myklebust 	if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL))
177f87d928fSTrond Myklebust 		goto out;
178b7fa0554SAndreas Gruenbacher 
179b7fa0554SAndreas Gruenbacher 	status = -EOPNOTSUPP;
180b7fa0554SAndreas Gruenbacher 	if (!nfs_server_capable(inode, NFS_CAP_ACLS))
181b7fa0554SAndreas Gruenbacher 		goto out;
182b7fa0554SAndreas Gruenbacher 
183f61f6da0SChuck Lever 	/* We are doing this here because XDR marshalling does not
184f61f6da0SChuck Lever 	 * return any results, it BUGs. */
185b7fa0554SAndreas Gruenbacher 	status = -ENOSPC;
186b7fa0554SAndreas Gruenbacher 	if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
187b7fa0554SAndreas Gruenbacher 		goto out;
188b7fa0554SAndreas Gruenbacher 	if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
189b7fa0554SAndreas Gruenbacher 		goto out;
190b7fa0554SAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode)) {
191b7fa0554SAndreas Gruenbacher 		args.mask |= NFS_DFACL;
192b7fa0554SAndreas Gruenbacher 		args.acl_default = dfacl;
193ae46141fSTrond Myklebust 		args.len = nfsacl_size(acl, dfacl);
194ae46141fSTrond Myklebust 	} else
195ae46141fSTrond Myklebust 		args.len = nfsacl_size(acl, NULL);
196ae46141fSTrond Myklebust 
197ae46141fSTrond Myklebust 	if (args.len > NFS_ACL_INLINE_BUFSIZE) {
198ae46141fSTrond Myklebust 		unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
199ae46141fSTrond Myklebust 
200ae46141fSTrond Myklebust 		status = -ENOMEM;
201ae46141fSTrond Myklebust 		do {
202ae46141fSTrond Myklebust 			args.pages[args.npages] = alloc_page(GFP_KERNEL);
203ae46141fSTrond Myklebust 			if (args.pages[args.npages] == NULL)
204ae46141fSTrond Myklebust 				goto out_freepages;
205ae46141fSTrond Myklebust 			args.npages++;
206ae46141fSTrond Myklebust 		} while (args.npages < npages);
207b7fa0554SAndreas Gruenbacher 	}
208b7fa0554SAndreas Gruenbacher 
209b7fa0554SAndreas Gruenbacher 	dprintk("NFS call setacl\n");
2106e94d629STrond Myklebust 	status = -ENOMEM;
2116e94d629STrond Myklebust 	fattr = nfs_alloc_fattr();
2126e94d629STrond Myklebust 	if (fattr == NULL)
2136e94d629STrond Myklebust 		goto out_freepages;
2146e94d629STrond Myklebust 
215dead28daSChuck Lever 	msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
2166e94d629STrond Myklebust 	msg.rpc_resp = fattr;
217dead28daSChuck Lever 	status = rpc_call_sync(server->client_acl, &msg, 0);
218f41f7418STrond Myklebust 	nfs_access_zap_cache(inode);
219f41f7418STrond Myklebust 	nfs_zap_acl_cache(inode);
220b7fa0554SAndreas Gruenbacher 	dprintk("NFS reply setacl: %d\n", status);
221b7fa0554SAndreas Gruenbacher 
222b7fa0554SAndreas Gruenbacher 	switch (status) {
223b7fa0554SAndreas Gruenbacher 		case 0:
2246e94d629STrond Myklebust 			status = nfs_refresh_inode(inode, fattr);
225b7fa0554SAndreas Gruenbacher 			break;
226b7fa0554SAndreas Gruenbacher 		case -EPFNOSUPPORT:
227b7fa0554SAndreas Gruenbacher 		case -EPROTONOSUPPORT:
228b7fa0554SAndreas Gruenbacher 			dprintk("NFS_V3_ACL SETACL RPC not supported"
229b7fa0554SAndreas Gruenbacher 					"(will not retry)\n");
230b7fa0554SAndreas Gruenbacher 			server->caps &= ~NFS_CAP_ACLS;
231df561f66SGustavo A. R. Silva 			fallthrough;
232b7fa0554SAndreas Gruenbacher 		case -ENOTSUPP:
233b7fa0554SAndreas Gruenbacher 			status = -EOPNOTSUPP;
234b7fa0554SAndreas Gruenbacher 	}
2356e94d629STrond Myklebust 	nfs_free_fattr(fattr);
236ae46141fSTrond Myklebust out_freepages:
237ae46141fSTrond Myklebust 	while (args.npages != 0) {
238ae46141fSTrond Myklebust 		args.npages--;
239ae46141fSTrond Myklebust 		__free_page(args.pages[args.npages]);
240ae46141fSTrond Myklebust 	}
241b7fa0554SAndreas Gruenbacher out:
242b7fa0554SAndreas Gruenbacher 	return status;
243b7fa0554SAndreas Gruenbacher }
244b7fa0554SAndreas Gruenbacher 
2458f493b9cSTrond Myklebust int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
2468f493b9cSTrond Myklebust 		struct posix_acl *dfacl)
2478f493b9cSTrond Myklebust {
2488f493b9cSTrond Myklebust 	int ret;
2498f493b9cSTrond Myklebust 	ret = __nfs3_proc_setacls(inode, acl, dfacl);
2508f493b9cSTrond Myklebust 	return (ret == -EOPNOTSUPP) ? 0 : ret;
2518f493b9cSTrond Myklebust 
2528f493b9cSTrond Myklebust }
2538f493b9cSTrond Myklebust 
254013cdf10SChristoph Hellwig int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
255b7fa0554SAndreas Gruenbacher {
2567648f939SAndreas Gruenbacher 	struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
257b7fa0554SAndreas Gruenbacher 	int status;
258b7fa0554SAndreas Gruenbacher 
259b7fa0554SAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode)) {
260b7fa0554SAndreas Gruenbacher 		switch(type) {
261b7fa0554SAndreas Gruenbacher 		case ACL_TYPE_ACCESS:
2627648f939SAndreas Gruenbacher 			alloc = get_acl(inode, ACL_TYPE_DEFAULT);
263b7fa0554SAndreas Gruenbacher 			if (IS_ERR(alloc))
264b7fa0554SAndreas Gruenbacher 				goto fail;
2657648f939SAndreas Gruenbacher 			dfacl = alloc;
266b7fa0554SAndreas Gruenbacher 			break;
267b7fa0554SAndreas Gruenbacher 
268b7fa0554SAndreas Gruenbacher 		case ACL_TYPE_DEFAULT:
2697648f939SAndreas Gruenbacher 			alloc = get_acl(inode, ACL_TYPE_ACCESS);
270b7fa0554SAndreas Gruenbacher 			if (IS_ERR(alloc))
271b7fa0554SAndreas Gruenbacher 				goto fail;
2727648f939SAndreas Gruenbacher 			dfacl = acl;
2737648f939SAndreas Gruenbacher 			acl = alloc;
274b7fa0554SAndreas Gruenbacher 			break;
275b7fa0554SAndreas Gruenbacher 		}
276013cdf10SChristoph Hellwig 	}
277b7fa0554SAndreas Gruenbacher 
278b7fa0554SAndreas Gruenbacher 	if (acl == NULL) {
2797648f939SAndreas Gruenbacher 		alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
280b7fa0554SAndreas Gruenbacher 		if (IS_ERR(alloc))
281b7fa0554SAndreas Gruenbacher 			goto fail;
2827648f939SAndreas Gruenbacher 		acl = alloc;
283b7fa0554SAndreas Gruenbacher 	}
2848f493b9cSTrond Myklebust 	status = __nfs3_proc_setacls(inode, acl, dfacl);
2857648f939SAndreas Gruenbacher out:
2867648f939SAndreas Gruenbacher 	if (acl != orig)
2877648f939SAndreas Gruenbacher 		posix_acl_release(acl);
2887648f939SAndreas Gruenbacher 	if (dfacl != orig)
2897648f939SAndreas Gruenbacher 		posix_acl_release(dfacl);
290b7fa0554SAndreas Gruenbacher 	return status;
291b7fa0554SAndreas Gruenbacher 
292b7fa0554SAndreas Gruenbacher fail:
2937648f939SAndreas Gruenbacher 	status = PTR_ERR(alloc);
2947648f939SAndreas Gruenbacher 	goto out;
295b7fa0554SAndreas Gruenbacher }
296055ffbeaSAndreas Gruenbacher 
297013cdf10SChristoph Hellwig const struct xattr_handler *nfs3_xattr_handlers[] = {
298013cdf10SChristoph Hellwig 	&posix_acl_access_xattr_handler,
299013cdf10SChristoph Hellwig 	&posix_acl_default_xattr_handler,
300013cdf10SChristoph Hellwig 	NULL,
301013cdf10SChristoph Hellwig };
30274adf83fSChristoph Hellwig 
30374adf83fSChristoph Hellwig static int
30474adf83fSChristoph Hellwig nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
30574adf83fSChristoph Hellwig 		size_t size, ssize_t *result)
30674adf83fSChristoph Hellwig {
30774adf83fSChristoph Hellwig 	struct posix_acl *acl;
30874adf83fSChristoph Hellwig 	char *p = data + *result;
30974adf83fSChristoph Hellwig 
31074adf83fSChristoph Hellwig 	acl = get_acl(inode, type);
3117a9e75a1SAndrey Utkin 	if (IS_ERR_OR_NULL(acl))
31274adf83fSChristoph Hellwig 		return 0;
31374adf83fSChristoph Hellwig 
31474adf83fSChristoph Hellwig 	posix_acl_release(acl);
31574adf83fSChristoph Hellwig 
31674adf83fSChristoph Hellwig 	*result += strlen(name);
31774adf83fSChristoph Hellwig 	*result += 1;
31874adf83fSChristoph Hellwig 	if (!size)
31974adf83fSChristoph Hellwig 		return 0;
32074adf83fSChristoph Hellwig 	if (*result > size)
32174adf83fSChristoph Hellwig 		return -ERANGE;
32274adf83fSChristoph Hellwig 
32374adf83fSChristoph Hellwig 	strcpy(p, name);
32474adf83fSChristoph Hellwig 	return 0;
32574adf83fSChristoph Hellwig }
32674adf83fSChristoph Hellwig 
32774adf83fSChristoph Hellwig ssize_t
32874adf83fSChristoph Hellwig nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
32974adf83fSChristoph Hellwig {
3302b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
33174adf83fSChristoph Hellwig 	ssize_t result = 0;
33274adf83fSChristoph Hellwig 	int error;
33374adf83fSChristoph Hellwig 
33474adf83fSChristoph Hellwig 	error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
33597d79299SAndreas Gruenbacher 			XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
33674adf83fSChristoph Hellwig 	if (error)
33774adf83fSChristoph Hellwig 		return error;
33874adf83fSChristoph Hellwig 
33974adf83fSChristoph Hellwig 	error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
34097d79299SAndreas Gruenbacher 			XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
34174adf83fSChristoph Hellwig 	if (error)
34274adf83fSChristoph Hellwig 		return error;
34374adf83fSChristoph Hellwig 	return result;
34474adf83fSChristoph Hellwig }
345