nfsd: use get_acl and ->set_acl
Remove the boilerplate code to marshall and unmarhall ACL objects into xattrs and operate on the posix_acl objects directly. Also move all the ACL handling code into nfs?acl.c where it belongs. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
					parent
					
						
							
								feda821e76
							
						
					
				
			
			
				commit
				
					
						4ac7249ea5
					
				
			
		
					 7 changed files with 174 additions and 348 deletions
				
			
		|  | @ -35,7 +35,9 @@ | |||
| #ifndef LINUX_NFS4_ACL_H | ||||
| #define LINUX_NFS4_ACL_H | ||||
| 
 | ||||
| #include <linux/posix_acl.h> | ||||
| struct nfs4_acl; | ||||
| struct svc_fh; | ||||
| struct svc_rqst; | ||||
| 
 | ||||
| /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
 | ||||
|  * fit in a page: */ | ||||
|  | @ -45,13 +47,9 @@ struct nfs4_acl *nfs4_acl_new(int); | |||
| int nfs4_acl_get_whotype(char *, u32); | ||||
| int nfs4_acl_write_who(int who, char *p); | ||||
| 
 | ||||
| #define NFS4_ACL_TYPE_DEFAULT	0x01 | ||||
| #define NFS4_ACL_DIR		0x02 | ||||
| #define NFS4_ACL_OWNER		0x04 | ||||
| 
 | ||||
| struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *, | ||||
| 				struct posix_acl *, unsigned int flags); | ||||
| int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **, | ||||
| 				struct posix_acl **, unsigned int flags); | ||||
| int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, | ||||
| 		struct nfs4_acl **acl); | ||||
| __be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||
| 		struct nfs4_acl *acl); | ||||
| 
 | ||||
| #endif /* LINUX_NFS4_ACL_H */ | ||||
|  |  | |||
|  | @ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | |||
| static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, | ||||
| 		struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||||
| { | ||||
| 	svc_fh *fh; | ||||
| 	struct posix_acl *acl; | ||||
| 	struct inode *inode; | ||||
| 	svc_fh *fh; | ||||
| 	__be32 nfserr = 0; | ||||
| 
 | ||||
| 	dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh)); | ||||
|  | @ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, | |||
| 	if (nfserr) | ||||
| 		RETURN_STATUS(nfserr); | ||||
| 
 | ||||
| 	inode = fh->fh_dentry->d_inode; | ||||
| 
 | ||||
| 	if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||||
| 		RETURN_STATUS(nfserr_inval); | ||||
| 	resp->mask = argp->mask; | ||||
|  | @ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, | |||
| 		goto fail; | ||||
| 
 | ||||
