[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>
This commit is contained in:
Andreas Gruenbacher
2005-06-22 17:16:26 +00:00
committed by Trond Myklebust
parent 9ba02638e4
commit a257cdd0e2
16 changed files with 1166 additions and 1 deletions

View File

@@ -46,8 +46,9 @@
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
#include <linux/dnotify.h>
#ifdef CONFIG_NFSD_V4
#include <linux/xattr_acl.h>
#include <linux/posix_acl.h>
#ifdef CONFIG_NFSD_V4
#include <linux/posix_acl_xattr.h>
#include <linux/xattr_acl.h>
#include <linux/xattr.h>
@@ -1857,3 +1858,107 @@ nfsd_racache_init(int cache_size)
nfsdstats.ra_size = cache_size;
return 0;
}
#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) || !inode->i_op || !inode->i_op->getxattr)
return ERR_PTR(-EOPNOTSUPP);
switch(type) {
case ACL_TYPE_ACCESS:
name = XATTR_NAME_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
name = XATTR_NAME_ACL_DEFAULT;
break;
default:
return ERR_PTR(-EOPNOTSUPP);
}
size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
if (size < 0) {
acl = ERR_PTR(size);
goto getout;
} else if (size > 0) {
value = kmalloc(size, GFP_KERNEL);
if (!value) {
acl = ERR_PTR(-ENOMEM);
goto getout;
}
size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
if (size < 0) {
acl = ERR_PTR(size);
goto getout;
}
}
acl = posix_acl_from_xattr(value, size);
getout:
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 ||
!inode->i_op->setxattr || !inode->i_op->removexattr)
return -EOPNOTSUPP;
switch(type) {
case ACL_TYPE_ACCESS:
name = XATTR_NAME_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
name = XATTR_NAME_ACL_DEFAULT;
break;
default:
return -EOPNOTSUPP;
}
if (acl && acl->a_count) {
size = xattr_acl_size(acl->a_count);
value = kmalloc(size, GFP_KERNEL);
if (!value)
return -ENOMEM;
size = posix_acl_to_xattr(acl, value, size);
if (size < 0) {
error = size;
goto getout;
}
} else
size = 0;
if (!fhp->fh_locked)
fh_lock(fhp); /* unlocking is done automatically */
if (size)
error = inode->i_op->setxattr(fhp->fh_dentry, name,
value, size, 0);
else {
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
error = 0;
else {
error = inode->i_op->removexattr(fhp->fh_dentry, name);
if (error == -ENODATA)
error = 0;
}
}
getout:
kfree(value);
return error;
}
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */