xref: /openbmc/linux/fs/nfs/nfs3acl.c (revision f9641a36)
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  */
nfs3_prepare_get_acl(struct posix_acl ** p)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 
24*f9641a36SUros Bizjak 	/* If the ACL isn't being read yet, set our sentinel. */
25*f9641a36SUros Bizjak 	cmpxchg(p, ACL_NOT_CACHED, sentinel);
26b8a7a3a6SAndreas Gruenbacher }
27b8a7a3a6SAndreas Gruenbacher 
nfs3_complete_get_acl(struct posix_acl ** p,struct posix_acl * acl)28b8a7a3a6SAndreas Gruenbacher static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
29b8a7a3a6SAndreas Gruenbacher {
30b8a7a3a6SAndreas Gruenbacher 	struct posix_acl *sentinel = uncached_acl_sentinel(current);
31b8a7a3a6SAndreas Gruenbacher 
32b8a7a3a6SAndreas Gruenbacher 	/* Only cache the ACL if our sentinel is still in place. */
33b8a7a3a6SAndreas Gruenbacher 	posix_acl_dup(acl);
34b8a7a3a6SAndreas Gruenbacher 	if (cmpxchg(p, sentinel, acl) != sentinel)
35b8a7a3a6SAndreas Gruenbacher 		posix_acl_release(acl);
36b8a7a3a6SAndreas Gruenbacher }
37b8a7a3a6SAndreas Gruenbacher 
nfs3_abort_get_acl(struct posix_acl ** p)38b8a7a3a6SAndreas Gruenbacher static void nfs3_abort_get_acl(struct posix_acl **p)
39b8a7a3a6SAndreas Gruenbacher {
40b8a7a3a6SAndreas Gruenbacher 	struct posix_acl *sentinel = uncached_acl_sentinel(current);
41b8a7a3a6SAndreas Gruenbacher 
42b8a7a3a6SAndreas Gruenbacher 	/* Remove our sentinel upon failure. */
43b8a7a3a6SAndreas Gruenbacher 	cmpxchg(p, sentinel, ACL_NOT_CACHED);
44b8a7a3a6SAndreas Gruenbacher }
45b8a7a3a6SAndreas Gruenbacher 
nfs3_get_acl(struct inode * inode,int type,bool rcu)460cad6246SMiklos Szeredi struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu)
47b7fa0554SAndreas Gruenbacher {
48b7fa0554SAndreas Gruenbacher 	struct nfs_server *server = NFS_SERVER(inode);
49b7fa0554SAndreas Gruenbacher 	struct page *pages[NFSACL_MAXPAGES] = { };
50b7fa0554SAndreas Gruenbacher 	struct nfs3_getaclargs args = {
51b7fa0554SAndreas Gruenbacher 		.fh = NFS_FH(inode),
52b7fa0554SAndreas Gruenbacher 		/* The xdr layer may allocate pages here. */
53b7fa0554SAndreas Gruenbacher 		.pages = pages,
54b7fa0554SAndreas Gruenbacher 	};
55b7fa0554SAndreas Gruenbacher 	struct nfs3_getaclres res = {
5617280175STrond Myklebust 		NULL,
57b7fa0554SAndreas Gruenbacher 	};
58dead28daSChuck Lever 	struct rpc_message msg = {
59dead28daSChuck Lever 		.rpc_argp	= &args,
60dead28daSChuck Lever 		.rpc_resp	= &res,
61dead28daSChuck Lever 	};
62b7fa0554SAndreas Gruenbacher 	int status, count;
63b7fa0554SAndreas Gruenbacher 
640cad6246SMiklos Szeredi 	if (rcu)
650cad6246SMiklos Szeredi 		return ERR_PTR(-ECHILD);
660cad6246SMiklos Szeredi 
67b7fa0554SAndreas Gruenbacher 	if (!nfs_server_capable(inode, NFS_CAP_ACLS))
68b7fa0554SAndreas Gruenbacher 		return ERR_PTR(-EOPNOTSUPP);
69b7fa0554SAndreas Gruenbacher 
701f3208b2STrond Myklebust 	status = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE);
715c6a9f7dSAndreas Gruenbacher 	if (status < 0)
725c6a9f7dSAndreas Gruenbacher 		return ERR_PTR(status);
73b7fa0554SAndreas Gruenbacher 
745c6a9f7dSAndreas Gruenbacher 	/*
755c6a9f7dSAndreas Gruenbacher 	 * Only get the access acl when explicitly requested: We don't
765c6a9f7dSAndreas Gruenbacher 	 * need it for access decisions, and only some applications use
775c6a9f7dSAndreas Gruenbacher 	 * it. Applications which request the access acl first are not
785c6a9f7dSAndreas Gruenbacher 	 * penalized from this optimization.
795c6a9f7dSAndreas Gruenbacher 	 */
805c6a9f7dSAndreas Gruenbacher 	if (type == ACL_TYPE_ACCESS)
815c6a9f7dSAndreas Gruenbacher 		args.mask |= NFS_ACLCNT|NFS_ACL;
825c6a9f7dSAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode))
835c6a9f7dSAndreas Gruenbacher 		args.mask |= NFS_DFACLCNT|NFS_DFACL;
845c6a9f7dSAndreas Gruenbacher 	if (args.mask == 0)
85b7fa0554SAndreas Gruenbacher 		return NULL;
86b7fa0554SAndreas Gruenbacher 
87b7fa0554SAndreas Gruenbacher 	dprintk("NFS call getacl\n");
88dead28daSChuck Lever 	msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
896e94d629STrond Myklebust 	res.fattr = nfs_alloc_fattr();
906e94d629STrond Myklebust 	if (res.fattr == NULL)
916e94d629STrond Myklebust 		return ERR_PTR(-ENOMEM);
926e94d629STrond Myklebust 
93b8a7a3a6SAndreas Gruenbacher 	if (args.mask & NFS_ACL)
94b8a7a3a6SAndreas Gruenbacher 		nfs3_prepare_get_acl(&inode->i_acl);
95b8a7a3a6SAndreas Gruenbacher 	if (args.mask & NFS_DFACL)
96b8a7a3a6SAndreas Gruenbacher 		nfs3_prepare_get_acl(&inode->i_default_acl);
97b8a7a3a6SAndreas Gruenbacher 
98dead28daSChuck Lever 	status = rpc_call_sync(server->client_acl, &msg, 0);
99b7fa0554SAndreas Gruenbacher 	dprintk("NFS reply getacl: %d\n", status);
100b7fa0554SAndreas Gruenbacher 
101b7fa0554SAndreas Gruenbacher 	/* pages may have been allocated at the xdr layer. */
102b7fa0554SAndreas Gruenbacher 	for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
103b7fa0554SAndreas Gruenbacher 		__free_page(args.pages[count]);
104b7fa0554SAndreas Gruenbacher 
105b7fa0554SAndreas Gruenbacher 	switch (status) {
106b7fa0554SAndreas Gruenbacher 		case 0:
1076e94d629STrond Myklebust 			status = nfs_refresh_inode(inode, res.fattr);
108b7fa0554SAndreas Gruenbacher 			break;
109b7fa0554SAndreas Gruenbacher 		case -EPFNOSUPPORT:
110b7fa0554SAndreas Gruenbacher 		case -EPROTONOSUPPORT:
111b7fa0554SAndreas Gruenbacher 			dprintk("NFS_V3_ACL extension not supported; disabling\n");
112b7fa0554SAndreas Gruenbacher 			server->caps &= ~NFS_CAP_ACLS;
113df561f66SGustavo A. R. Silva 			fallthrough;
114b7fa0554SAndreas Gruenbacher 		case -ENOTSUPP:
115b7fa0554SAndreas Gruenbacher 			status = -EOPNOTSUPP;
116ffb81717SGustavo A. R. Silva 			goto getout;
117b7fa0554SAndreas Gruenbacher 		default:
118b7fa0554SAndreas Gruenbacher 			goto getout;
119b7fa0554SAndreas Gruenbacher 	}
120b7fa0554SAndreas Gruenbacher 	if ((args.mask & res.mask) != args.mask) {
121b7fa0554SAndreas Gruenbacher 		status = -EIO;
122b7fa0554SAndreas Gruenbacher 		goto getout;
123b7fa0554SAndreas Gruenbacher 	}
124b7fa0554SAndreas Gruenbacher 
125b7fa0554SAndreas Gruenbacher 	if (res.acl_access != NULL) {
126718360c5SNoah Massey 		if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
127013cdf10SChristoph Hellwig 		    res.acl_access->a_count == 0) {
128b7fa0554SAndreas Gruenbacher 			posix_acl_release(res.acl_access);
129b7fa0554SAndreas Gruenbacher 			res.acl_access = NULL;
130b7fa0554SAndreas Gruenbacher 		}
131b7fa0554SAndreas Gruenbacher 	}
132b7fa0554SAndreas Gruenbacher 
133013cdf10SChristoph Hellwig 	if (res.mask & NFS_ACL)
134b8a7a3a6SAndreas Gruenbacher 		nfs3_complete_get_acl(&inode->i_acl, res.acl_access);
135013cdf10SChristoph Hellwig 	else
136013cdf10SChristoph Hellwig 		forget_cached_acl(inode, ACL_TYPE_ACCESS);
137b7fa0554SAndreas Gruenbacher 
138013cdf10SChristoph Hellwig 	if (res.mask & NFS_DFACL)
139b8a7a3a6SAndreas Gruenbacher 		nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default);
140013cdf10SChristoph Hellwig 	else
141013cdf10SChristoph Hellwig 		forget_cached_acl(inode, ACL_TYPE_DEFAULT);
142013cdf10SChristoph Hellwig 
143013cdf10SChristoph Hellwig 	nfs_free_fattr(res.fattr);
144013cdf10SChristoph Hellwig 	if (type == ACL_TYPE_ACCESS) {
145013cdf10SChristoph Hellwig 		posix_acl_release(res.acl_default);
146013cdf10SChristoph Hellwig 		return res.acl_access;
147013cdf10SChristoph Hellwig 	} else {
148013cdf10SChristoph Hellwig 		posix_acl_release(res.acl_access);
149013cdf10SChristoph Hellwig 		return res.acl_default;
150b7fa0554SAndreas Gruenbacher 	}
151b7fa0554SAndreas Gruenbacher 
152b7fa0554SAndreas Gruenbacher getout:
153b8a7a3a6SAndreas Gruenbacher 	nfs3_abort_get_acl(&inode->i_acl);
154b8a7a3a6SAndreas Gruenbacher 	nfs3_abort_get_acl(&inode->i_default_acl);
155b7fa0554SAndreas Gruenbacher 	posix_acl_release(res.acl_access);
156b7fa0554SAndreas Gruenbacher 	posix_acl_release(res.acl_default);
1576e94d629STrond Myklebust 	nfs_free_fattr(res.fattr);
158013cdf10SChristoph Hellwig 	return ERR_PTR(status);
159b7fa0554SAndreas Gruenbacher }
160b7fa0554SAndreas Gruenbacher 
__nfs3_proc_setacls(struct inode * inode,struct posix_acl * acl,struct posix_acl * dfacl)1618f493b9cSTrond Myklebust static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
162b7fa0554SAndreas Gruenbacher 		struct posix_acl *dfacl)
163b7fa0554SAndreas Gruenbacher {
164b7fa0554SAndreas Gruenbacher 	struct nfs_server *server = NFS_SERVER(inode);
1656e94d629STrond Myklebust 	struct nfs_fattr *fattr;
166ae46141fSTrond Myklebust 	struct page *pages[NFSACL_MAXPAGES];
167b7fa0554SAndreas Gruenbacher 	struct nfs3_setaclargs args = {
168b7fa0554SAndreas Gruenbacher 		.inode = inode,
169b7fa0554SAndreas Gruenbacher 		.mask = NFS_ACL,
170b7fa0554SAndreas Gruenbacher 		.acl_access = acl,
171b7fa0554SAndreas Gruenbacher 		.pages = pages,
172b7fa0554SAndreas Gruenbacher 	};
173dead28daSChuck Lever 	struct rpc_message msg = {
174dead28daSChuck Lever 		.rpc_argp	= &args,
175dead28daSChuck Lever 		.rpc_resp	= &fattr,
176dead28daSChuck Lever 	};
177f87d928fSTrond Myklebust 	int status = 0;
178f87d928fSTrond Myklebust 
179f87d928fSTrond Myklebust 	if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL))
180f87d928fSTrond Myklebust 		goto out;
181b7fa0554SAndreas Gruenbacher 
182b7fa0554SAndreas Gruenbacher 	status = -EOPNOTSUPP;
183b7fa0554SAndreas Gruenbacher 	if (!nfs_server_capable(inode, NFS_CAP_ACLS))
184b7fa0554SAndreas Gruenbacher 		goto out;
185b7fa0554SAndreas Gruenbacher 
186f61f6da0SChuck Lever 	/* We are doing this here because XDR marshalling does not
187f61f6da0SChuck Lever 	 * return any results, it BUGs. */
188b7fa0554SAndreas Gruenbacher 	status = -ENOSPC;
189b7fa0554SAndreas Gruenbacher 	if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
190b7fa0554SAndreas Gruenbacher 		goto out;
191b7fa0554SAndreas Gruenbacher 	if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
192b7fa0554SAndreas Gruenbacher 		goto out;
193b7fa0554SAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode)) {
194b7fa0554SAndreas Gruenbacher 		args.mask |= NFS_DFACL;
195b7fa0554SAndreas Gruenbacher 		args.acl_default = dfacl;
196ae46141fSTrond Myklebust 		args.len = nfsacl_size(acl, dfacl);
197ae46141fSTrond Myklebust 	} else
198ae46141fSTrond Myklebust 		args.len = nfsacl_size(acl, NULL);
199ae46141fSTrond Myklebust 
200ae46141fSTrond Myklebust 	if (args.len > NFS_ACL_INLINE_BUFSIZE) {
201ae46141fSTrond Myklebust 		unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
202ae46141fSTrond Myklebust 
203ae46141fSTrond Myklebust 		status = -ENOMEM;
204ae46141fSTrond Myklebust 		do {
205ae46141fSTrond Myklebust 			args.pages[args.npages] = alloc_page(GFP_KERNEL);
206ae46141fSTrond Myklebust 			if (args.pages[args.npages] == NULL)
207ae46141fSTrond Myklebust 				goto out_freepages;
208ae46141fSTrond Myklebust 			args.npages++;
209ae46141fSTrond Myklebust 		} while (args.npages < npages);
210b7fa0554SAndreas Gruenbacher 	}
211b7fa0554SAndreas Gruenbacher 
212b7fa0554SAndreas Gruenbacher 	dprintk("NFS call setacl\n");
2136e94d629STrond Myklebust 	status = -ENOMEM;
2146e94d629STrond Myklebust 	fattr = nfs_alloc_fattr();
2156e94d629STrond Myklebust 	if (fattr == NULL)
2166e94d629STrond Myklebust 		goto out_freepages;
2176e94d629STrond Myklebust 
218dead28daSChuck Lever 	msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
2196e94d629STrond Myklebust 	msg.rpc_resp = fattr;
220dead28daSChuck Lever 	status = rpc_call_sync(server->client_acl, &msg, 0);
221f41f7418STrond Myklebust 	nfs_access_zap_cache(inode);
222f41f7418STrond Myklebust 	nfs_zap_acl_cache(inode);
223b7fa0554SAndreas Gruenbacher 	dprintk("NFS reply setacl: %d\n", status);
224b7fa0554SAndreas Gruenbacher 
225b7fa0554SAndreas Gruenbacher 	switch (status) {
226b7fa0554SAndreas Gruenbacher 		case 0:
2276e94d629STrond Myklebust 			status = nfs_refresh_inode(inode, fattr);
228b7fa0554SAndreas Gruenbacher 			break;
229b7fa0554SAndreas Gruenbacher 		case -EPFNOSUPPORT:
230b7fa0554SAndreas Gruenbacher 		case -EPROTONOSUPPORT:
231b7fa0554SAndreas Gruenbacher 			dprintk("NFS_V3_ACL SETACL RPC not supported"
232b7fa0554SAndreas Gruenbacher 					"(will not retry)\n");
233b7fa0554SAndreas Gruenbacher 			server->caps &= ~NFS_CAP_ACLS;
234df561f66SGustavo A. R. Silva 			fallthrough;
235b7fa0554SAndreas Gruenbacher 		case -ENOTSUPP:
236b7fa0554SAndreas Gruenbacher 			status = -EOPNOTSUPP;
237b7fa0554SAndreas Gruenbacher 	}
2386e94d629STrond Myklebust 	nfs_free_fattr(fattr);
239ae46141fSTrond Myklebust out_freepages:
240ae46141fSTrond Myklebust 	while (args.npages != 0) {
241ae46141fSTrond Myklebust 		args.npages--;
242ae46141fSTrond Myklebust 		__free_page(args.pages[args.npages]);
243ae46141fSTrond Myklebust 	}
244b7fa0554SAndreas Gruenbacher out:
245b7fa0554SAndreas Gruenbacher 	return status;
246b7fa0554SAndreas Gruenbacher }
247b7fa0554SAndreas Gruenbacher 
nfs3_proc_setacls(struct inode * inode,struct posix_acl * acl,struct posix_acl * dfacl)2488f493b9cSTrond Myklebust int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
2498f493b9cSTrond Myklebust 		struct posix_acl *dfacl)
2508f493b9cSTrond Myklebust {
2518f493b9cSTrond Myklebust 	int ret;
2528f493b9cSTrond Myklebust 	ret = __nfs3_proc_setacls(inode, acl, dfacl);
2538f493b9cSTrond Myklebust 	return (ret == -EOPNOTSUPP) ? 0 : ret;
2548f493b9cSTrond Myklebust 
2558f493b9cSTrond Myklebust }
2568f493b9cSTrond Myklebust 
nfs3_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,struct posix_acl * acl,int type)25713e83a49SChristian Brauner int nfs3_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
258549c7297SChristian Brauner 		 struct posix_acl *acl, int type)
259b7fa0554SAndreas Gruenbacher {
2607648f939SAndreas Gruenbacher 	struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
261138060baSChristian Brauner 	struct inode *inode = d_inode(dentry);
262b7fa0554SAndreas Gruenbacher 	int status;
263b7fa0554SAndreas Gruenbacher 
264b7fa0554SAndreas Gruenbacher 	if (S_ISDIR(inode->i_mode)) {
265b7fa0554SAndreas Gruenbacher 		switch(type) {
266b7fa0554SAndreas Gruenbacher 		case ACL_TYPE_ACCESS:
267cac2f8b8SChristian Brauner 			alloc = get_inode_acl(inode, ACL_TYPE_DEFAULT);
268b7fa0554SAndreas Gruenbacher 			if (IS_ERR(alloc))
269b7fa0554SAndreas Gruenbacher 				goto fail;
2707648f939SAndreas Gruenbacher 			dfacl = alloc;
271b7fa0554SAndreas Gruenbacher 			break;
272b7fa0554SAndreas Gruenbacher 
273b7fa0554SAndreas Gruenbacher 		case ACL_TYPE_DEFAULT:
274cac2f8b8SChristian Brauner 			alloc = get_inode_acl(inode, ACL_TYPE_ACCESS);
275b7fa0554SAndreas Gruenbacher 			if (IS_ERR(alloc))
276b7fa0554SAndreas Gruenbacher 				goto fail;
2777648f939SAndreas Gruenbacher 			dfacl = acl;
2787648f939SAndreas Gruenbacher 			acl = alloc;
279b7fa0554SAndreas Gruenbacher 			break;
280b7fa0554SAndreas Gruenbacher 		}
281013cdf10SChristoph Hellwig 	}
282b7fa0554SAndreas Gruenbacher 
283b7fa0554SAndreas Gruenbacher 	if (acl == NULL) {
2847648f939SAndreas Gruenbacher 		alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
285b7fa0554SAndreas Gruenbacher 		if (IS_ERR(alloc))
286b7fa0554SAndreas Gruenbacher 			goto fail;
2877648f939SAndreas Gruenbacher 		acl = alloc;
288b7fa0554SAndreas Gruenbacher 	}
2898f493b9cSTrond Myklebust 	status = __nfs3_proc_setacls(inode, acl, dfacl);
2907648f939SAndreas Gruenbacher out:
2917648f939SAndreas Gruenbacher 	if (acl != orig)
2927648f939SAndreas Gruenbacher 		posix_acl_release(acl);
2937648f939SAndreas Gruenbacher 	if (dfacl != orig)
2947648f939SAndreas Gruenbacher 		posix_acl_release(dfacl);
295b7fa0554SAndreas Gruenbacher 	return status;
296b7fa0554SAndreas Gruenbacher 
297b7fa0554SAndreas Gruenbacher fail:
2987648f939SAndreas Gruenbacher 	status = PTR_ERR(alloc);
2997648f939SAndreas Gruenbacher 	goto out;
300b7fa0554SAndreas Gruenbacher }
301055ffbeaSAndreas Gruenbacher 
302013cdf10SChristoph Hellwig static int
nfs3_list_one_acl(struct inode * inode,int type,const char * name,void * data,size_t size,ssize_t * result)303013cdf10SChristoph Hellwig nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
304013cdf10SChristoph Hellwig 		size_t size, ssize_t *result)
305013cdf10SChristoph Hellwig {
306013cdf10SChristoph Hellwig 	struct posix_acl *acl;
30774adf83fSChristoph Hellwig 	char *p = data + *result;
30874adf83fSChristoph Hellwig 
30974adf83fSChristoph Hellwig 	acl = get_inode_acl(inode, type);
31074adf83fSChristoph Hellwig 	if (IS_ERR_OR_NULL(acl))
31174adf83fSChristoph Hellwig 		return 0;
31274adf83fSChristoph Hellwig 
31374adf83fSChristoph Hellwig 	posix_acl_release(acl);
31474adf83fSChristoph Hellwig 
315cac2f8b8SChristian Brauner 	*result += strlen(name);
3167a9e75a1SAndrey Utkin 	*result += 1;
31774adf83fSChristoph Hellwig 	if (!size)
31874adf83fSChristoph Hellwig 		return 0;
31974adf83fSChristoph Hellwig 	if (*result > size)
32074adf83fSChristoph Hellwig 		return -ERANGE;
32174adf83fSChristoph Hellwig 
32274adf83fSChristoph Hellwig 	strcpy(p, name);
32374adf83fSChristoph Hellwig 	return 0;
32474adf83fSChristoph Hellwig }
32574adf83fSChristoph Hellwig 
32674adf83fSChristoph Hellwig ssize_t
nfs3_listxattr(struct dentry * dentry,char * data,size_t size)32774adf83fSChristoph Hellwig nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
32874adf83fSChristoph Hellwig {
32974adf83fSChristoph Hellwig 	struct inode *inode = d_inode(dentry);
33074adf83fSChristoph Hellwig 	ssize_t result = 0;
33174adf83fSChristoph Hellwig 	int error;
33274adf83fSChristoph Hellwig 
33374adf83fSChristoph Hellwig 	error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
33474adf83fSChristoph Hellwig 			XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
3352b0143b5SDavid Howells 	if (error)
33674adf83fSChristoph Hellwig 		return error;
33774adf83fSChristoph Hellwig 
33874adf83fSChristoph Hellwig 	error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
33974adf83fSChristoph Hellwig 			XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
34097d79299SAndreas Gruenbacher 	if (error)
34174adf83fSChristoph Hellwig 		return error;
34274adf83fSChristoph Hellwig 	return result;
34374adf83fSChristoph Hellwig }
34474adf83fSChristoph Hellwig