Commit b7fa0554 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Trond Myklebust

[PATCH] NFS: Add support for NFSv3 ACLs

 This adds acl support fo nfs clients via the NFSACL protocol extension, by
 implementing the getxattr, listxattr, setxattr, and removexattr iops for the
 system.posix_acl_access and system.posix_acl_default attributes.  This patch
 implements a dumb version that uses no caching (and thus adds some overhead).
 (Another patch in this patchset adds caching as well.)
Signed-off-by: default avatarAndreas Gruenbacher <agruen@suse.de>
Acked-by: default avatarOlaf Kirch <okir@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a257cdd0
...@@ -1268,6 +1268,7 @@ config NFS_FS ...@@ -1268,6 +1268,7 @@ config NFS_FS
depends on INET depends on INET
select LOCKD select LOCKD
select SUNRPC select SUNRPC
select NFS_ACL_SUPPORT if NFS_V3_ACL
help help
If you are connected to some other (usually local) Unix computer If you are connected to some other (usually local) Unix computer
(using SLIP, PLIP, PPP or Ethernet) and want to mount files residing (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
...@@ -1310,6 +1311,16 @@ config NFS_V3 ...@@ -1310,6 +1311,16 @@ config NFS_V3
If unsure, say Y. If unsure, say Y.
config NFS_V3_ACL
bool "Provide client support for the NFSv3 ACL protocol extension"
depends on NFS_V3
help
Implement the NFSv3 ACL protocol extension for manipulating POSIX
Access Control Lists. The server should also be compiled with
the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.
If unsure, say N.
config NFS_V4 config NFS_V4
bool "Provide NFSv4 client support (EXPERIMENTAL)" bool "Provide NFSv4 client support (EXPERIMENTAL)"
depends on NFS_FS && EXPERIMENTAL depends on NFS_FS && EXPERIMENTAL
......
...@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ ...@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o proc.o read.o symlink.o unlink.o write.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \ delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o callback.o callback_xdr.o callback_proc.o
......
...@@ -75,6 +75,27 @@ struct inode_operations nfs_dir_inode_operations = { ...@@ -75,6 +75,27 @@ struct inode_operations nfs_dir_inode_operations = {
.setattr = nfs_setattr, .setattr = nfs_setattr,
}; };
#ifdef CONFIG_NFS_V3
struct inode_operations nfs3_dir_inode_operations = {
.create = nfs_create,
.lookup = nfs_lookup,
.link = nfs_link,
.unlink = nfs_unlink,
.symlink = nfs_symlink,
.mkdir = nfs_mkdir,
.rmdir = nfs_rmdir,
.mknod = nfs_mknod,
.rename = nfs_rename,
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
.listxattr = nfs3_listxattr,
.getxattr = nfs3_getxattr,
.setxattr = nfs3_setxattr,
.removexattr = nfs3_removexattr,
};
#endif /* CONFIG_NFS_V3 */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
......
...@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = { ...@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = {
.setattr = nfs_setattr, .setattr = nfs_setattr,
}; };
#ifdef CONFIG_NFS_V3
struct inode_operations nfs3_file_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
.listxattr = nfs3_listxattr,
.getxattr = nfs3_getxattr,
.setxattr = nfs3_setxattr,
.removexattr = nfs3_removexattr,
};
#endif /* CONFIG_NFS_v3 */
/* Hack for future NFS swap support */ /* Hack for future NFS swap support */
#ifndef IS_SWAPFILE #ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0) # define IS_SWAPFILE(inode) (0)
......
...@@ -108,6 +108,21 @@ static struct rpc_program nfs_program = { ...@@ -108,6 +108,21 @@ static struct rpc_program nfs_program = {
.pipe_dir_name = "/nfs", .pipe_dir_name = "/nfs",
}; };
#ifdef CONFIG_NFS_V3_ACL
static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
static struct rpc_version * nfsacl_version[] = {
[3] = &nfsacl_version3,
};
struct rpc_program nfsacl_program = {
.name = "nfsacl",
.number = NFS_ACL_PROGRAM,
.nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]),
.version = nfsacl_version,
.stats = &nfsacl_rpcstat,
};
#endif /* CONFIG_NFS_V3_ACL */
static inline unsigned long static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr) nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
{ {
...@@ -165,6 +180,9 @@ nfs_umount_begin(struct super_block *sb) ...@@ -165,6 +180,9 @@ nfs_umount_begin(struct super_block *sb)
/* -EIO all pending I/O */ /* -EIO all pending I/O */
if (!IS_ERR(rpc)) if (!IS_ERR(rpc))
rpc_killall_tasks(rpc); rpc_killall_tasks(rpc);
rpc = NFS_SB(sb)->client_acl;
if (!IS_ERR(rpc))
rpc_killall_tasks(rpc);
} }
...@@ -461,8 +479,17 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) ...@@ -461,8 +479,17 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
atomic_inc(&server->client->cl_count); atomic_inc(&server->client->cl_count);
server->client_sys = server->client; server->client_sys = server->client;
} }
if (server->flags & NFS_MOUNT_VER3) { if (server->flags & NFS_MOUNT_VER3) {
#ifdef CONFIG_NFS_V3_ACL
if (!(server->flags & NFS_MOUNT_NOACL)) {
server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
/* No errors! Assume that Sun nfsacls are supported */
if (!IS_ERR(server->client_acl))
server->caps |= NFS_CAP_ACLS;
}
#else
server->flags &= ~NFS_MOUNT_NOACL;
#endif /* CONFIG_NFS_V3_ACL */
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN; server->namelen = NFS3_MAXNAMLEN;
sb->s_time_gran = 1; sb->s_time_gran = 1;
...@@ -546,6 +573,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -546,6 +573,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
{ NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" },
{ NFS_MOUNT_NOACL, ",noacl", "" },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
struct proc_nfs_info *nfs_infop; struct proc_nfs_info *nfs_infop;
...@@ -1452,7 +1480,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, ...@@ -1452,7 +1480,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
memset(server, 0, sizeof(struct nfs_server)); memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */ /* Zero out the NFS state stuff */
init_nfsv4_state(server); init_nfsv4_state(server);
server->client = server->client_sys = ERR_PTR(-EINVAL); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
root = &server->fh; root = &server->fh;
if (data->flags & NFS_MOUNT_VER3) if (data->flags & NFS_MOUNT_VER3)
...@@ -1513,6 +1541,8 @@ static void nfs_kill_super(struct super_block *s) ...@@ -1513,6 +1541,8 @@ static void nfs_kill_super(struct super_block *s)
rpc_shutdown_client(server->client); rpc_shutdown_client(server->client);
if (!IS_ERR(server->client_sys)) if (!IS_ERR(server->client_sys))
rpc_shutdown_client(server->client_sys); rpc_shutdown_client(server->client_sys);
if (!IS_ERR(server->client_acl))
rpc_shutdown_client(server->client_acl);
if (!(server->flags & NFS_MOUNT_NONLM)) if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */ lockd_down(); /* release rpc.lockd */
...@@ -1794,7 +1824,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, ...@@ -1794,7 +1824,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
memset(server, 0, sizeof(struct nfs_server)); memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */ /* Zero out the NFS state stuff */
init_nfsv4_state(server); init_nfsv4_state(server);
server->client = server->client_sys = ERR_PTR(-EINVAL); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
p = nfs_copy_user_string(NULL, &data->hostname, 256); p = nfs_copy_user_string(NULL, &data->hostname, 256);
if (IS_ERR(p)) if (IS_ERR(p))
......
#include <linux/fs.h>
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/xattr_acl.h>
#include <linux/nfsacl.h>
#define NFSDBG_FACILITY NFSDBG_PROC
ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct inode *inode = dentry->d_inode;
struct posix_acl *acl;
int pos=0, len=0;
# define output(s) do { \
if (pos + sizeof(s) <= size) { \
memcpy(buffer + pos, s, sizeof(s)); \
pos += sizeof(s); \
} \
len += sizeof(s); \
} while(0)
acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
output("system.posix_acl_access");
posix_acl_release(acl);
}
if (S_ISDIR(inode->i_mode)) {
acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
output("system.posix_acl_default");
posix_acl_release(acl);
}
}
# undef output
if (!buffer || len <= size)
return len;
return -ERANGE;
}
ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size)
{
struct inode *inode = dentry->d_inode;
struct posix_acl *acl;
int type, error = 0;
if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
acl = nfs3_proc_getacl(inode, type);
if (IS_ERR(acl))
return PTR_ERR(acl);
else if (acl) {
if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
error = -ENODATA;
else
error = posix_acl_to_xattr(acl, buffer, size);
posix_acl_release(acl);
} else
error = -ENODATA;
return error;
}
int nfs3_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
struct posix_acl *acl;
int type, error;
if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
acl = posix_acl_from_xattr(value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
error = nfs3_proc_setacl(inode, type, acl);
posix_acl_release(acl);
return error;
}
int nfs3_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int type;
if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
return nfs3_proc_setacl(inode, type, NULL);
}
struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_fattr fattr;
struct page *pages[NFSACL_MAXPAGES] = { };
struct nfs3_getaclargs args = {
.fh = NFS_FH(inode),
/* The xdr layer may allocate pages here. */
.pages = pages,
};
struct nfs3_getaclres res = {
.fattr = &fattr,
};
struct posix_acl *acl = NULL;
int status, count;
if (!nfs_server_capable(inode, NFS_CAP_ACLS))
return ERR_PTR(-EOPNOTSUPP);
switch (type) {
case ACL_TYPE_ACCESS:
args.mask = NFS_ACLCNT|NFS_ACL;
break;
case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode))
return NULL;
args.mask = NFS_DFACLCNT|NFS_DFACL;
break;
default:
return ERR_PTR(-EINVAL);
}
dprintk("NFS call getacl\n");
status = rpc_call(server->client_acl, ACLPROC3_GETACL,
&args, &res, 0);
dprintk("NFS reply getacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */
for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
__free_page(args.pages[count]);
switch (status) {
case 0:
status = nfs_refresh_inode(inode, &fattr);
break;
case -EPFNOSUPPORT:
case -EPROTONOSUPPORT:
dprintk("NFS_V3_ACL extension not supported; disabling\n");
server->caps &= ~NFS_CAP_ACLS;
case -ENOTSUPP:
status = -EOPNOTSUPP;
default:
goto getout;
}
if ((args.mask & res.mask) != args.mask) {
status = -EIO;
goto getout;
}
if (res.acl_access != NULL) {
if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {
posix_acl_release(res.acl_access);
res.acl_access = NULL;
}
}
switch(type) {
case ACL_TYPE_ACCESS:
acl = res.acl_access;
res.acl_access = NULL;
break;
case ACL_TYPE_DEFAULT:
acl = res.acl_default;
res.acl_default = NULL;
}
getout:
posix_acl_release(res.acl_access);
posix_acl_release(res.acl_default);
if (status != 0) {
posix_acl_release(acl);
acl = ERR_PTR(status);
}
return acl;
}
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,
};
int status, count;
status = -EOPNOTSUPP;
if (!nfs_server_capable(inode, NFS_CAP_ACLS))
goto out;
/* We are doing this here, because XDR marshalling can only
return -ENOMEM. */
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;
}
dprintk("NFS call setacl\n");
nfs_begin_data_update(inode);
status = rpc_call(server->client_acl, ACLPROC3_SETACL,
&args, &fattr, 0);
NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
nfs_end_data_update(inode);
dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */
for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
__free_page(args.pages[count]);
switch (status) {
case 0:
status = nfs_refresh_inode(inode, &fattr);
break;
case -EPFNOSUPPORT:
case -EPROTONOSUPPORT:
dprintk("NFS_V3_ACL SETACL RPC not supported"
"(will not retry)\n");
server->caps &= ~NFS_CAP_ACLS;
case -ENOTSUPP:
status = -EOPNOTSUPP;
}
out:
return status;
}
int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
{
struct posix_acl *alloc = NULL, *dfacl = NULL;
int status;
if (S_ISDIR(inode->i_mode)) {
switch(type) {
case ACL_TYPE_ACCESS:
alloc = dfacl = nfs3_proc_getacl(inode,
ACL_TYPE_DEFAULT);
if (IS_ERR(alloc))
goto fail;
break;
case ACL_TYPE_DEFAULT:
dfacl = acl;
alloc = acl = nfs3_proc_getacl(inode,
ACL_TYPE_ACCESS);
if (IS_ERR(alloc))
goto fail;
break;
default:
return -EINVAL;
}
} else if (type != ACL_TYPE_ACCESS)
return -EINVAL;
if (acl == NULL) {
alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
if (IS_ERR(alloc))
goto fail;
}
status = nfs3_proc_setacls(inode, acl, dfacl);
posix_acl_release(alloc);
return status;
fail:
return PTR_ERR(alloc);
}
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <linux/lockd/bind.h> #include <linux/lockd/bind.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/nfs_mount.h>
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
...@@ -45,7 +46,7 @@ static inline int ...@@ -45,7 +46,7 @@ static inline int
nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
{ {
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[proc], .rpc_proc = &clnt->cl_procinfo[proc],
.rpc_argp = argp, .rpc_argp = argp,
.rpc_resp = resp, .rpc_resp = resp,
}; };
...@@ -825,8 +826,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -825,8 +826,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
struct nfs_rpc_ops nfs_v3_clientops = { struct nfs_rpc_ops nfs_v3_clientops = {
.version = 3, /* protocol version */ .version = 3, /* protocol version */
.dentry_ops = &nfs_dentry_operations, .dentry_ops = &nfs_dentry_operations,
.dir_inode_ops = &nfs_dir_inode_operations, .dir_inode_ops = &nfs3_dir_inode_operations,
.file_inode_ops = &nfs_file_inode_operations, .file_inode_ops = &nfs3_file_inode_operations,
.getroot = nfs3_proc_get_root, .getroot = nfs3_proc_get_root,
.getattr = nfs3_proc_getattr, .getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr, .setattr = nfs3_proc_setattr,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/nfs.h> #include <linux/nfs.h>
#include <linux/nfs3.h> #include <linux/nfs3.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfsacl.h>
#define NFSDBG_FACILITY NFSDBG_XDR #define NFSDBG_FACILITY NFSDBG_XDR
...@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int); ...@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int);
#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
/* /*
* Map file type to S_IFMT bits * Map file type to S_IFMT bits
*/ */
...@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) ...@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
return 0; return 0;
} }
#ifdef CONFIG_NFS_V3_ACL
/*
* Encode GETACL arguments
*/
static int
nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
struct nfs3_getaclargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->mask);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
if (args->mask & (NFS_ACL | NFS_DFACL)) {
/* Inline the page array */
replen = (RPC_REPHDRSIZE + auth->au_rslack +
ACL3_getaclres_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
NFSACL_MAXPAGES << PAGE_SHIFT);
}
return 0;
}
/*
* Encode SETACL arguments
*/
static int
nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
struct nfs3_setaclargs *args)
{
struct xdr_buf *buf = &req->rq_snd_buf;
unsigned int base, len_in_head, len = nfsacl_size(
(args->mask & NFS_ACL) ? args->acl_access : NULL,
(args->mask & NFS_DFACL) ? args->acl_default : NULL);
int count, err;
p = xdr_encode_fhandle(p, NFS_FH(args->inode));
*p++ = htonl(args->mask);
base = (char *)p - (char *)buf->head->iov_base;
/* put as much of the acls into head as possible. */
len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
len -= len_in_head;
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + len_in_head);
for (count = 0; (count << PAGE_SHIFT) < len; count++) {
args->pages[count] = alloc_page(GFP_KERNEL);
if (!args->pages[count]) {
while (count)
__free_page(args->pages[--count]);
return -ENOMEM;
}
}
xdr_encode_pages(buf, args->pages, 0, len);
err = nfsacl_encode(buf, base, args->inode,
(args->mask & NFS_ACL) ?
args->acl_access : NULL, 1, 0);
if (err > 0)
err = nfsacl_encode(buf, base + err, args->inode,
(args->mask & NFS_DFACL) ?
args->acl_default : NULL, 1,
NFS_ACL_DEFAULT);
return (err > 0) ? 0 : err;
}
#endif /* CONFIG_NFS_V3_ACL */
/* /*
* NFS XDR decode functions * NFS XDR decode functions
*/ */
...@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) ...@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
return 0; return 0;
} }
#ifdef CONFIG_NFS_V3_ACL
/*
* Decode GETACL reply
*/
static int
nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
struct nfs3_getaclres *res)
{
struct xdr_buf *buf = &req->rq_rcv_buf;
int status = ntohl(*p++);
struct posix_acl **acl;
unsigned int *aclcnt;
int err, base;
if (status != 0)
return -nfs_stat_to_errno(status);
p = xdr_decode_post_op_attr(p, res->fattr);
res->mask = ntohl(*p++);
if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
return -EINVAL;
base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
err = nfsacl_decode(buf, base, aclcnt, acl);
acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
if (err > 0)
err = nfsacl_decode(buf, base + err, aclcnt, acl);
return (err > 0) ? 0 : err;
}
/*
* Decode setacl reply.
*/
static int
nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
{
int status = ntohl(*p++);
if (status)
return -nfs_stat_to_errno(status);
xdr_decode_post_op_attr(p, fattr);
return 0;
}
#endif /* CONFIG_NFS_V3_ACL */
#ifndef MAX #ifndef MAX
# define MAX(a, b) (((a) > (b))? (a) : (b)) # define MAX(a, b) (((a) > (b))? (a) : (b))
#endif #endif
...@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = { ...@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = {
.procs = nfs3_procedures .procs = nfs3_procedures
}; };
#ifdef CONFIG_NFS_V3_ACL
static struct rpc_procinfo nfs3_acl_procedures[] = {
[ACLPROC3_GETACL] = {
.p_proc = ACLPROC3_GETACL,
.p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
.p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
.p_timer = 1,
},
[ACLPROC3_SETACL] = {
.p_proc = ACLPROC3_SETACL,
.p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
.p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
.p_timer = 0,
},
};
struct rpc_version nfsacl_version3 = {
.number = 3,
.nrprocs = sizeof(nfs3_acl_procedures)/
sizeof(nfs3_acl_procedures[0]),
.procs = nfs3_acl_procedures,
};
#endif /* CONFIG_NFS_V3_ACL */
...@@ -124,6 +124,7 @@ enum { ...@@ -124,6 +124,7 @@ enum {
Opt_soft, Opt_hard, Opt_intr, Opt_soft, Opt_hard, Opt_intr,
Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
Opt_acl, Opt_noacl,
/* Error token */ /* Error token */
Opt_err Opt_err
}; };
...@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = { ...@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = {
{Opt_udp, "udp"}, {Opt_udp, "udp"},
{Opt_tcp, "proto=tcp"}, {Opt_tcp, "proto=tcp"},
{Opt_tcp, "tcp"}, {Opt_tcp, "tcp"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf) ...@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf)
case Opt_tcp: case Opt_tcp:
nfs_data.flags |= NFS_MOUNT_TCP; nfs_data.flags |= NFS_MOUNT_TCP;
break; break;
case Opt_acl:
nfs_data.flags &= ~NFS_MOUNT_NOACL;
break;
case Opt_noacl:
nfs_data.flags |= NFS_MOUNT_NOACL;
break;
default : default :
return 0; return 0;
} }
......
...@@ -301,6 +301,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/ ...@@ -301,6 +301,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/
* linux/fs/nfs/file.c * linux/fs/nfs/file.c
*/ */
extern struct inode_operations nfs_file_inode_operations; extern struct inode_operations nfs_file_inode_operations;
#ifdef CONFIG_NFS_V3
extern struct inode_operations nfs3_file_inode_operations;
#endif /* CONFIG_NFS_V3 */
extern struct file_operations nfs_file_operations; extern struct file_operations nfs_file_operations;
extern struct address_space_operations nfs_file_aops; extern struct address_space_operations nfs_file_aops;
...@@ -315,6 +318,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file) ...@@ -315,6 +318,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file)
return NULL; return NULL;
} }
/*
* linux/fs/nfs/xattr.c
*/
#ifdef CONFIG_NFS_V3_ACL
extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t);
extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t);
extern int nfs3_setxattr(struct dentry *, const char *,
const void *, size_t, int);
extern int nfs3_removexattr (struct dentry *, const char *name);
#else
# define nfs3_listxattr NULL
# define nfs3_getxattr NULL
# define nfs3_setxattr NULL
# define nfs3_removexattr NULL
#endif
/* /*
* linux/fs/nfs/direct.c * linux/fs/nfs/direct.c
*/ */
...@@ -329,6 +348,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, ...@@ -329,6 +348,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
* linux/fs/nfs/dir.c * linux/fs/nfs/dir.c
*/ */
extern struct inode_operations nfs_dir_inode_operations; extern struct inode_operations nfs_dir_inode_operations;
#ifdef CONFIG_NFS_V3
extern struct inode_operations nfs3_dir_inode_operations;
#endif /* CONFIG_NFS_V3 */
extern struct file_operations nfs_dir_operations; extern struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations; extern struct dentry_operations nfs_dentry_operations;
...@@ -449,6 +471,15 @@ static inline void nfs_readdata_free(struct nfs_read_data *p) ...@@ -449,6 +471,15 @@ static inline void nfs_readdata_free(struct nfs_read_data *p)
extern void nfs_readdata_release(struct rpc_task *task); extern void nfs_readdata_release(struct rpc_task *task);
/*
* linux/fs/nfs3proc.c
*/
#ifdef CONFIG_NFS_V3_ACL
extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
extern int nfs3_proc_setacl(struct inode *inode, int type,
struct posix_acl *acl);
#endif /* CONFIG_NFS_V3_ACL */
/* /*
* linux/fs/mount_clnt.c * linux/fs/mount_clnt.c
* (Used only by nfsroot module) * (Used only by nfsroot module)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
struct nfs_server { struct nfs_server {
struct rpc_clnt * client; /* RPC client handle */ struct rpc_clnt * client; /* RPC client handle */
struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
struct rpc_clnt * client_acl; /* ACL RPC client handle */
struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
struct backing_dev_info backing_dev_info; struct backing_dev_info backing_dev_info;
int flags; /* various flags */ int flags; /* various flags */
......
...@@ -58,6 +58,7 @@ struct nfs_mount_data { ...@@ -58,6 +58,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
#define NFS_MOUNT_NONLM 0x0200 /* 3 */ #define NFS_MOUNT_NONLM 0x0200 /* 3 */
#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
#define NFS_MOUNT_NOACL 0x0800 /* 4 */
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF #define NFS_MOUNT_FLAGMASK 0xFFFF
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _LINUX_NFS_XDR_H #define _LINUX_NFS_XDR_H
#include <linux/sunrpc/xprt.h> #include <linux/sunrpc/xprt.h>
#include <linux/nfsacl.h>
struct nfs4_fsid { struct nfs4_fsid {
__u64 major; __u64 major;
...@@ -368,6 +369,20 @@ struct nfs_readdirargs { ...@@ -368,6 +369,20 @@ struct nfs_readdirargs {
struct page ** pages; struct page ** pages;
}; };
struct nfs3_getaclargs {
struct nfs_fh * fh;
int mask;
struct page ** pages;
};
struct nfs3_setaclargs {
struct inode * inode;
int mask;
struct posix_acl * acl_access;
struct posix_acl * acl_default;
struct page ** pages;
};
struct nfs_diropok { struct nfs_diropok {
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
...@@ -491,6 +506,15 @@ struct nfs3_readdirres { ...@@ -491,6 +506,15 @@ struct nfs3_readdirres {
int plus; int plus;
}; };
struct nfs3_getaclres {
struct nfs_fattr * fattr;
int mask;
unsigned int acl_access_count;
unsigned int acl_default_count;
struct posix_acl * acl_access;
struct posix_acl * acl_default;
};
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
typedef u64 clientid4; typedef u64 clientid4;
...@@ -748,4 +772,7 @@ extern struct rpc_version nfs_version2; ...@@ -748,4 +772,7 @@ extern struct rpc_version nfs_version2;
extern struct rpc_version nfs_version3; extern struct rpc_version nfs_version3;
extern struct rpc_version nfs_version4; extern struct rpc_version nfs_version4;
extern struct rpc_version nfsacl_version3;
extern struct rpc_program nfsacl_program;
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment