Blame view
fs/nfs/nfs3acl.c
7.95 KB
b7fa0554c [PATCH] NFS: Add ... |
1 |
#include <linux/fs.h> |
5a0e3ad6a include cleanup: ... |
2 |
#include <linux/gfp.h> |
b7fa0554c [PATCH] NFS: Add ... |
3 4 5 |
#include <linux/nfs.h> #include <linux/nfs3.h> #include <linux/nfs_fs.h> |
334a13ec3 [PATCH] really re... |
6 |
#include <linux/posix_acl_xattr.h> |
b7fa0554c [PATCH] NFS: Add ... |
7 |
#include <linux/nfsacl.h> |
f41f74183 NFS: Ensure we za... |
8 |
#include "internal.h" |
3fc3edf14 NFSv3: Fix missin... |
9 |
#include "nfs3_fs.h" |
f41f74183 NFS: Ensure we za... |
10 |
|
b7fa0554c [PATCH] NFS: Add ... |
11 |
#define NFSDBG_FACILITY NFSDBG_PROC |
b8a7a3a66 posix_acl: Inode ... |
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for * caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl() * for explanations. */ static void nfs3_prepare_get_acl(struct posix_acl **p) { struct posix_acl *sentinel = uncached_acl_sentinel(current); if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) { /* Not the first reader or sentinel already in place. */ } } static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl) { struct posix_acl *sentinel = uncached_acl_sentinel(current); /* Only cache the ACL if our sentinel is still in place. */ posix_acl_dup(acl); if (cmpxchg(p, sentinel, acl) != sentinel) posix_acl_release(acl); } static void nfs3_abort_get_acl(struct posix_acl **p) { struct posix_acl *sentinel = uncached_acl_sentinel(current); /* Remove our sentinel upon failure. */ cmpxchg(p, sentinel, ACL_NOT_CACHED); } |
013cdf108 nfs: use generic ... |
43 |
struct posix_acl *nfs3_get_acl(struct inode *inode, int type) |
b7fa0554c [PATCH] NFS: Add ... |
44 45 |
{ struct nfs_server *server = NFS_SERVER(inode); |
b7fa0554c [PATCH] NFS: Add ... |
46 47 48 49 50 51 52 |
struct page *pages[NFSACL_MAXPAGES] = { }; struct nfs3_getaclargs args = { .fh = NFS_FH(inode), /* The xdr layer may allocate pages here. */ .pages = pages, }; struct nfs3_getaclres res = { |
17280175c NFS: Fix a number... |
53 |
NULL, |
b7fa0554c [PATCH] NFS: Add ... |
54 |
}; |
dead28da8 SUNRPC: eliminate... |
55 56 57 58 |
struct rpc_message msg = { .rpc_argp = &args, .rpc_resp = &res, }; |
b7fa0554c [PATCH] NFS: Add ... |
59 60 61 62 |
int status, count; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) return ERR_PTR(-EOPNOTSUPP); |
5c6a9f7d9 [PATCH] NFS: Cach... |
63 64 65 |
status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); |
b7fa0554c [PATCH] NFS: Add ... |
66 |
|
5c6a9f7d9 [PATCH] NFS: Cach... |
67 68 69 70 71 72 73 74 75 76 77 78 |
/* * Only get the access acl when explicitly requested: We don't * need it for access decisions, and only some applications use * it. Applications which request the access acl first are not * penalized from this optimization. */ if (type == ACL_TYPE_ACCESS) args.mask |= NFS_ACLCNT|NFS_ACL; if (S_ISDIR(inode->i_mode)) args.mask |= NFS_DFACLCNT|NFS_DFACL; if (args.mask == 0) return NULL; |
b7fa0554c [PATCH] NFS: Add ... |
79 80 81 |
dprintk("NFS call getacl "); |
dead28da8 SUNRPC: eliminate... |
82 |
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; |
6e94d6299 NFS: Reduce stack... |
83 84 85 |
res.fattr = nfs_alloc_fattr(); if (res.fattr == NULL) return ERR_PTR(-ENOMEM); |
b8a7a3a66 posix_acl: Inode ... |
86 87 88 89 |
if (args.mask & NFS_ACL) nfs3_prepare_get_acl(&inode->i_acl); if (args.mask & NFS_DFACL) nfs3_prepare_get_acl(&inode->i_default_acl); |
dead28da8 SUNRPC: eliminate... |
90 |
status = rpc_call_sync(server->client_acl, &msg, 0); |
b7fa0554c [PATCH] NFS: Add ... |
91 92 93 94 95 96 97 98 99 |
dprintk("NFS reply getacl: %d ", status); /* pages may have been allocated at the xdr layer. */ for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) __free_page(args.pages[count]); switch (status) { case 0: |
6e94d6299 NFS: Reduce stack... |
100 |
status = nfs_refresh_inode(inode, res.fattr); |
b7fa0554c [PATCH] NFS: Add ... |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: dprintk("NFS_V3_ACL extension not supported; disabling "); server->caps &= ~NFS_CAP_ACLS; case -ENOTSUPP: status = -EOPNOTSUPP; default: goto getout; } if ((args.mask & res.mask) != args.mask) { status = -EIO; goto getout; } if (res.acl_access != NULL) { |
718360c59 nfs: fix setting ... |
118 |
if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) || |
013cdf108 nfs: use generic ... |
119 |
res.acl_access->a_count == 0) { |
b7fa0554c [PATCH] NFS: Add ... |
120 121 122 123 |
posix_acl_release(res.acl_access); res.acl_access = NULL; } } |
013cdf108 nfs: use generic ... |
124 |
if (res.mask & NFS_ACL) |
b8a7a3a66 posix_acl: Inode ... |
125 |
nfs3_complete_get_acl(&inode->i_acl, res.acl_access); |
013cdf108 nfs: use generic ... |
126 127 |
else forget_cached_acl(inode, ACL_TYPE_ACCESS); |
b7fa0554c [PATCH] NFS: Add ... |
128 |
|
013cdf108 nfs: use generic ... |
129 |
if (res.mask & NFS_DFACL) |
b8a7a3a66 posix_acl: Inode ... |
130 |
nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default); |
013cdf108 nfs: use generic ... |
131 132 133 134 135 136 137 138 139 140 |
else forget_cached_acl(inode, ACL_TYPE_DEFAULT); nfs_free_fattr(res.fattr); if (type == ACL_TYPE_ACCESS) { posix_acl_release(res.acl_default); return res.acl_access; } else { posix_acl_release(res.acl_access); return res.acl_default; |
b7fa0554c [PATCH] NFS: Add ... |
141 142 143 |
} getout: |
b8a7a3a66 posix_acl: Inode ... |
144 145 |
nfs3_abort_get_acl(&inode->i_acl); nfs3_abort_get_acl(&inode->i_default_acl); |
b7fa0554c [PATCH] NFS: Add ... |
146 147 |
posix_acl_release(res.acl_access); posix_acl_release(res.acl_default); |
6e94d6299 NFS: Reduce stack... |
148 |
nfs_free_fattr(res.fattr); |
013cdf108 nfs: use generic ... |
149 |
return ERR_PTR(status); |
b7fa0554c [PATCH] NFS: Add ... |
150 |
} |
8f493b9cf NFSv3: Fix return... |
151 |
static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, |
013cdf108 nfs: use generic ... |
152 |
struct posix_acl *dfacl) |
b7fa0554c [PATCH] NFS: Add ... |
153 154 |
{ struct nfs_server *server = NFS_SERVER(inode); |
6e94d6299 NFS: Reduce stack... |
155 |
struct nfs_fattr *fattr; |
ae46141ff NFSv3: Fix posix ... |
156 |
struct page *pages[NFSACL_MAXPAGES]; |
b7fa0554c [PATCH] NFS: Add ... |
157 158 159 160 161 162 |
struct nfs3_setaclargs args = { .inode = inode, .mask = NFS_ACL, .acl_access = acl, .pages = pages, }; |
dead28da8 SUNRPC: eliminate... |
163 164 165 166 |
struct rpc_message msg = { .rpc_argp = &args, .rpc_resp = &fattr, }; |
f87d928f6 NFSv3: Fix anothe... |
167 168 169 170 |
int status = 0; if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) goto out; |
b7fa0554c [PATCH] NFS: Add ... |
171 172 173 174 |
status = -EOPNOTSUPP; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) goto out; |
f61f6da0d NFS: Prevent memo... |
175 176 |
/* We are doing this here because XDR marshalling does not * return any results, it BUGs. */ |
b7fa0554c [PATCH] NFS: Add ... |
177 178 179 180 181 182 183 184 |
status = -ENOSPC; if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) goto out; if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) goto out; if (S_ISDIR(inode->i_mode)) { args.mask |= NFS_DFACL; args.acl_default = dfacl; |
ae46141ff NFSv3: Fix posix ... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
args.len = nfsacl_size(acl, dfacl); } else args.len = nfsacl_size(acl, NULL); if (args.len > NFS_ACL_INLINE_BUFSIZE) { unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT); status = -ENOMEM; do { args.pages[args.npages] = alloc_page(GFP_KERNEL); if (args.pages[args.npages] == NULL) goto out_freepages; args.npages++; } while (args.npages < npages); |
b7fa0554c [PATCH] NFS: Add ... |
199 200 201 202 |
} dprintk("NFS call setacl "); |
6e94d6299 NFS: Reduce stack... |
203 204 205 206 |
status = -ENOMEM; fattr = nfs_alloc_fattr(); if (fattr == NULL) goto out_freepages; |
dead28da8 SUNRPC: eliminate... |
207 |
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; |
6e94d6299 NFS: Reduce stack... |
208 |
msg.rpc_resp = fattr; |
dead28da8 SUNRPC: eliminate... |
209 |
status = rpc_call_sync(server->client_acl, &msg, 0); |
f41f74183 NFS: Ensure we za... |
210 211 |
nfs_access_zap_cache(inode); nfs_zap_acl_cache(inode); |
b7fa0554c [PATCH] NFS: Add ... |
212 213 |
dprintk("NFS reply setacl: %d ", status); |
b7fa0554c [PATCH] NFS: Add ... |
214 215 |
switch (status) { case 0: |
6e94d6299 NFS: Reduce stack... |
216 |
status = nfs_refresh_inode(inode, fattr); |
013cdf108 nfs: use generic ... |
217 218 |
set_cached_acl(inode, ACL_TYPE_ACCESS, acl); set_cached_acl(inode, ACL_TYPE_DEFAULT, dfacl); |
b7fa0554c [PATCH] NFS: Add ... |
219 220 221 222 223 224 225 226 227 228 |
break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: dprintk("NFS_V3_ACL SETACL RPC not supported" "(will not retry) "); server->caps &= ~NFS_CAP_ACLS; case -ENOTSUPP: status = -EOPNOTSUPP; } |
6e94d6299 NFS: Reduce stack... |
229 |
nfs_free_fattr(fattr); |
ae46141ff NFSv3: Fix posix ... |
230 231 232 233 234 |
out_freepages: while (args.npages != 0) { args.npages--; __free_page(args.pages[args.npages]); } |
b7fa0554c [PATCH] NFS: Add ... |
235 236 237 |
out: return status; } |
8f493b9cf NFSv3: Fix return... |
238 239 240 241 242 243 244 245 |
int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, struct posix_acl *dfacl) { int ret; ret = __nfs3_proc_setacls(inode, acl, dfacl); return (ret == -EOPNOTSUPP) ? 0 : ret; } |
013cdf108 nfs: use generic ... |
246 |
int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type) |
b7fa0554c [PATCH] NFS: Add ... |
247 248 249 250 251 252 |
{ struct posix_acl *alloc = NULL, *dfacl = NULL; int status; if (S_ISDIR(inode->i_mode)) { switch(type) { |
013cdf108 nfs: use generic ... |
253 254 255 256 257 258 259 260 261 262 263 264 |
case ACL_TYPE_ACCESS: alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(alloc)) goto fail; break; case ACL_TYPE_DEFAULT: dfacl = acl; alloc = acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(alloc)) goto fail; break; |
b7fa0554c [PATCH] NFS: Add ... |
265 |
} |
013cdf108 nfs: use generic ... |
266 |
} |
b7fa0554c [PATCH] NFS: Add ... |
267 268 269 270 271 272 |
if (acl == NULL) { alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); if (IS_ERR(alloc)) goto fail; } |
8f493b9cf NFSv3: Fix return... |
273 |
status = __nfs3_proc_setacls(inode, acl, dfacl); |
b7fa0554c [PATCH] NFS: Add ... |
274 275 276 277 278 279 |
posix_acl_release(alloc); return status; fail: return PTR_ERR(alloc); } |
055ffbea0 [PATCH] NFS: Fix ... |
280 |
|
013cdf108 nfs: use generic ... |
281 282 283 284 285 |
const struct xattr_handler *nfs3_xattr_handlers[] = { &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, NULL, }; |
74adf83f5 nfs: only show Po... |
286 287 288 289 290 291 292 293 294 |
static int nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data, size_t size, ssize_t *result) { struct posix_acl *acl; char *p = data + *result; acl = get_acl(inode, type); |
7a9e75a18 nfs3_list_one_acl... |
295 |
if (IS_ERR_OR_NULL(acl)) |
74adf83f5 nfs: only show Po... |
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
return 0; posix_acl_release(acl); *result += strlen(name); *result += 1; if (!size) return 0; if (*result > size) return -ERANGE; strcpy(p, name); return 0; } ssize_t nfs3_listxattr(struct dentry *dentry, char *data, size_t size) { |
2b0143b5c VFS: normal files... |
314 |
struct inode *inode = d_inode(dentry); |
74adf83f5 nfs: only show Po... |
315 316 317 318 |
ssize_t result = 0; int error; error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS, |
97d792992 posix acls: Remov... |
319 |
XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result); |
74adf83f5 nfs: only show Po... |
320 321 322 323 |
if (error) return error; error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT, |
97d792992 posix acls: Remov... |
324 |
XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result); |
74adf83f5 nfs: only show Po... |
325 326 327 328 |
if (error) return error; return result; } |