Branch data Line data Source code
1 : : #include <linux/fs.h>
2 : : #include <linux/gfp.h>
3 : : #include <linux/nfs.h>
4 : : #include <linux/nfs3.h>
5 : : #include <linux/nfs_fs.h>
6 : : #include <linux/posix_acl_xattr.h>
7 : : #include <linux/nfsacl.h>
8 : :
9 : : #include "internal.h"
10 : :
11 : : #define NFSDBG_FACILITY NFSDBG_PROC
12 : :
13 : 0 : struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
14 : : {
15 : : struct nfs_server *server = NFS_SERVER(inode);
16 : 0 : struct page *pages[NFSACL_MAXPAGES] = { };
17 : 0 : struct nfs3_getaclargs args = {
18 : 0 : .fh = NFS_FH(inode),
19 : : /* The xdr layer may allocate pages here. */
20 : : .pages = pages,
21 : : };
22 : 0 : struct nfs3_getaclres res = {
23 : : NULL,
24 : : };
25 : 0 : struct rpc_message msg = {
26 : : .rpc_argp = &args,
27 : : .rpc_resp = &res,
28 : : };
29 : : int status, count;
30 : :
31 [ # # ]: 0 : if (!nfs_server_capable(inode, NFS_CAP_ACLS))
32 : : return ERR_PTR(-EOPNOTSUPP);
33 : :
34 : 0 : status = nfs_revalidate_inode(server, inode);
35 [ # # ]: 0 : if (status < 0)
36 : 0 : return ERR_PTR(status);
37 : :
38 : : /*
39 : : * Only get the access acl when explicitly requested: We don't
40 : : * need it for access decisions, and only some applications use
41 : : * it. Applications which request the access acl first are not
42 : : * penalized from this optimization.
43 : : */
44 [ # # ]: 0 : if (type == ACL_TYPE_ACCESS)
45 : 0 : args.mask |= NFS_ACLCNT|NFS_ACL;
46 [ # # ]: 0 : if (S_ISDIR(inode->i_mode))
47 : 0 : args.mask |= NFS_DFACLCNT|NFS_DFACL;
48 [ # # ]: 0 : if (args.mask == 0)
49 : : return NULL;
50 : :
51 : : dprintk("NFS call getacl\n");
52 : 0 : msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
53 : 0 : res.fattr = nfs_alloc_fattr();
54 [ # # ]: 0 : if (res.fattr == NULL)
55 : : return ERR_PTR(-ENOMEM);
56 : :
57 : 0 : status = rpc_call_sync(server->client_acl, &msg, 0);
58 : : dprintk("NFS reply getacl: %d\n", status);
59 : :
60 : : /* pages may have been allocated at the xdr layer. */
61 [ # # ][ # # ]: 0 : for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
62 : 0 : __free_page(args.pages[count]);
63 : :
64 [ # # # # ]: 0 : switch (status) {
65 : : case 0:
66 : 0 : status = nfs_refresh_inode(inode, res.fattr);
67 : : break;
68 : : case -EPFNOSUPPORT:
69 : : case -EPROTONOSUPPORT:
70 : : dprintk("NFS_V3_ACL extension not supported; disabling\n");
71 : 0 : server->caps &= ~NFS_CAP_ACLS;
72 : : case -ENOTSUPP:
73 : : status = -EOPNOTSUPP;
74 : : default:
75 : : goto getout;
76 : : }
77 [ # # ]: 0 : if ((args.mask & res.mask) != args.mask) {
78 : : status = -EIO;
79 : : goto getout;
80 : : }
81 : :
82 [ # # ]: 0 : if (res.acl_access != NULL) {
83 [ # # ][ # # ]: 0 : if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
84 : 0 : res.acl_access->a_count == 0) {
85 : 0 : posix_acl_release(res.acl_access);
86 : 0 : res.acl_access = NULL;
87 : : }
88 : : }
89 : :
90 [ # # ]: 0 : if (res.mask & NFS_ACL)
91 : 0 : set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access);
92 : : else
93 : 0 : forget_cached_acl(inode, ACL_TYPE_ACCESS);
94 : :
95 [ # # ]: 0 : if (res.mask & NFS_DFACL)
96 : 0 : set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default);
97 : : else
98 : 0 : forget_cached_acl(inode, ACL_TYPE_DEFAULT);
99 : :
100 : 0 : nfs_free_fattr(res.fattr);
101 [ # # ]: 0 : if (type == ACL_TYPE_ACCESS) {
102 : 0 : posix_acl_release(res.acl_default);
103 : 0 : return res.acl_access;
104 : : } else {
105 : 0 : posix_acl_release(res.acl_access);
106 : 0 : return res.acl_default;
107 : : }
108 : :
109 : : getout:
110 : 0 : posix_acl_release(res.acl_access);
111 : 0 : posix_acl_release(res.acl_default);
112 : 0 : nfs_free_fattr(res.fattr);
113 : 0 : return ERR_PTR(status);
114 : : }
115 : :
116 : 0 : static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
117 : : struct posix_acl *dfacl)
118 : : {
119 : : struct nfs_server *server = NFS_SERVER(inode);
120 : : struct nfs_fattr *fattr;
121 : : struct page *pages[NFSACL_MAXPAGES];
122 : 0 : struct nfs3_setaclargs args = {
123 : : .inode = inode,
124 : : .mask = NFS_ACL,
125 : : .acl_access = acl,
126 : : .pages = pages,
127 : : };
128 : 0 : struct rpc_message msg = {
129 : : .rpc_argp = &args,
130 : : .rpc_resp = &fattr,
131 : : };
132 : : int status;
133 : :
134 : : status = -EOPNOTSUPP;
135 [ # # ]: 0 : if (!nfs_server_capable(inode, NFS_CAP_ACLS))
136 : : goto out;
137 : :
138 : : /* We are doing this here because XDR marshalling does not
139 : : * return any results, it BUGs. */
140 : : status = -ENOSPC;
141 [ # # ][ # # ]: 0 : if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
142 : : goto out;
143 [ # # ][ # # ]: 0 : if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
144 : : goto out;
145 [ # # ]: 0 : if (S_ISDIR(inode->i_mode)) {
146 : 0 : args.mask |= NFS_DFACL;
147 : 0 : args.acl_default = dfacl;
148 : 0 : args.len = nfsacl_size(acl, dfacl);
149 : : } else
150 : 0 : args.len = nfsacl_size(acl, NULL);
151 : :
152 [ # # ]: 0 : if (args.len > NFS_ACL_INLINE_BUFSIZE) {
153 : 0 : unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
154 : :
155 : : status = -ENOMEM;
156 : : do {
157 : 0 : args.pages[args.npages] = alloc_page(GFP_KERNEL);
158 [ # # ]: 0 : if (args.pages[args.npages] == NULL)
159 : : goto out_freepages;
160 : 0 : args.npages++;
161 [ # # ]: 0 : } while (args.npages < npages);
162 : : }
163 : :
164 : : dprintk("NFS call setacl\n");
165 : : status = -ENOMEM;
166 : 0 : fattr = nfs_alloc_fattr();
167 [ # # ]: 0 : if (fattr == NULL)
168 : : goto out_freepages;
169 : :
170 : 0 : msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
171 : 0 : msg.rpc_resp = fattr;
172 : 0 : status = rpc_call_sync(server->client_acl, &msg, 0);
173 : 0 : nfs_access_zap_cache(inode);
174 : 0 : nfs_zap_acl_cache(inode);
175 : : dprintk("NFS reply setacl: %d\n", status);
176 : :
177 [ # # # # ]: 0 : switch (status) {
178 : : case 0:
179 : 0 : status = nfs_refresh_inode(inode, fattr);
180 : 0 : set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
181 : 0 : set_cached_acl(inode, ACL_TYPE_DEFAULT, dfacl);
182 : 0 : break;
183 : : case -EPFNOSUPPORT:
184 : : case -EPROTONOSUPPORT:
185 : : dprintk("NFS_V3_ACL SETACL RPC not supported"
186 : : "(will not retry)\n");
187 : 0 : server->caps &= ~NFS_CAP_ACLS;
188 : : case -ENOTSUPP:
189 : : status = -EOPNOTSUPP;
190 : : }
191 : 0 : nfs_free_fattr(fattr);
192 : : out_freepages:
193 [ # # ]: 0 : while (args.npages != 0) {
194 : 0 : args.npages--;
195 : 0 : __free_page(args.pages[args.npages]);
196 : : }
197 : : out:
198 : 0 : return status;
199 : : }
200 : :
201 : 0 : int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
202 : : struct posix_acl *dfacl)
203 : : {
204 : : int ret;
205 : 0 : ret = __nfs3_proc_setacls(inode, acl, dfacl);
206 [ # # ]: 0 : return (ret == -EOPNOTSUPP) ? 0 : ret;
207 : :
208 : : }
209 : :
210 : 0 : int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
211 : : {
212 : : struct posix_acl *alloc = NULL, *dfacl = NULL;
213 : : int status;
214 : :
215 [ # # ]: 0 : if (S_ISDIR(inode->i_mode)) {
216 [ # # # ]: 0 : switch(type) {
217 : : case ACL_TYPE_ACCESS:
218 : 0 : alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
219 [ # # ]: 0 : if (IS_ERR(alloc))
220 : : goto fail;
221 : : break;
222 : :
223 : : case ACL_TYPE_DEFAULT:
224 : : dfacl = acl;
225 : 0 : alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
226 [ # # ]: 0 : if (IS_ERR(alloc))
227 : : goto fail;
228 : : break;
229 : : }
230 : : }
231 : :
232 [ # # ]: 0 : if (acl == NULL) {
233 : 0 : alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
234 [ # # ]: 0 : if (IS_ERR(alloc))
235 : : goto fail;
236 : : }
237 : 0 : status = __nfs3_proc_setacls(inode, acl, dfacl);
238 : : posix_acl_release(alloc);
239 : 0 : return status;
240 : :
241 : : fail:
242 : 0 : return PTR_ERR(alloc);
243 : : }
244 : :
245 : : const struct xattr_handler *nfs3_xattr_handlers[] = {
246 : : &posix_acl_access_xattr_handler,
247 : : &posix_acl_default_xattr_handler,
248 : : NULL,
249 : : };
|