| 	if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||||
| 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||||
| 		acl = get_acl(inode, ACL_TYPE_ACCESS); | ||||
| 		if (IS_ERR(acl)) { | ||||
| 			int err = PTR_ERR(acl); | ||||
| 
 | ||||
| 			if (err == -ENODATA || err == -EOPNOTSUPP) | ||||
| 				acl = NULL; | ||||
| 			else { | ||||
| 				nfserr = nfserrno(err); | ||||
| 				goto fail; | ||||
| 			} | ||||
| 			nfserr = nfserrno(PTR_ERR(acl)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if (acl == NULL) { | ||||
| 			/* Solaris returns the inode's minimum ACL. */ | ||||
| 
 | ||||
| 			struct inode *inode = fh->fh_dentry->d_inode; | ||||
| 			acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||||
| 		} | ||||
| 		resp->acl_access = acl; | ||||
|  | @ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, | |||
| 	if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||||
| 		/* Check how Solaris handles requests for the Default ACL
 | ||||
| 		   of a non-directory! */ | ||||
| 
 | ||||
| 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||||
| 		acl = get_acl(inode, ACL_TYPE_DEFAULT); | ||||
| 		if (IS_ERR(acl)) { | ||||
| 			int err = PTR_ERR(acl); | ||||
| 
 | ||||
| 			if (err == -ENODATA || err == -EOPNOTSUPP) | ||||
| 				acl = NULL; | ||||
| 			else { | ||||
| 				nfserr = nfserrno(err); | ||||
| 				goto fail; | ||||
| 			} | ||||
| 			nfserr = nfserrno(PTR_ERR(acl)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		resp->acl_default = acl; | ||||
| 	} | ||||
|  | @ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, | |||
| 		struct nfsd3_setaclargs *argp, | ||||
| 		struct nfsd_attrstat *resp) | ||||
| { | ||||
| 	struct inode *inode; | ||||
| 	svc_fh *fh; | ||||
| 	__be32 nfserr = 0; | ||||
| 	int error; | ||||
| 
 | ||||
| 	dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh)); | ||||
| 
 | ||||
| 	fh = fh_copy(&resp->fh, &argp->fh); | ||||
| 	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); | ||||
| 	if (nfserr) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (!nfserr) { | ||||
| 		nfserr = nfserrno( nfsd_set_posix_acl( | ||||
| 			fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||||
| 	} | ||||
| 	if (!nfserr) { | ||||
| 		nfserr = nfserrno( nfsd_set_posix_acl( | ||||
| 			fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||||
| 	} | ||||
| 	if (!nfserr) { | ||||
| 		nfserr = fh_getattr(fh, &resp->stat); | ||||
| 	inode = fh->fh_dentry->d_inode; | ||||
| 	if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { | ||||
| 		error = -EOPNOTSUPP; | ||||
| 		goto out_errno; | ||||
| 	} | ||||
| 
 | ||||
| 	error = fh_want_write(fh); | ||||
| 	if (error) | ||||
| 		goto out_errno; | ||||
| 
 | ||||
| 	error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	error = inode->i_op->set_acl(inode, argp->acl_default, | ||||
| 				     ACL_TYPE_DEFAULT); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 
 | ||||
| 	fh_drop_write(fh); | ||||
| 
 | ||||
| 	nfserr = fh_getattr(fh, &resp->stat); | ||||
| 
 | ||||
| out: | ||||
| 	/* argp->acl_{access,default} may have been allocated in
 | ||||
| 	   nfssvc_decode_setaclargs. */ | ||||
| 	posix_acl_release(argp->acl_access); | ||||
| 	posix_acl_release(argp->acl_default); | ||||
| 	return nfserr; | ||||
| out_drop_write: | ||||
| 	fh_drop_write(fh); | ||||
| out_errno: | ||||
| 	nfserr = nfserrno(error); | ||||
| 	goto out; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -29,8 +29,9 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | |||
| static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, | ||||
| 		struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||||
| { | ||||
| 	svc_fh *fh; | ||||
| 	struct posix_acl *acl; | ||||
| 	struct inode *inode; | ||||
| 	svc_fh *fh; | ||||
| 	__be32 nfserr = 0; | ||||
| 
 | ||||
| 	fh = fh_copy(&resp->fh, &argp->fh); | ||||
|  | @ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, | |||
| 	if (nfserr) | ||||
| 		RETURN_STATUS(nfserr); | ||||
| 
 | ||||
| 	inode = fh->fh_dentry->d_inode; | ||||
| 
 | ||||
| 	if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||||
| 		RETURN_STATUS(nfserr_inval); | ||||
| 	resp->mask = argp->mask; | ||||
| 
 | ||||
| 	if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||||
| 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||||
| 		acl = get_acl(inode, ACL_TYPE_ACCESS); | ||||
| 		if (IS_ERR(acl)) { | ||||
| 			int err = PTR_ERR(acl); | ||||
| 
 | ||||
| 			if (err == -ENODATA || err == -EOPNOTSUPP) | ||||
| 				acl = NULL; | ||||
| 			else { | ||||
| 				nfserr = nfserrno(err); | ||||
| 				goto fail; | ||||
| 			} | ||||
| 			nfserr = nfserrno(PTR_ERR(acl)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if (acl == NULL) { | ||||
| 			/* Solaris returns the inode's minimum ACL. */ | ||||
| 
 | ||||
| 			struct inode *inode = fh->fh_dentry->d_inode; | ||||
| 			acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||||
| 		} | ||||
| 		resp->acl_access = acl; | ||||
|  | @ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, | |||
| 	if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||||
| 		/* Check how Solaris handles requests for the Default ACL
 | ||||
| 		   of a non-directory! */ | ||||
| 
 | ||||
| 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||||
| 		acl = get_acl(inode, ACL_TYPE_DEFAULT); | ||||
| 		if (IS_ERR(acl)) { | ||||
| 			int err = PTR_ERR(acl); | ||||
| 
 | ||||
| 			if (err == -ENODATA || err == -EOPNOTSUPP) | ||||
| 				acl = NULL; | ||||
| 			else { | ||||
| 				nfserr = nfserrno(err); | ||||
| 				goto fail; | ||||
| 			} | ||||
| 			nfserr = nfserrno(PTR_ERR(acl)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		resp->acl_default = acl; | ||||
| 	} | ||||
|  | @ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, | |||
| 		struct nfsd3_setaclargs *argp, | ||||
| 		struct nfsd3_attrstat *resp) | ||||
| { | ||||
| 	struct inode *inode; | ||||
| 	svc_fh *fh; | ||||
| 	__be32 nfserr = 0; | ||||
| 	int error; | ||||
| 
 | ||||
| 	fh = fh_copy(&resp->fh, &argp->fh); | ||||
| 	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); | ||||
| 	if (nfserr) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (!nfserr) { | ||||
| 		nfserr = nfserrno( nfsd_set_posix_acl( | ||||
| 			fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||||
| 	} | ||||
| 	if (!nfserr) { | ||||
| 		nfserr = nfserrno( nfsd_set_posix_acl( | ||||
| 			fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||||
| 	inode = fh->fh_dentry->d_inode; | ||||
| 	if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { | ||||
| 		error = -EOPNOTSUPP; | ||||
| 		goto out_errno; | ||||
| 	} | ||||
| 
 | ||||
| 	error = fh_want_write(fh); | ||||
| 	if (error) | ||||
| 		goto out_errno; | ||||
| 
 | ||||
| 	error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	error = inode->i_op->set_acl(inode, argp->acl_default, | ||||
| 				     ACL_TYPE_DEFAULT); | ||||
| 
 | ||||
| out_drop_write: | ||||
| 	fh_drop_write(fh); | ||||
| out_errno: | ||||
| 	nfserr = nfserrno(error); | ||||
| out: | ||||
| 	/* argp->acl_{access,default} may have been allocated in
 | ||||
| 	   nfs3svc_decode_setaclargs. */ | ||||
| 	posix_acl_release(argp->acl_access); | ||||
|  |  | |||
|  | @ -37,8 +37,13 @@ | |||
| #include <linux/slab.h> | ||||
| #include <linux/nfs_fs.h> | ||||
| #include <linux/export.h> | ||||
| #include "nfsfh.h" | ||||
| #include "acl.h" | ||||
| #include "vfs.h" | ||||
| 
 | ||||
| #define NFS4_ACL_TYPE_DEFAULT	0x01 | ||||
| #define NFS4_ACL_DIR		0x02 | ||||
| #define NFS4_ACL_OWNER		0x04 | ||||
| 
 | ||||
| /* mode bit translations: */ | ||||
| #define NFS4_READ_MODE (NFS4_ACE_READ_DATA) | ||||
|  | @ -130,36 +135,50 @@ static short ace2type(struct nfs4_ace *); | |||
| static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, | ||||
| 				unsigned int); | ||||
| 
 | ||||
| struct nfs4_acl * | ||||
| nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, | ||||
| 			unsigned int flags) | ||||
| int | ||||
| nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, | ||||
| 		struct nfs4_acl **acl) | ||||
| { | ||||
| 	struct nfs4_acl *acl; | ||||
| 	struct inode *inode = dentry->d_inode; | ||||
| 	int error = 0; | ||||
| 	struct posix_acl *pacl = NULL, *dpacl = NULL; | ||||
| 	unsigned int flags = 0; | ||||
| 	int size = 0; | ||||
| 
 | ||||
| 	if (pacl) { | ||||
| 		if (posix_acl_valid(pacl) < 0) | ||||
| 			return ERR_PTR(-EINVAL); | ||||
| 		size += 2*pacl->a_count; | ||||
| 	} | ||||
| 	if (dpacl) { | ||||
| 		if (posix_acl_valid(dpacl) < 0) | ||||
| 			return ERR_PTR(-EINVAL); | ||||
| 		size += 2*dpacl->a_count; | ||||
| 	pacl = get_acl(inode, ACL_TYPE_ACCESS); | ||||
| 	if (!pacl) { | ||||
| 		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||||
| 		if (IS_ERR(pacl)) | ||||
| 			return PTR_ERR(pacl); | ||||
| 		/* allocate for worst case: one (deny, allow) pair each: */ | ||||
| 		size += 2 * pacl->a_count; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Allocate for worst case: one (deny, allow) pair each: */ | ||||
| 	acl = nfs4_acl_new(size); | ||||
| 	if (acl == NULL) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 	if (S_ISDIR(inode->i_mode)) { | ||||
| 		flags = NFS4_ACL_DIR; | ||||
| 		dpacl = get_acl(inode, ACL_TYPE_DEFAULT); | ||||
| 		if (dpacl) | ||||
| 			size += 2 * dpacl->a_count; | ||||
| 	} else { | ||||
| 		dpacl = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	*acl = nfs4_acl_new(size); | ||||
| 	if (*acl == NULL) { | ||||
| 		error = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pacl) | ||||
| 		_posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT); | ||||
| 		_posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); | ||||
| 
 | ||||
| 	if (dpacl) | ||||
| 		_posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT); | ||||
| 		_posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); | ||||
| 
 | ||||
| 	return acl; | ||||
|  out: | ||||
| 	posix_acl_release(pacl); | ||||
| 	posix_acl_release(dpacl); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| struct posix_acl_summary { | ||||
|  | @ -719,8 +738,9 @@ static void process_one_v4_ace(struct posix_acl_state *state, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, | ||||
| 			    struct posix_acl **dpacl, unsigned int flags) | ||||
| static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, | ||||
| 		struct posix_acl **pacl, struct posix_acl **dpacl, | ||||
| 		unsigned int flags) | ||||
| { | ||||
| 	struct posix_acl_state effective_acl_state, default_acl_state; | ||||
| 	struct nfs4_ace *ace; | ||||
|  | @ -780,6 +800,57 @@ out_estate: | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| __be32 | ||||
| nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||
| 		struct nfs4_acl *acl) | ||||
| { | ||||
| 	__be32 error; | ||||
| 	int host_error; | ||||
| 	struct dentry *dentry; | ||||
| 	struct inode *inode; | ||||
| 	struct posix_acl *pacl = NULL, *dpacl = NULL; | ||||
| 	unsigned int flags = 0; | ||||
| 
 | ||||
| 	/* Get inode */ | ||||
| 	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	dentry = fhp->fh_dentry; | ||||
| 	inode = dentry->d_inode; | ||||
| 
 | ||||
| 	if (!inode->i_op->set_acl || !IS_POSIXACL(inode)) | ||||
| 		return nfserr_attrnotsupp; | ||||
| 
 | ||||
| 	if (S_ISDIR(inode->i_mode)) | ||||
| 		flags = NFS4_ACL_DIR; | ||||
| 
 | ||||
| 	host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); | ||||
| 	if (host_error == -EINVAL) | ||||
| 		return nfserr_attrnotsupp; | ||||
| 	if (host_error < 0) | ||||
| 		goto out_nfserr; | ||||
| 
 | ||||
| 	host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS); | ||||
| 	if (host_error < 0) | ||||
| 		goto out_release; | ||||
| 
 | ||||
| 	if (S_ISDIR(inode->i_mode)) { | ||||
| 		host_error = inode->i_op->set_acl(inode, dpacl, | ||||
| 						  ACL_TYPE_DEFAULT); | ||||
| 	} | ||||
| 
 | ||||
| out_release: | ||||
| 	posix_acl_release(pacl); | ||||
| 	posix_acl_release(dpacl); | ||||
| out_nfserr: | ||||
| 	if (host_error == -EOPNOTSUPP) | ||||
| 		return nfserr_attrnotsupp; | ||||
| 	else | ||||
| 		return nfserrno(host_error); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static short | ||||
| ace2type(struct nfs4_ace *ace) | ||||
| { | ||||
|  | @ -798,9 +869,6 @@ ace2type(struct nfs4_ace *ace) | |||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); | ||||
| EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); | ||||
| 
 | ||||
| struct nfs4_acl * | ||||
| nfs4_acl_new(int n) | ||||
| { | ||||
|  | @ -862,7 +930,3 @@ nfs4_acl_write_who(int who, char *p) | |||
| 	BUG(); | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| EXPORT_SYMBOL(nfs4_acl_new); | ||||
| EXPORT_SYMBOL(nfs4_acl_get_whotype); | ||||
| EXPORT_SYMBOL(nfs4_acl_write_who); | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ | |||
| #include "vfs.h" | ||||
| #include "current_stateid.h" | ||||
| #include "netns.h" | ||||
| #include "acl.h" | ||||
| 
 | ||||
| #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||||
| #include <linux/security.h> | ||||
|  |  | |||
							
								
								
									
										241
									
								
								fs/nfsd/vfs.c
									
										
									
									
									
								
							
							
						
						
									
										241
									
								
								fs/nfsd/vfs.c
									
										
									
									
									
								
							|  | @ -468,158 +468,7 @@ out: | |||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || \ | ||||
|     defined(CONFIG_NFSD_V3_ACL) || \ | ||||
|     defined(CONFIG_NFSD_V4) | ||||
| static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) | ||||
| { | ||||
| 	ssize_t buflen; | ||||
| 	ssize_t ret; | ||||
| 
 | ||||
| 	buflen = vfs_getxattr(dentry, key, NULL, 0); | ||||
| 	if (buflen <= 0) | ||||
| 		return buflen; | ||||
| 
 | ||||
| 	*buf = kmalloc(buflen, GFP_KERNEL); | ||||
| 	if (!*buf) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	ret = vfs_getxattr(dentry, key, *buf, buflen); | ||||
| 	if (ret < 0) | ||||
| 		kfree(*buf); | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(CONFIG_NFSD_V4) | ||||
| static int | ||||
| set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) | ||||
| { | ||||
| 	int len; | ||||
| 	size_t buflen; | ||||
| 	char *buf = NULL; | ||||
| 	int error = 0; | ||||
| 
 | ||||
| 	buflen = posix_acl_xattr_size(pacl->a_count); | ||||
| 	buf = kmalloc(buflen, GFP_KERNEL); | ||||
| 	error = -ENOMEM; | ||||
| 	if (buf == NULL) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen); | ||||
| 	if (len < 0) { | ||||
| 		error = len; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	error = vfs_setxattr(dentry, key, buf, len, 0); | ||||
| out: | ||||
| 	kfree(buf); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| __be32 | ||||
| nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||||
|     struct nfs4_acl *acl) | ||||
| { | ||||
| 	__be32 error; | ||||
| 	int host_error; | ||||
| 	struct dentry *dentry; | ||||
| 	struct inode *inode; | ||||
| 	struct posix_acl *pacl = NULL, *dpacl = NULL; | ||||
| 	unsigned int flags = 0; | ||||
| 
 | ||||
| 	/* Get inode */ | ||||
| 	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	dentry = fhp->fh_dentry; | ||||
| 	inode = dentry->d_inode; | ||||
| 	if (S_ISDIR(inode->i_mode)) | ||||
| 		flags = NFS4_ACL_DIR; | ||||
| 
 | ||||
| 	host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); | ||||
| 	if (host_error == -EINVAL) { | ||||
| 		return nfserr_attrnotsupp; | ||||
| 	} else if (host_error < 0) | ||||
| 		goto out_nfserr; | ||||
| 
 | ||||
| 	host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); | ||||
| 	if (host_error < 0) | ||||
| 		goto out_release; | ||||
| 
 | ||||
| 	if (S_ISDIR(inode->i_mode)) | ||||
| 		host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); | ||||
| 
 | ||||
| out_release: | ||||
| 	posix_acl_release(pacl); | ||||
| 	posix_acl_release(dpacl); | ||||
| out_nfserr: | ||||
| 	if (host_error == -EOPNOTSUPP) | ||||
| 		return nfserr_attrnotsupp; | ||||
| 	else | ||||
| 		return nfserrno(host_error); | ||||
| } | ||||
| 
 | ||||
| static struct posix_acl * | ||||
| _get_posix_acl(struct dentry *dentry, char *key) | ||||
| { | ||||
| 	void *buf = NULL; | ||||
| 	struct posix_acl *pacl = NULL; | ||||
| 	int buflen; | ||||
| 
 | ||||
| 	buflen = nfsd_getxattr(dentry, key, &buf); | ||||
| 	if (!buflen) | ||||
| 		buflen = -ENODATA; | ||||
| 	if (buflen <= 0) | ||||
| 		return ERR_PTR(buflen); | ||||
| 
 | ||||
| 	pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen); | ||||
| 	kfree(buf); | ||||
| 	return pacl; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) | ||||
| { | ||||
| 	struct inode *inode = dentry->d_inode; | ||||
| 	int error = 0; | ||||
| 	struct posix_acl *pacl = NULL, *dpacl = NULL; | ||||
| 	unsigned int flags = 0; | ||||
| 
 | ||||
| 	pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); | ||||
| 	if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) | ||||
| 		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||||
| 	if (IS_ERR(pacl)) { | ||||
| 		error = PTR_ERR(pacl); | ||||
| 		pacl = NULL; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (S_ISDIR(inode->i_mode)) { | ||||
| 		dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); | ||||
| 		if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) | ||||
| 			dpacl = NULL; | ||||
| 		else if (IS_ERR(dpacl)) { | ||||
| 			error = PTR_ERR(dpacl); | ||||
| 			dpacl = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		flags = NFS4_ACL_DIR; | ||||
| 	} | ||||
| 
 | ||||
| 	*acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags); | ||||
| 	if (IS_ERR(*acl)) { | ||||
| 		error = PTR_ERR(*acl); | ||||
| 		*acl = NULL; | ||||
| 	} | ||||
|  out: | ||||
| 	posix_acl_release(pacl); | ||||
| 	posix_acl_release(dpacl); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * NFS junction information is stored in an extended attribute. | ||||
|  */ | ||||
|  | @ -2284,93 +2133,3 @@ out_nomem: | |||
| 	nfsd_racache_shutdown(); | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| 
 | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||||
| struct posix_acl * | ||||
| nfsd_get_posix_acl(struct svc_fh *fhp, int type) | ||||
| { | ||||
| 	struct inode *inode = fhp->fh_dentry->d_inode; | ||||
| 	char *name; | ||||
| 	void *value = NULL; | ||||
| 	ssize_t size; | ||||
| 	struct posix_acl *acl; | ||||
| 
 | ||||
| 	if (!IS_POSIXACL(inode)) | ||||
| 		return ERR_PTR(-EOPNOTSUPP); | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case ACL_TYPE_ACCESS: | ||||
| 		name = POSIX_ACL_XATTR_ACCESS; | ||||
| 		break; | ||||
| 	case ACL_TYPE_DEFAULT: | ||||
| 		name = POSIX_ACL_XATTR_DEFAULT; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return ERR_PTR(-EOPNOTSUPP); | ||||
| 	} | ||||
| 
 | ||||
| 	size = nfsd_getxattr(fhp->fh_dentry, name, &value); | ||||
| 	if (size < 0) | ||||
| 		return ERR_PTR(size); | ||||
| 
 | ||||
| 	acl = posix_acl_from_xattr(&init_user_ns, value, size); | ||||
| 	kfree(value); | ||||
| 	return acl; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | ||||
| { | ||||
| 	struct inode *inode = fhp->fh_dentry->d_inode; | ||||
| 	char *name; | ||||
| 	void *value = NULL; | ||||
| 	size_t size; | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (!IS_POSIXACL(inode) || | ||||
| 	    !inode->i_op->setxattr || !inode->i_op->removexattr) | ||||
| 		return -EOPNOTSUPP; | ||||
| 	switch(type) { | ||||
| 		case ACL_TYPE_ACCESS: | ||||
| 			name = POSIX_ACL_XATTR_ACCESS; | ||||
| 			break; | ||||
| 		case ACL_TYPE_DEFAULT: | ||||
| 			name = POSIX_ACL_XATTR_DEFAULT; | ||||
| 			break; | ||||
| 		default: | ||||
| 			return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	if (acl && acl->a_count) { | ||||
| 		size = posix_acl_xattr_size(acl->a_count); | ||||
| 		value = kmalloc(size, GFP_KERNEL); | ||||
| 		if (!value) | ||||
| 			return -ENOMEM; | ||||
| 		error = posix_acl_to_xattr(&init_user_ns, acl, value, size); | ||||
| 		if (error < 0) | ||||
| 			goto getout; | ||||
| 		size = error; | ||||
| 	} else | ||||
| 		size = 0; | ||||
| 
 | ||||
| 	error = fh_want_write(fhp); | ||||
| 	if (error) | ||||
| 		goto getout; | ||||
| 	if (size) | ||||
| 		error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); | ||||
| 	else { | ||||
| 		if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) | ||||
| 			error = 0; | ||||
| 		else { | ||||
| 			error = vfs_removexattr(fhp->fh_dentry, name); | ||||
| 			if (error == -ENODATA) | ||||
| 				error = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	fh_drop_write(fhp); | ||||
| 
 | ||||
| getout: | ||||
| 	kfree(value); | ||||
| 	return error; | ||||
| } | ||||
| #endif  /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | ||||
|  |  | |||
|  | @ -52,9 +52,6 @@ __be32		nfsd_setattr(struct svc_rqst *, struct svc_fh *, | |||
| 				struct iattr *, int, time_t); | ||||
| int nfsd_mountpoint(struct dentry *, struct svc_export *); | ||||
| #ifdef CONFIG_NFSD_V4 | ||||
| __be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, | ||||
|                     struct nfs4_acl *); | ||||
| int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); | ||||
| __be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, | ||||
| 		    struct xdr_netobj *); | ||||
| #endif /* CONFIG_NFSD_V4 */ | ||||
|  | @ -101,11 +98,6 @@ __be32		nfsd_statfs(struct svc_rqst *, struct svc_fh *, | |||
| __be32		nfsd_permission(struct svc_rqst *, struct svc_export *, | ||||
| 				struct dentry *, int); | ||||
| 
 | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||||
| struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | ||||
| int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); | ||||
| #endif | ||||
| 
 | ||||
| static inline int fh_want_write(struct svc_fh *fh) | ||||
| { | ||||
| 	int ret = mnt_want_write(fh->fh_export->ex_path.mnt); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Christoph Hellwig
				Christoph Hellwig