Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] NFSD: Add server support for NFSv3 ACLs.

This adds functions for encoding and decoding POSIX ACLs for the NFSACL
protocol extension, and the GETACL and SETACL RPCs. The implementation is
compatible with NFSACL in Solaris.

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Andreas Gruenbacher and committed by
Trond Myklebust
a257cdd0 9ba02638

+1166 -1
+24
fs/Kconfig
··· 1353 1353 select LOCKD 1354 1354 select SUNRPC 1355 1355 select EXPORTFS 1356 + select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL 1356 1357 help 1357 1358 If you want your Linux box to act as an NFS *server*, so that other 1358 1359 computers on your local network which support NFS can access certain ··· 1377 1376 To compile the NFS server support as a module, choose M here: the 1378 1377 module will be called nfsd. If unsure, say N. 1379 1378 1379 + config NFSD_V2_ACL 1380 + bool 1381 + depends on NFSD 1382 + 1380 1383 config NFSD_V3 1381 1384 bool "Provide NFSv3 server support" 1382 1385 depends on NFSD 1383 1386 help 1384 1387 If you would like to include the NFSv3 server as well as the NFSv2 1385 1388 server, say Y here. If unsure, say Y. 1389 + 1390 + config NFSD_V3_ACL 1391 + bool "Provide server support for the NFSv3 ACL protocol extension" 1392 + depends on NFSD_V3 1393 + select NFSD_V2_ACL 1394 + help 1395 + Implement the NFSv3 ACL protocol extension for manipulating POSIX 1396 + Access Control Lists on exported file systems. NFS clients should 1397 + be compiled with the NFSv3 ACL protocol extension; see the 1398 + CONFIG_NFS_V3_ACL option. If unsure, say N. 1386 1399 1387 1400 config NFSD_V4 1388 1401 bool "Provide NFSv4 server support (EXPERIMENTAL)" ··· 1441 1426 1442 1427 config EXPORTFS 1443 1428 tristate 1429 + 1430 + config NFS_ACL_SUPPORT 1431 + tristate 1432 + select FS_POSIX_ACL 1433 + 1434 + config NFS_COMMON 1435 + bool 1436 + depends on NFSD || NFS_FS 1437 + default y 1444 1438 1445 1439 config SUNRPC 1446 1440 tristate
+1
fs/Makefile
··· 31 31 32 32 obj-$(CONFIG_FS_MBCACHE) += mbcache.o 33 33 obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o 34 + obj-$(CONFIG_NFS_COMMON) += nfs_common/ 34 35 35 36 obj-$(CONFIG_QUOTA) += dquot.o 36 37 obj-$(CONFIG_QFMT_V1) += quota_v1.o
+7
fs/nfs_common/Makefile
··· 1 + # 2 + # Makefile for Linux filesystem routines that are shared by client and server. 3 + # 4 + 5 + obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o 6 + 7 + nfs_acl-objs := nfsacl.o
+257
fs/nfs_common/nfsacl.c
··· 1 + /* 2 + * fs/nfs_common/nfsacl.c 3 + * 4 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 5 + */ 6 + 7 + /* 8 + * The Solaris nfsacl protocol represents some ACLs slightly differently 9 + * than POSIX 1003.1e draft 17 does (and we do): 10 + * 11 + * - Minimal ACLs always have an ACL_MASK entry, so they have 12 + * four instead of three entries. 13 + * - The ACL_MASK entry in such minimal ACLs always has the same 14 + * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs 15 + * the ACL_MASK and ACL_GROUP_OBJ entries may differ.) 16 + * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ 17 + * entries contain the identifiers of the owner and owning group. 18 + * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID). 19 + * - ACL entries in the kernel are kept sorted in ascending order 20 + * of (e_tag, e_id). Solaris ACLs are unsorted. 21 + */ 22 + 23 + #include <linux/module.h> 24 + #include <linux/fs.h> 25 + #include <linux/sunrpc/xdr.h> 26 + #include <linux/nfsacl.h> 27 + #include <linux/nfs3.h> 28 + #include <linux/sort.h> 29 + 30 + MODULE_LICENSE("GPL"); 31 + 32 + EXPORT_SYMBOL(nfsacl_encode); 33 + EXPORT_SYMBOL(nfsacl_decode); 34 + 35 + struct nfsacl_encode_desc { 36 + struct xdr_array2_desc desc; 37 + unsigned int count; 38 + struct posix_acl *acl; 39 + int typeflag; 40 + uid_t uid; 41 + gid_t gid; 42 + }; 43 + 44 + static int 45 + xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) 46 + { 47 + struct nfsacl_encode_desc *nfsacl_desc = 48 + (struct nfsacl_encode_desc *) desc; 49 + u32 *p = (u32 *) elem; 50 + 51 + if (nfsacl_desc->count < nfsacl_desc->acl->a_count) { 52 + struct posix_acl_entry *entry = 53 + &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; 54 + 55 + *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); 56 + switch(entry->e_tag) { 57 + case ACL_USER_OBJ: 58 + *p++ = htonl(nfsacl_desc->uid); 59 + break; 60 + case ACL_GROUP_OBJ: 61 + *p++ = htonl(nfsacl_desc->gid); 62 + break; 63 + case ACL_USER: 64 + case ACL_GROUP: 65 + *p++ = htonl(entry->e_id); 66 + break; 67 + default: /* Solaris depends on that! */ 68 + *p++ = 0; 69 + break; 70 + } 71 + *p++ = htonl(entry->e_perm & S_IRWXO); 72 + } else { 73 + const struct posix_acl_entry *pa, *pe; 74 + int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE; 75 + 76 + FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) { 77 + if (pa->e_tag == ACL_GROUP_OBJ) { 78 + group_obj_perm = pa->e_perm & S_IRWXO; 79 + break; 80 + } 81 + } 82 + /* fake up ACL_MASK entry */ 83 + *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag); 84 + *p++ = htonl(0); 85 + *p++ = htonl(group_obj_perm); 86 + } 87 + 88 + return 0; 89 + } 90 + 91 + unsigned int 92 + nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, 93 + struct posix_acl *acl, int encode_entries, int typeflag) 94 + { 95 + int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; 96 + struct nfsacl_encode_desc nfsacl_desc = { 97 + .desc = { 98 + .elem_size = 12, 99 + .array_len = encode_entries ? entries : 0, 100 + .xcode = xdr_nfsace_encode, 101 + }, 102 + .acl = acl, 103 + .typeflag = typeflag, 104 + .uid = inode->i_uid, 105 + .gid = inode->i_gid, 106 + }; 107 + int err; 108 + 109 + if (entries > NFS_ACL_MAX_ENTRIES || 110 + xdr_encode_word(buf, base, entries)) 111 + return -EINVAL; 112 + err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); 113 + if (!err) 114 + err = 8 + nfsacl_desc.desc.elem_size * 115 + nfsacl_desc.desc.array_len; 116 + return err; 117 + } 118 + 119 + struct nfsacl_decode_desc { 120 + struct xdr_array2_desc desc; 121 + unsigned int count; 122 + struct posix_acl *acl; 123 + }; 124 + 125 + static int 126 + xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) 127 + { 128 + struct nfsacl_decode_desc *nfsacl_desc = 129 + (struct nfsacl_decode_desc *) desc; 130 + u32 *p = (u32 *) elem; 131 + struct posix_acl_entry *entry; 132 + 133 + if (!nfsacl_desc->acl) { 134 + if (desc->array_len > NFS_ACL_MAX_ENTRIES) 135 + return -EINVAL; 136 + nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); 137 + if (!nfsacl_desc->acl) 138 + return -ENOMEM; 139 + nfsacl_desc->count = 0; 140 + } 141 + 142 + entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; 143 + entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; 144 + entry->e_id = ntohl(*p++); 145 + entry->e_perm = ntohl(*p++); 146 + 147 + switch(entry->e_tag) { 148 + case ACL_USER_OBJ: 149 + case ACL_USER: 150 + case ACL_GROUP_OBJ: 151 + case ACL_GROUP: 152 + case ACL_OTHER: 153 + if (entry->e_perm & ~S_IRWXO) 154 + return -EINVAL; 155 + break; 156 + case ACL_MASK: 157 + /* Solaris sometimes sets additonal bits in the mask */ 158 + entry->e_perm &= S_IRWXO; 159 + break; 160 + default: 161 + return -EINVAL; 162 + } 163 + 164 + return 0; 165 + } 166 + 167 + static int 168 + cmp_acl_entry(const void *x, const void *y) 169 + { 170 + const struct posix_acl_entry *a = x, *b = y; 171 + 172 + if (a->e_tag != b->e_tag) 173 + return a->e_tag - b->e_tag; 174 + else if (a->e_id > b->e_id) 175 + return 1; 176 + else if (a->e_id < b->e_id) 177 + return -1; 178 + else 179 + return 0; 180 + } 181 + 182 + /* 183 + * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. 184 + */ 185 + static int 186 + posix_acl_from_nfsacl(struct posix_acl *acl) 187 + { 188 + struct posix_acl_entry *pa, *pe, 189 + *group_obj = NULL, *mask = NULL; 190 + 191 + if (!acl) 192 + return 0; 193 + 194 + sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry), 195 + cmp_acl_entry, NULL); 196 + 197 + /* Clear undefined identifier fields and find the ACL_GROUP_OBJ 198 + and ACL_MASK entries. */ 199 + FOREACH_ACL_ENTRY(pa, acl, pe) { 200 + switch(pa->e_tag) { 201 + case ACL_USER_OBJ: 202 + pa->e_id = ACL_UNDEFINED_ID; 203 + break; 204 + case ACL_GROUP_OBJ: 205 + pa->e_id = ACL_UNDEFINED_ID; 206 + group_obj = pa; 207 + break; 208 + case ACL_MASK: 209 + mask = pa; 210 + /* fall through */ 211 + case ACL_OTHER: 212 + pa->e_id = ACL_UNDEFINED_ID; 213 + break; 214 + } 215 + } 216 + if (acl->a_count == 4 && group_obj && mask && 217 + mask->e_perm == group_obj->e_perm) { 218 + /* remove bogus ACL_MASK entry */ 219 + memmove(mask, mask+1, (3 - (mask - acl->a_entries)) * 220 + sizeof(struct posix_acl_entry)); 221 + acl->a_count = 3; 222 + } 223 + return 0; 224 + } 225 + 226 + unsigned int 227 + nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, 228 + struct posix_acl **pacl) 229 + { 230 + struct nfsacl_decode_desc nfsacl_desc = { 231 + .desc = { 232 + .elem_size = 12, 233 + .xcode = pacl ? xdr_nfsace_decode : NULL, 234 + }, 235 + }; 236 + u32 entries; 237 + int err; 238 + 239 + if (xdr_decode_word(buf, base, &entries) || 240 + entries > NFS_ACL_MAX_ENTRIES) 241 + return -EINVAL; 242 + err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc); 243 + if (err) 244 + return err; 245 + if (pacl) { 246 + if (entries != nfsacl_desc.desc.array_len || 247 + posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { 248 + posix_acl_release(nfsacl_desc.acl); 249 + return -EINVAL; 250 + } 251 + *pacl = nfsacl_desc.acl; 252 + } 253 + if (aclcnt) 254 + *aclcnt = entries; 255 + return 8 + nfsacl_desc.desc.elem_size * 256 + nfsacl_desc.desc.array_len; 257 + }
+2
fs/nfsd/Makefile
··· 6 6 7 7 nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ 8 8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o 9 + nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o 9 10 nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o 11 + nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o 10 12 nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ 11 13 nfs4acl.o nfs4callback.o 12 14 nfsd-objs := $(nfsd-y)
+336
fs/nfsd/nfs2acl.c
··· 1 + /* 2 + * linux/fs/nfsd/nfsacl.c 3 + * 4 + * Process version 2 NFSACL requests. 5 + * 6 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 7 + */ 8 + 9 + #include <linux/sunrpc/svc.h> 10 + #include <linux/nfs.h> 11 + #include <linux/nfsd/nfsd.h> 12 + #include <linux/nfsd/cache.h> 13 + #include <linux/nfsd/xdr.h> 14 + #include <linux/nfsd/xdr3.h> 15 + #include <linux/posix_acl.h> 16 + #include <linux/nfsacl.h> 17 + 18 + #define NFSDDBG_FACILITY NFSDDBG_PROC 19 + #define RETURN_STATUS(st) { resp->status = (st); return (st); } 20 + 21 + /* 22 + * NULL call. 23 + */ 24 + static int 25 + nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 26 + { 27 + return nfs_ok; 28 + } 29 + 30 + /* 31 + * Get the Access and/or Default ACL of a file. 32 + */ 33 + static int nfsacld_proc_getacl(struct svc_rqst * rqstp, 34 + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 35 + { 36 + svc_fh *fh; 37 + struct posix_acl *acl; 38 + int nfserr = 0; 39 + 40 + dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 41 + 42 + fh = fh_copy(&resp->fh, &argp->fh); 43 + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) 44 + RETURN_STATUS(nfserr_inval); 45 + 46 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 47 + RETURN_STATUS(nfserr_inval); 48 + resp->mask = argp->mask; 49 + 50 + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 51 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 52 + if (IS_ERR(acl)) { 53 + int err = PTR_ERR(acl); 54 + 55 + if (err == -ENODATA || err == -EOPNOTSUPP) 56 + acl = NULL; 57 + else { 58 + nfserr = nfserrno(err); 59 + goto fail; 60 + } 61 + } 62 + if (acl == NULL) { 63 + /* Solaris returns the inode's minimum ACL. */ 64 + 65 + struct inode *inode = fh->fh_dentry->d_inode; 66 + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 67 + } 68 + resp->acl_access = acl; 69 + } 70 + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 71 + /* Check how Solaris handles requests for the Default ACL 72 + of a non-directory! */ 73 + 74 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 75 + if (IS_ERR(acl)) { 76 + int err = PTR_ERR(acl); 77 + 78 + if (err == -ENODATA || err == -EOPNOTSUPP) 79 + acl = NULL; 80 + else { 81 + nfserr = nfserrno(err); 82 + goto fail; 83 + } 84 + } 85 + resp->acl_default = acl; 86 + } 87 + 88 + /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ 89 + RETURN_STATUS(0); 90 + 91 + fail: 92 + posix_acl_release(resp->acl_access); 93 + posix_acl_release(resp->acl_default); 94 + RETURN_STATUS(nfserr); 95 + } 96 + 97 + /* 98 + * Set the Access and/or Default ACL of a file. 99 + */ 100 + static int nfsacld_proc_setacl(struct svc_rqst * rqstp, 101 + struct nfsd3_setaclargs *argp, 102 + struct nfsd_attrstat *resp) 103 + { 104 + svc_fh *fh; 105 + int nfserr = 0; 106 + 107 + dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 108 + 109 + fh = fh_copy(&resp->fh, &argp->fh); 110 + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 111 + 112 + if (!nfserr) { 113 + nfserr = nfserrno( nfsd_set_posix_acl( 114 + fh, ACL_TYPE_ACCESS, argp->acl_access) ); 115 + } 116 + if (!nfserr) { 117 + nfserr = nfserrno( nfsd_set_posix_acl( 118 + fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 119 + } 120 + 121 + /* argp->acl_{access,default} may have been allocated in 122 + nfssvc_decode_setaclargs. */ 123 + posix_acl_release(argp->acl_access); 124 + posix_acl_release(argp->acl_default); 125 + return nfserr; 126 + } 127 + 128 + /* 129 + * Check file attributes 130 + */ 131 + static int nfsacld_proc_getattr(struct svc_rqst * rqstp, 132 + struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) 133 + { 134 + dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 135 + 136 + fh_copy(&resp->fh, &argp->fh); 137 + return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 138 + } 139 + 140 + /* 141 + * Check file access 142 + */ 143 + static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, 144 + struct nfsd3_accessres *resp) 145 + { 146 + int nfserr; 147 + 148 + dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", 149 + SVCFH_fmt(&argp->fh), 150 + argp->access); 151 + 152 + fh_copy(&resp->fh, &argp->fh); 153 + resp->access = argp->access; 154 + nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); 155 + return nfserr; 156 + } 157 + 158 + /* 159 + * XDR decode functions 160 + */ 161 + static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, 162 + struct nfsd3_getaclargs *argp) 163 + { 164 + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 165 + return 0; 166 + argp->mask = ntohl(*p); p++; 167 + 168 + return xdr_argsize_check(rqstp, p); 169 + } 170 + 171 + 172 + static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, 173 + struct nfsd3_setaclargs *argp) 174 + { 175 + struct kvec *head = rqstp->rq_arg.head; 176 + unsigned int base; 177 + int n; 178 + 179 + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 180 + return 0; 181 + argp->mask = ntohl(*p++); 182 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 183 + !xdr_argsize_check(rqstp, p)) 184 + return 0; 185 + 186 + base = (char *)p - (char *)head->iov_base; 187 + n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 188 + (argp->mask & NFS_ACL) ? 189 + &argp->acl_access : NULL); 190 + if (n > 0) 191 + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 192 + (argp->mask & NFS_DFACL) ? 193 + &argp->acl_default : NULL); 194 + return (n > 0); 195 + } 196 + 197 + static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, 198 + struct nfsd_fhandle *argp) 199 + { 200 + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 201 + return 0; 202 + return xdr_argsize_check(rqstp, p); 203 + } 204 + 205 + static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, 206 + struct nfsd3_accessargs *argp) 207 + { 208 + if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 209 + return 0; 210 + argp->access = ntohl(*p++); 211 + 212 + return xdr_argsize_check(rqstp, p); 213 + } 214 + 215 + /* 216 + * XDR encode functions 217 + */ 218 + 219 + /* GETACL */ 220 + static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, 221 + struct nfsd3_getaclres *resp) 222 + { 223 + struct dentry *dentry = resp->fh.fh_dentry; 224 + struct inode *inode = dentry->d_inode; 225 + int w = nfsacl_size( 226 + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 227 + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 228 + struct kvec *head = rqstp->rq_res.head; 229 + unsigned int base; 230 + int n; 231 + 232 + if (dentry == NULL || dentry->d_inode == NULL) 233 + return 0; 234 + inode = dentry->d_inode; 235 + 236 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 237 + *p++ = htonl(resp->mask); 238 + if (!xdr_ressize_check(rqstp, p)) 239 + return 0; 240 + base = (char *)p - (char *)head->iov_base; 241 + 242 + rqstp->rq_res.page_len = w; 243 + while (w > 0) { 244 + if (!svc_take_res_page(rqstp)) 245 + return 0; 246 + w -= PAGE_SIZE; 247 + } 248 + 249 + n = nfsacl_encode(&rqstp->rq_res, base, inode, 250 + resp->acl_access, 251 + resp->mask & NFS_ACL, 0); 252 + if (n > 0) 253 + n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 254 + resp->acl_default, 255 + resp->mask & NFS_DFACL, 256 + NFS_ACL_DEFAULT); 257 + if (n <= 0) 258 + return 0; 259 + return 1; 260 + } 261 + 262 + static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, 263 + struct nfsd_attrstat *resp) 264 + { 265 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 266 + return xdr_ressize_check(rqstp, p); 267 + } 268 + 269 + /* ACCESS */ 270 + static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, 271 + struct nfsd3_accessres *resp) 272 + { 273 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 274 + *p++ = htonl(resp->access); 275 + return xdr_ressize_check(rqstp, p); 276 + } 277 + 278 + /* 279 + * XDR release functions 280 + */ 281 + static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, 282 + struct nfsd3_getaclres *resp) 283 + { 284 + fh_put(&resp->fh); 285 + posix_acl_release(resp->acl_access); 286 + posix_acl_release(resp->acl_default); 287 + return 1; 288 + } 289 + 290 + static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, 291 + struct nfsd_fhandle *resp) 292 + { 293 + fh_put(&resp->fh); 294 + return 1; 295 + } 296 + 297 + #define nfsaclsvc_decode_voidargs NULL 298 + #define nfsaclsvc_encode_voidres NULL 299 + #define nfsaclsvc_release_void NULL 300 + #define nfsd3_fhandleargs nfsd_fhandle 301 + #define nfsd3_attrstatres nfsd_attrstat 302 + #define nfsd3_voidres nfsd3_voidargs 303 + struct nfsd3_voidargs { int dummy; }; 304 + 305 + #define PROC(name, argt, rest, relt, cache, respsize) \ 306 + { (svc_procfunc) nfsacld_proc_##name, \ 307 + (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ 308 + (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ 309 + (kxdrproc_t) nfsaclsvc_release_##relt, \ 310 + sizeof(struct nfsd3_##argt##args), \ 311 + sizeof(struct nfsd3_##rest##res), \ 312 + 0, \ 313 + cache, \ 314 + respsize, \ 315 + } 316 + 317 + #define ST 1 /* status*/ 318 + #define AT 21 /* attributes */ 319 + #define pAT (1+AT) /* post attributes - conditional */ 320 + #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 321 + 322 + static struct svc_procedure nfsd_acl_procedures2[] = { 323 + PROC(null, void, void, void, RC_NOCACHE, ST), 324 + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 325 + PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT), 326 + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), 327 + PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1), 328 + }; 329 + 330 + struct svc_version nfsd_acl_version2 = { 331 + .vs_vers = 2, 332 + .vs_nproc = 5, 333 + .vs_proc = nfsd_acl_procedures2, 334 + .vs_dispatch = nfsd_dispatch, 335 + .vs_xdrsize = NFS3_SVC_XDRSIZE, 336 + };
+267
fs/nfsd/nfs3acl.c
··· 1 + /* 2 + * linux/fs/nfsd/nfs3acl.c 3 + * 4 + * Process version 3 NFSACL requests. 5 + * 6 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 7 + */ 8 + 9 + #include <linux/sunrpc/svc.h> 10 + #include <linux/nfs3.h> 11 + #include <linux/nfsd/nfsd.h> 12 + #include <linux/nfsd/cache.h> 13 + #include <linux/nfsd/xdr3.h> 14 + #include <linux/posix_acl.h> 15 + #include <linux/nfsacl.h> 16 + 17 + #define RETURN_STATUS(st) { resp->status = (st); return (st); } 18 + 19 + /* 20 + * NULL call. 21 + */ 22 + static int 23 + nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 24 + { 25 + return nfs_ok; 26 + } 27 + 28 + /* 29 + * Get the Access and/or Default ACL of a file. 30 + */ 31 + static int nfsd3_proc_getacl(struct svc_rqst * rqstp, 32 + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 33 + { 34 + svc_fh *fh; 35 + struct posix_acl *acl; 36 + int nfserr = 0; 37 + 38 + fh = fh_copy(&resp->fh, &argp->fh); 39 + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) 40 + RETURN_STATUS(nfserr_inval); 41 + 42 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 43 + RETURN_STATUS(nfserr_inval); 44 + resp->mask = argp->mask; 45 + 46 + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 47 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 48 + if (IS_ERR(acl)) { 49 + int err = PTR_ERR(acl); 50 + 51 + if (err == -ENODATA || err == -EOPNOTSUPP) 52 + acl = NULL; 53 + else { 54 + nfserr = nfserrno(err); 55 + goto fail; 56 + } 57 + } 58 + if (acl == NULL) { 59 + /* Solaris returns the inode's minimum ACL. */ 60 + 61 + struct inode *inode = fh->fh_dentry->d_inode; 62 + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 63 + } 64 + resp->acl_access = acl; 65 + } 66 + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 67 + /* Check how Solaris handles requests for the Default ACL 68 + of a non-directory! */ 69 + 70 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 71 + if (IS_ERR(acl)) { 72 + int err = PTR_ERR(acl); 73 + 74 + if (err == -ENODATA || err == -EOPNOTSUPP) 75 + acl = NULL; 76 + else { 77 + nfserr = nfserrno(err); 78 + goto fail; 79 + } 80 + } 81 + resp->acl_default = acl; 82 + } 83 + 84 + /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ 85 + RETURN_STATUS(0); 86 + 87 + fail: 88 + posix_acl_release(resp->acl_access); 89 + posix_acl_release(resp->acl_default); 90 + RETURN_STATUS(nfserr); 91 + } 92 + 93 + /* 94 + * Set the Access and/or Default ACL of a file. 95 + */ 96 + static int nfsd3_proc_setacl(struct svc_rqst * rqstp, 97 + struct nfsd3_setaclargs *argp, 98 + struct nfsd3_attrstat *resp) 99 + { 100 + svc_fh *fh; 101 + int nfserr = 0; 102 + 103 + fh = fh_copy(&resp->fh, &argp->fh); 104 + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 105 + 106 + if (!nfserr) { 107 + nfserr = nfserrno( nfsd_set_posix_acl( 108 + fh, ACL_TYPE_ACCESS, argp->acl_access) ); 109 + } 110 + if (!nfserr) { 111 + nfserr = nfserrno( nfsd_set_posix_acl( 112 + fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 113 + } 114 + 115 + /* argp->acl_{access,default} may have been allocated in 116 + nfs3svc_decode_setaclargs. */ 117 + posix_acl_release(argp->acl_access); 118 + posix_acl_release(argp->acl_default); 119 + RETURN_STATUS(nfserr); 120 + } 121 + 122 + /* 123 + * XDR decode functions 124 + */ 125 + static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, 126 + struct nfsd3_getaclargs *args) 127 + { 128 + if (!(p = nfs3svc_decode_fh(p, &args->fh))) 129 + return 0; 130 + args->mask = ntohl(*p); p++; 131 + 132 + return xdr_argsize_check(rqstp, p); 133 + } 134 + 135 + 136 + static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, 137 + struct nfsd3_setaclargs *args) 138 + { 139 + struct kvec *head = rqstp->rq_arg.head; 140 + unsigned int base; 141 + int n; 142 + 143 + if (!(p = nfs3svc_decode_fh(p, &args->fh))) 144 + return 0; 145 + args->mask = ntohl(*p++); 146 + if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 147 + !xdr_argsize_check(rqstp, p)) 148 + return 0; 149 + 150 + base = (char *)p - (char *)head->iov_base; 151 + n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 152 + (args->mask & NFS_ACL) ? 153 + &args->acl_access : NULL); 154 + if (n > 0) 155 + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 156 + (args->mask & NFS_DFACL) ? 157 + &args->acl_default : NULL); 158 + return (n > 0); 159 + } 160 + 161 + /* 162 + * XDR encode functions 163 + */ 164 + 165 + /* GETACL */ 166 + static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, 167 + struct nfsd3_getaclres *resp) 168 + { 169 + struct dentry *dentry = resp->fh.fh_dentry; 170 + 171 + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 172 + if (resp->status == 0 && dentry && dentry->d_inode) { 173 + struct inode *inode = dentry->d_inode; 174 + int w = nfsacl_size( 175 + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 176 + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 177 + struct kvec *head = rqstp->rq_res.head; 178 + unsigned int base; 179 + int n; 180 + 181 + *p++ = htonl(resp->mask); 182 + if (!xdr_ressize_check(rqstp, p)) 183 + return 0; 184 + base = (char *)p - (char *)head->iov_base; 185 + 186 + rqstp->rq_res.page_len = w; 187 + while (w > 0) { 188 + if (!svc_take_res_page(rqstp)) 189 + return 0; 190 + w -= PAGE_SIZE; 191 + } 192 + 193 + n = nfsacl_encode(&rqstp->rq_res, base, inode, 194 + resp->acl_access, 195 + resp->mask & NFS_ACL, 0); 196 + if (n > 0) 197 + n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 198 + resp->acl_default, 199 + resp->mask & NFS_DFACL, 200 + NFS_ACL_DEFAULT); 201 + if (n <= 0) 202 + return 0; 203 + } else 204 + if (!xdr_ressize_check(rqstp, p)) 205 + return 0; 206 + 207 + return 1; 208 + } 209 + 210 + /* SETACL */ 211 + static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, 212 + struct nfsd3_attrstat *resp) 213 + { 214 + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 215 + 216 + return xdr_ressize_check(rqstp, p); 217 + } 218 + 219 + /* 220 + * XDR release functions 221 + */ 222 + static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, 223 + struct nfsd3_getaclres *resp) 224 + { 225 + fh_put(&resp->fh); 226 + posix_acl_release(resp->acl_access); 227 + posix_acl_release(resp->acl_default); 228 + return 1; 229 + } 230 + 231 + #define nfs3svc_decode_voidargs NULL 232 + #define nfs3svc_release_void NULL 233 + #define nfsd3_setaclres nfsd3_attrstat 234 + #define nfsd3_voidres nfsd3_voidargs 235 + struct nfsd3_voidargs { int dummy; }; 236 + 237 + #define PROC(name, argt, rest, relt, cache, respsize) \ 238 + { (svc_procfunc) nfsd3_proc_##name, \ 239 + (kxdrproc_t) nfs3svc_decode_##argt##args, \ 240 + (kxdrproc_t) nfs3svc_encode_##rest##res, \ 241 + (kxdrproc_t) nfs3svc_release_##relt, \ 242 + sizeof(struct nfsd3_##argt##args), \ 243 + sizeof(struct nfsd3_##rest##res), \ 244 + 0, \ 245 + cache, \ 246 + respsize, \ 247 + } 248 + 249 + #define ST 1 /* status*/ 250 + #define AT 21 /* attributes */ 251 + #define pAT (1+AT) /* post attributes - conditional */ 252 + #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 253 + 254 + static struct svc_procedure nfsd_acl_procedures3[] = { 255 + PROC(null, void, void, void, RC_NOCACHE, ST), 256 + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 257 + PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), 258 + }; 259 + 260 + struct svc_version nfsd_acl_version3 = { 261 + .vs_vers = 3, 262 + .vs_nproc = 3, 263 + .vs_proc = nfsd_acl_procedures3, 264 + .vs_dispatch = nfsd_dispatch, 265 + .vs_xdrsize = NFS3_SVC_XDRSIZE, 266 + }; 267 +
+13
fs/nfsd/nfs3xdr.c
··· 71 71 return p + XDR_QUADLEN(size); 72 72 } 73 73 74 + /* Helper function for NFSv3 ACL code */ 75 + u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) 76 + { 77 + return decode_fh(p, fhp); 78 + } 79 + 74 80 static inline u32 * 75 81 encode_fh(u32 *p, struct svc_fh *fhp) 76 82 { ··· 237 231 } 238 232 *p++ = xdr_zero; 239 233 return p; 234 + } 235 + 236 + /* Helper for NFSv3 ACLs */ 237 + u32 * 238 + nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 239 + { 240 + return encode_post_op_attr(rqstp, p, fhp); 240 241 } 241 242 242 243 /*
+27
fs/nfsd/nfssvc.c
··· 31 31 #include <linux/nfsd/stats.h> 32 32 #include <linux/nfsd/cache.h> 33 33 #include <linux/lockd/bind.h> 34 + #include <linux/nfsacl.h> 34 35 35 36 #define NFSDDBG_FACILITY NFSDDBG_SVC 36 37 ··· 363 362 return 1; 364 363 } 365 364 365 + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 366 + static struct svc_stat nfsd_acl_svcstats; 367 + static struct svc_version * nfsd_acl_version[] = { 368 + [2] = &nfsd_acl_version2, 369 + [3] = &nfsd_acl_version3, 370 + }; 371 + 372 + #define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0])) 373 + static struct svc_program nfsd_acl_program = { 374 + .pg_prog = NFS_ACL_PROGRAM, 375 + .pg_nvers = NFSD_ACL_NRVERS, 376 + .pg_vers = nfsd_acl_version, 377 + .pg_name = "nfsd", 378 + .pg_stats = &nfsd_acl_svcstats, 379 + }; 380 + 381 + static struct svc_stat nfsd_acl_svcstats = { 382 + .program = &nfsd_acl_program, 383 + }; 384 + 385 + #define nfsd_acl_program_p &nfsd_acl_program 386 + #else 387 + #define nfsd_acl_program_p NULL 388 + #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ 389 + 366 390 extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; 367 391 368 392 static struct svc_version * nfsd_version[] = { ··· 402 376 403 377 #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) 404 378 struct svc_program nfsd_program = { 379 + .pg_next = nfsd_acl_program_p, 405 380 .pg_prog = NFS_PROGRAM, /* program number */ 406 381 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ 407 382 .pg_vers = nfsd_version, /* version table */
+11
fs/nfsd/nfsxdr.c
··· 49 49 return p + (NFS_FHSIZE >> 2); 50 50 } 51 51 52 + /* Helper function for NFSv2 ACL code */ 53 + u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) 54 + { 55 + return decode_fh(p, fhp); 56 + } 57 + 52 58 static inline u32 * 53 59 encode_fh(u32 *p, struct svc_fh *fhp) 54 60 { ··· 196 190 return p; 197 191 } 198 192 193 + /* Helper function for NFSv2 ACL code */ 194 + u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 195 + { 196 + return encode_fattr(rqstp, p, fhp); 197 + } 199 198 200 199 /* 201 200 * XDR decode functions
+106 -1
fs/nfsd/vfs.c
··· 46 46 #include <linux/nfsd/nfsfh.h> 47 47 #include <linux/quotaops.h> 48 48 #include <linux/dnotify.h> 49 - #ifdef CONFIG_NFSD_V4 49 + #include <linux/xattr_acl.h> 50 50 #include <linux/posix_acl.h> 51 + #ifdef CONFIG_NFSD_V4 51 52 #include <linux/posix_acl_xattr.h> 52 53 #include <linux/xattr_acl.h> 53 54 #include <linux/xattr.h> ··· 1858 1857 nfsdstats.ra_size = cache_size; 1859 1858 return 0; 1860 1859 } 1860 + 1861 + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 1862 + struct posix_acl * 1863 + nfsd_get_posix_acl(struct svc_fh *fhp, int type) 1864 + { 1865 + struct inode *inode = fhp->fh_dentry->d_inode; 1866 + char *name; 1867 + void *value = NULL; 1868 + ssize_t size; 1869 + struct posix_acl *acl; 1870 + 1871 + if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr) 1872 + return ERR_PTR(-EOPNOTSUPP); 1873 + switch(type) { 1874 + case ACL_TYPE_ACCESS: 1875 + name = XATTR_NAME_ACL_ACCESS; 1876 + break; 1877 + case ACL_TYPE_DEFAULT: 1878 + name = XATTR_NAME_ACL_DEFAULT; 1879 + break; 1880 + default: 1881 + return ERR_PTR(-EOPNOTSUPP); 1882 + } 1883 + 1884 + size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0); 1885 + 1886 + if (size < 0) { 1887 + acl = ERR_PTR(size); 1888 + goto getout; 1889 + } else if (size > 0) { 1890 + value = kmalloc(size, GFP_KERNEL); 1891 + if (!value) { 1892 + acl = ERR_PTR(-ENOMEM); 1893 + goto getout; 1894 + } 1895 + size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size); 1896 + if (size < 0) { 1897 + acl = ERR_PTR(size); 1898 + goto getout; 1899 + } 1900 + } 1901 + acl = posix_acl_from_xattr(value, size); 1902 + 1903 + getout: 1904 + kfree(value); 1905 + return acl; 1906 + } 1907 + 1908 + int 1909 + nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) 1910 + { 1911 + struct inode *inode = fhp->fh_dentry->d_inode; 1912 + char *name; 1913 + void *value = NULL; 1914 + size_t size; 1915 + int error; 1916 + 1917 + if (!IS_POSIXACL(inode) || !inode->i_op || 1918 + !inode->i_op->setxattr || !inode->i_op->removexattr) 1919 + return -EOPNOTSUPP; 1920 + switch(type) { 1921 + case ACL_TYPE_ACCESS: 1922 + name = XATTR_NAME_ACL_ACCESS; 1923 + break; 1924 + case ACL_TYPE_DEFAULT: 1925 + name = XATTR_NAME_ACL_DEFAULT; 1926 + break; 1927 + default: 1928 + return -EOPNOTSUPP; 1929 + } 1930 + 1931 + if (acl && acl->a_count) { 1932 + size = xattr_acl_size(acl->a_count); 1933 + value = kmalloc(size, GFP_KERNEL); 1934 + if (!value) 1935 + return -ENOMEM; 1936 + size = posix_acl_to_xattr(acl, value, size); 1937 + if (size < 0) { 1938 + error = size; 1939 + goto getout; 1940 + } 1941 + } else 1942 + size = 0; 1943 + 1944 + if (!fhp->fh_locked) 1945 + fh_lock(fhp); /* unlocking is done automatically */ 1946 + if (size) 1947 + error = inode->i_op->setxattr(fhp->fh_dentry, name, 1948 + value, size, 0); 1949 + else { 1950 + if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) 1951 + error = 0; 1952 + else { 1953 + error = inode->i_op->removexattr(fhp->fh_dentry, name); 1954 + if (error == -ENODATA) 1955 + error = 0; 1956 + } 1957 + } 1958 + 1959 + getout: 1960 + kfree(value); 1961 + return error; 1962 + } 1963 + #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
+58
include/linux/nfsacl.h
··· 1 + /* 2 + * File: linux/nfsacl.h 3 + * 4 + * (C) 2003 Andreas Gruenbacher <agruen@suse.de> 5 + */ 6 + #ifndef __LINUX_NFSACL_H 7 + #define __LINUX_NFSACL_H 8 + 9 + #define NFS_ACL_PROGRAM 100227 10 + 11 + #define ACLPROC2_GETACL 1 12 + #define ACLPROC2_SETACL 2 13 + #define ACLPROC2_GETATTR 3 14 + #define ACLPROC2_ACCESS 4 15 + 16 + #define ACLPROC3_GETACL 1 17 + #define ACLPROC3_SETACL 2 18 + 19 + 20 + /* Flags for the getacl/setacl mode */ 21 + #define NFS_ACL 0x0001 22 + #define NFS_ACLCNT 0x0002 23 + #define NFS_DFACL 0x0004 24 + #define NFS_DFACLCNT 0x0008 25 + 26 + /* Flag for Default ACL entries */ 27 + #define NFS_ACL_DEFAULT 0x1000 28 + 29 + #ifdef __KERNEL__ 30 + 31 + #include <linux/posix_acl.h> 32 + 33 + /* Maximum number of ACL entries over NFS */ 34 + #define NFS_ACL_MAX_ENTRIES 1024 35 + 36 + #define NFSACL_MAXWORDS (2*(2+3*NFS_ACL_MAX_ENTRIES)) 37 + #define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ 38 + >> PAGE_SHIFT) 39 + 40 + static inline unsigned int 41 + nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) 42 + { 43 + unsigned int w = 16; 44 + w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12; 45 + if (acl_default) 46 + w += max((int)acl_default->a_count, 4) * 12; 47 + return w; 48 + } 49 + 50 + extern unsigned int 51 + nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, 52 + struct posix_acl *acl, int encode_entries, int typeflag); 53 + extern unsigned int 54 + nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, 55 + struct posix_acl **pacl); 56 + 57 + #endif /* __KERNEL__ */ 58 + #endif /* __LINUX_NFSACL_H */
+16
include/linux/nfsd/nfsd.h
··· 15 15 #include <linux/unistd.h> 16 16 #include <linux/dirent.h> 17 17 #include <linux/fs.h> 18 + #include <linux/posix_acl.h> 18 19 #include <linux/mount.h> 19 20 20 21 #include <linux/nfsd/debug.h> ··· 124 123 125 124 int nfsd_notify_change(struct inode *, struct iattr *); 126 125 int nfsd_permission(struct svc_export *, struct dentry *, int); 126 + 127 + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 128 + #ifdef CONFIG_NFSD_V2_ACL 129 + extern struct svc_version nfsd_acl_version2; 130 + #else 131 + #define nfsd_acl_version2 NULL 132 + #endif 133 + #ifdef CONFIG_NFSD_V3_ACL 134 + extern struct svc_version nfsd_acl_version3; 135 + #else 136 + #define nfsd_acl_version3 NULL 137 + #endif 138 + struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); 139 + int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); 140 + #endif 127 141 128 142 129 143 /*
+4
include/linux/nfsd/xdr.h
··· 169 169 170 170 int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); 171 171 172 + /* Helper functions for NFSv2 ACL code */ 173 + u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp); 174 + u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp); 175 + 172 176 #endif /* LINUX_NFSD_H */
+26
include/linux/nfsd/xdr3.h
··· 110 110 __u32 count; 111 111 }; 112 112 113 + struct nfsd3_getaclargs { 114 + struct svc_fh fh; 115 + int mask; 116 + }; 117 + 118 + struct posix_acl; 119 + struct nfsd3_setaclargs { 120 + struct svc_fh fh; 121 + int mask; 122 + struct posix_acl *acl_access; 123 + struct posix_acl *acl_default; 124 + }; 125 + 113 126 struct nfsd3_attrstat { 114 127 __u32 status; 115 128 struct svc_fh fh; ··· 222 209 struct svc_fh fh; 223 210 }; 224 211 212 + struct nfsd3_getaclres { 213 + __u32 status; 214 + struct svc_fh fh; 215 + int mask; 216 + struct posix_acl *acl_access; 217 + struct posix_acl *acl_default; 218 + }; 219 + 225 220 /* dummy type for release */ 226 221 struct nfsd3_fhandle_pair { 227 222 __u32 dummy; ··· 262 241 struct nfsd3_fsinfores fsinfores; 263 242 struct nfsd3_pathconfres pathconfres; 264 243 struct nfsd3_commitres commitres; 244 + struct nfsd3_getaclres getaclres; 265 245 }; 266 246 267 247 #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) ··· 338 316 int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, 339 317 int namlen, loff_t offset, ino_t ino, 340 318 unsigned int); 319 + /* Helper functions for NFSv3 ACL code */ 320 + u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, 321 + struct svc_fh *fhp); 322 + u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp); 341 323 342 324 343 325 #endif /* _LINUX_NFSD_XDR3_H */
+11
include/linux/sunrpc/svc.h
··· 185 185 return vec->iov_len <= PAGE_SIZE; 186 186 } 187 187 188 + static inline struct page * 189 + svc_take_res_page(struct svc_rqst *rqstp) 190 + { 191 + if (rqstp->rq_arghi <= rqstp->rq_argused) 192 + return NULL; 193 + rqstp->rq_arghi--; 194 + rqstp->rq_respages[rqstp->rq_resused] = 195 + rqstp->rq_argpages[rqstp->rq_arghi]; 196 + return rqstp->rq_respages[rqstp->rq_resused++]; 197 + } 198 + 188 199 static inline int svc_take_page(struct svc_rqst *rqstp) 189 200 { 190 201 if (rqstp->rq_arghi <= rqstp->rq_argused)