Commit 4ac7249e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Al Viro

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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent feda821e
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
#ifndef LINUX_NFS4_ACL_H #ifndef LINUX_NFS4_ACL_H
#define 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 /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
* fit in a page: */ * fit in a page: */
...@@ -45,13 +47,9 @@ struct nfs4_acl *nfs4_acl_new(int); ...@@ -45,13 +47,9 @@ struct nfs4_acl *nfs4_acl_new(int);
int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_get_whotype(char *, u32);
int nfs4_acl_write_who(int who, char *p); int nfs4_acl_write_who(int who, char *p);
#define NFS4_ACL_TYPE_DEFAULT 0x01 int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
#define NFS4_ACL_DIR 0x02 struct nfs4_acl **acl);
#define NFS4_ACL_OWNER 0x04 __be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfs4_acl *acl);
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);
#endif /* LINUX_NFS4_ACL_H */ #endif /* LINUX_NFS4_ACL_H */
...@@ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) ...@@ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
{ {
svc_fh *fh;
struct posix_acl *acl; struct posix_acl *acl;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0; __be32 nfserr = 0;
dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
...@@ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, ...@@ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
if (nfserr) if (nfserr)
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
inode = fh->fh_dentry->d_inode;
if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
RETURN_STATUS(nfserr_inval); RETURN_STATUS(nfserr_inval);
resp->mask = argp->mask; resp->mask = argp->mask;
...@@ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, ...@@ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
goto fail; goto fail;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 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)) { if (IS_ERR(acl)) {
int err = PTR_ERR(acl); nfserr = nfserrno(PTR_ERR(acl));
goto fail;
if (err == -ENODATA || err == -EOPNOTSUPP)
acl = NULL;
else {
nfserr = nfserrno(err);
goto fail;
}
} }
if (acl == NULL) { if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */ /* 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); acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
} }
resp->acl_access = acl; resp->acl_access = acl;
...@@ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, ...@@ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL /* Check how Solaris handles requests for the Default ACL
of a non-directory! */ of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
int err = PTR_ERR(acl); nfserr = nfserrno(PTR_ERR(acl));
goto fail;
if (err == -ENODATA || err == -EOPNOTSUPP)
acl = NULL;
else {
nfserr = nfserrno(err);
goto fail;
}
} }
resp->acl_default = acl; resp->acl_default = acl;
} }
...@@ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, ...@@ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
struct nfsd3_setaclargs *argp, struct nfsd3_setaclargs *argp,
struct nfsd_attrstat *resp) struct nfsd_attrstat *resp)
{ {
struct inode *inode;
svc_fh *fh; svc_fh *fh;
__be32 nfserr = 0; __be32 nfserr = 0;
int error;
dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
fh = fh_copy(&resp->fh, &argp->fh); fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (nfserr)
goto out;
if (!nfserr) { inode = fh->fh_dentry->d_inode;
nfserr = nfserrno( nfsd_set_posix_acl( if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
fh, ACL_TYPE_ACCESS, argp->acl_access) ); error = -EOPNOTSUPP;
} goto out_errno;
if (!nfserr) {
nfserr = nfserrno( nfsd_set_posix_acl(
fh, ACL_TYPE_DEFAULT, argp->acl_default) );
}
if (!nfserr) {
nfserr = fh_getattr(fh, &resp->stat);
} }
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 /* argp->acl_{access,default} may have been allocated in
nfssvc_decode_setaclargs. */ nfssvc_decode_setaclargs. */
posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default); posix_acl_release(argp->acl_default);
return nfserr; 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) ...@@ -29,8 +29,9 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
{ {
svc_fh *fh;
struct posix_acl *acl; struct posix_acl *acl;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0; __be32 nfserr = 0;
fh = fh_copy(&resp->fh, &argp->fh); fh = fh_copy(&resp->fh, &argp->fh);
...@@ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, ...@@ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
if (nfserr) if (nfserr)
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
inode = fh->fh_dentry->d_inode;
if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
RETURN_STATUS(nfserr_inval); RETURN_STATUS(nfserr_inval);
resp->mask = argp->mask; resp->mask = argp->mask;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 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)) { if (IS_ERR(acl)) {
int err = PTR_ERR(acl); nfserr = nfserrno(PTR_ERR(acl));
goto fail;
if (err == -ENODATA || err == -EOPNOTSUPP)
acl = NULL;
else {
nfserr = nfserrno(err);
goto fail;
}
} }
if (acl == NULL) { if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */ /* 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); acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
} }
resp->acl_access = acl; resp->acl_access = acl;
...@@ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, ...@@ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL /* Check how Solaris handles requests for the Default ACL
of a non-directory! */ of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
int err = PTR_ERR(acl); nfserr = nfserrno(PTR_ERR(acl));
goto fail;
if (err == -ENODATA || err == -EOPNOTSUPP)
acl = NULL;
else {
nfserr = nfserrno(err);
goto fail;
}
} }
resp->acl_default = acl; resp->acl_default = acl;
} }
...@@ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, ...@@ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
struct nfsd3_setaclargs *argp, struct nfsd3_setaclargs *argp,
struct nfsd3_attrstat *resp) struct nfsd3_attrstat *resp)
{ {
struct inode *inode;
svc_fh *fh; svc_fh *fh;
__be32 nfserr = 0; __be32 nfserr = 0;
int error;
fh = fh_copy(&resp->fh, &argp->fh); fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (nfserr)
goto out;
if (!nfserr) { inode = fh->fh_dentry->d_inode;
nfserr = nfserrno( nfsd_set_posix_acl( if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
fh, ACL_TYPE_ACCESS, argp->acl_access) ); error = -EOPNOTSUPP;
} goto out_errno;
if (!nfserr) {
nfserr = nfserrno( nfsd_set_posix_acl(
fh, ACL_TYPE_DEFAULT, argp->acl_default) );
} }
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 /* argp->acl_{access,default} may have been allocated in
nfs3svc_decode_setaclargs. */ nfs3svc_decode_setaclargs. */
posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_access);
......
...@@ -37,8 +37,13 @@ ...@@ -37,8 +37,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/export.h> #include <linux/export.h>
#include "nfsfh.h"
#include "acl.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: */ /* mode bit translations: */
#define NFS4_READ_MODE (NFS4_ACE_READ_DATA) #define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
...@@ -130,36 +135,50 @@ static short ace2type(struct nfs4_ace *); ...@@ -130,36 +135,50 @@ static short ace2type(struct nfs4_ace *);
static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
unsigned int); unsigned int);
struct nfs4_acl * int
nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
unsigned int flags) 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; int size = 0;
if (pacl) { pacl = get_acl(inode, ACL_TYPE_ACCESS);
if (posix_acl_valid(pacl) < 0) if (!pacl) {
return ERR_PTR(-EINVAL); pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
size += 2*pacl->a_count; if (IS_ERR(pacl))
return PTR_ERR(pacl);
/* allocate for worst case: one (deny, allow) pair each: */
size += 2 * pacl->a_count;
} }
if (dpacl) {
if (posix_acl_valid(dpacl) < 0) if (S_ISDIR(inode->i_mode)) {
return ERR_PTR(-EINVAL); flags = NFS4_ACL_DIR;
size += 2*dpacl->a_count; dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
if (dpacl)
size += 2 * dpacl->a_count;
} else {
dpacl = NULL;
} }
/* Allocate for worst case: one (deny, allow) pair each: */ *acl = nfs4_acl_new(size);
acl = nfs4_acl_new(size); if (*acl == NULL) {
if (acl == NULL) error = -ENOMEM;
return ERR_PTR(-ENOMEM); goto out;
}
if (pacl) 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) 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 { struct posix_acl_summary {
...@@ -719,8 +738,9 @@ static void process_one_v4_ace(struct posix_acl_state *state, ...@@ -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, static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
struct posix_acl **dpacl, unsigned int flags) struct posix_acl **pacl, struct posix_acl **dpacl,
unsigned int flags)
{ {
struct posix_acl_state effective_acl_state, default_acl_state; struct posix_acl_state effective_acl_state, default_acl_state;
struct nfs4_ace *ace; struct nfs4_ace *ace;
...@@ -780,6 +800,57 @@ out_estate: ...@@ -780,6 +800,57 @@ out_estate:
return ret; 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 static short
ace2type(struct nfs4_ace *ace) ace2type(struct nfs4_ace *ace)
{ {
...@@ -798,9 +869,6 @@ ace2type(struct nfs4_ace *ace) ...@@ -798,9 +869,6 @@ ace2type(struct nfs4_ace *ace)
return -1; return -1;
} }
EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
struct nfs4_acl * struct nfs4_acl *
nfs4_acl_new(int n) nfs4_acl_new(int n)
{ {
...@@ -862,7 +930,3 @@ nfs4_acl_write_who(int who, char *p) ...@@ -862,7 +930,3 @@ nfs4_acl_write_who(int who, char *p)
BUG(); BUG();
return -1; return -1;
} }
EXPORT_SYMBOL(nfs4_acl_new);
EXPORT_SYMBOL(nfs4_acl_get_whotype);
EXPORT_SYMBOL(nfs4_acl_write_who);
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "vfs.h" #include "vfs.h"
#include "current_stateid.h" #include "current_stateid.h"
#include "netns.h" #include "netns.h"
#include "acl.h"
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
#include <linux/security.h> #include <linux/security.h>
......
...@@ -468,158 +468,7 @@ out: ...@@ -468,158 +468,7 @@ out:
return err; 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) #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. * NFS junction information is stored in an extended attribute.
*/ */
...@@ -2284,93 +2133,3 @@ out_nomem: ...@@ -2284,93 +2133,3 @@ out_nomem:
nfsd_racache_shutdown(); nfsd_racache_shutdown();
return -ENOMEM; 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);