static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, struct posix_acl *dfacl) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_fattr *fattr; struct page *pages[NFSACL_MAXPAGES]; struct nfs3_setaclargs args = { .inode = inode, .mask = NFS_ACL, .acl_access = acl, .pages = pages, }; struct rpc_message msg = { .rpc_argp = &args, .rpc_resp = &fattr, }; int status = 0; if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) goto out; status = -EOPNOTSUPP; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) goto out; /* We are doing this here because XDR marshalling does not * return any results, it BUGs. */ 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; 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); }
/* GETACL */ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; struct inode *inode; struct kvec *head = rqstp->rq_res.head; unsigned int base; int n; int w; /* * Since this is version 2, the check for nfserr in * nfsd_dispatch actually ensures the following cannot happen. * However, it seems fragile to depend on that. */ if (dentry == NULL || dentry->d_inode == NULL) return 0; inode = dentry->d_inode; p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); *p++ = htonl(resp->mask); if (!xdr_ressize_check(rqstp, p)) return 0; base = (char *)p - (char *)head->iov_base; rqstp->rq_res.page_len = w = nfsacl_size( (resp->mask & NFS_ACL) ? resp->acl_access : NULL, (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); while (w > 0) { if (!rqstp->rq_respages[rqstp->rq_resused++]) return 0; w -= PAGE_SIZE; } n = nfsacl_encode(&rqstp->rq_res, base, inode, resp->acl_access, resp->mask & NFS_ACL, 0); if (n > 0) n = nfsacl_encode(&rqstp->rq_res, base + n, inode, resp->acl_default, resp->mask & NFS_DFACL, NFS_ACL_DEFAULT); if (n <= 0) return 0; return 1; }
/* GETACL */ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_getaclres *resp) { struct dentry *dentry = resp->fh.fh_dentry; p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0 && dentry && dentry->d_inode) { struct inode *inode = dentry->d_inode; struct kvec *head = rqstp->rq_res.head; unsigned int base; int n; int w; *p++ = htonl(resp->mask); if (!xdr_ressize_check(rqstp, p)) return 0; base = (char *)p - (char *)head->iov_base; rqstp->rq_res.page_len = w = nfsacl_size( (resp->mask & NFS_ACL) ? resp->acl_access : NULL, (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); while (w > 0) { if (!rqstp->rq_respages[rqstp->rq_resused++]) return 0; w -= PAGE_SIZE; } n = nfsacl_encode(&rqstp->rq_res, base, inode, resp->acl_access, resp->mask & NFS_ACL, 0); if (n > 0) n = nfsacl_encode(&rqstp->rq_res, base + n, inode, resp->acl_default, resp->mask & NFS_DFACL, NFS_ACL_DEFAULT); if (n <= 0) return 0; } else if (!xdr_ressize_check(rqstp, p)) return 0; return 1; }