[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: 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:
parent
a257cdd0e2
commit
b7fa0554cf
11
fs/Kconfig
11
fs/Kconfig
|
@ -1268,6 +1268,7 @@ config NFS_FS
|
|||
depends on INET
|
||||
select LOCKD
|
||||
select SUNRPC
|
||||
select NFS_ACL_SUPPORT if NFS_V3_ACL
|
||||
help
|
||||
If you are connected to some other (usually local) Unix computer
|
||||
(using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
|
||||
|
@ -1310,6 +1311,16 @@ config NFS_V3
|
|||
|
||||
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
|
||||
bool "Provide NFSv4 client support (EXPERIMENTAL)"
|
||||
depends on NFS_FS && EXPERIMENTAL
|
||||
|
|
|
@ -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
|
||||
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.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 \
|
||||
delegation.o idmap.o \
|
||||
callback.o callback_xdr.o callback_proc.o
|
||||
|
|
21
fs/nfs/dir.c
21
fs/nfs/dir.c
|
@ -75,6 +75,27 @@ struct inode_operations nfs_dir_inode_operations = {
|
|||
.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
|
||||
|
||||
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
|
|
|
@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = {
|
|||
.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 */
|
||||
#ifndef IS_SWAPFILE
|
||||
# define IS_SWAPFILE(inode) (0)
|
||||
|
|
|
@ -108,6 +108,21 @@ static struct rpc_program nfs_program = {
|
|||
.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
|
||||
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
|
||||
{
|
||||
|
@ -165,6 +180,9 @@ nfs_umount_begin(struct super_block *sb)
|
|||
/* -EIO all pending I/O */
|
||||
if (!IS_ERR(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)
|
|||
atomic_inc(&server->client->cl_count);
|
||||
server->client_sys = server->client;
|
||||
}
|
||||
|
||||
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)
|
||||
server->namelen = NFS3_MAXNAMLEN;
|
||||
sb->s_time_gran = 1;
|
||||
|
@ -546,6 +573,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
|||
{ NFS_MOUNT_NOCTO, ",nocto", "" },
|
||||
{ NFS_MOUNT_NOAC, ",noac", "" },
|
||||
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
|
||||
{ NFS_MOUNT_NOACL, ",noacl", "" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
struct proc_nfs_info *nfs_infop;
|
||||
|
@ -1452,7 +1480,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
|
|||
memset(server, 0, sizeof(struct nfs_server));
|
||||
/* Zero out the NFS state stuff */
|
||||
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;
|
||||
if (data->flags & NFS_MOUNT_VER3)
|
||||
|
@ -1513,6 +1541,8 @@ static void nfs_kill_super(struct super_block *s)
|
|||
rpc_shutdown_client(server->client);
|
||||
if (!IS_ERR(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))
|
||||
lockd_down(); /* release rpc.lockd */
|
||||
|
@ -1794,7 +1824,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
|
|||
memset(server, 0, sizeof(struct nfs_server));
|
||||
/* Zero out the NFS state stuff */
|
||||
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);
|
||||
if (IS_ERR(p))
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
#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 @@
|
|||
#include <linux/nfs_page.h>
|
||||
#include <linux/lockd/bind.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/nfs_mount.h>
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
|
||||
|
@ -45,7 +46,7 @@ static inline int
|
|||
nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs3_procedures[proc],
|
||||
.rpc_proc = &clnt->cl_procinfo[proc],
|
||||
.rpc_argp = argp,
|
||||
.rpc_resp = resp,
|
||||
};
|
||||
|
@ -825,8 +826,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
|
|||
struct nfs_rpc_ops nfs_v3_clientops = {
|
||||
.version = 3, /* protocol version */
|
||||
.dentry_ops = &nfs_dentry_operations,
|
||||
.dir_inode_ops = &nfs_dir_inode_operations,
|
||||
.file_inode_ops = &nfs_file_inode_operations,
|
||||
.dir_inode_ops = &nfs3_dir_inode_operations,
|
||||
.file_inode_ops = &nfs3_file_inode_operations,
|
||||
.getroot = nfs3_proc_get_root,
|
||||
.getattr = nfs3_proc_getattr,
|
||||
.setattr = nfs3_proc_setattr,
|
||||
|
|
147
fs/nfs/nfs3xdr.c
147
fs/nfs/nfs3xdr.c
|
@ -21,6 +21,7 @@
|
|||
#include <linux/nfs.h>
|
||||
#include <linux/nfs3.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfsacl.h>
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_XDR
|
||||
|
||||
|
@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int);
|
|||
#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
|
||||
#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
|
||||
*/
|
||||
|
@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
|
|||
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
|
||||
*/
|
||||
|
@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
|
|||
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
|
||||
# define MAX(a, b) (((a) > (b))? (a) : (b))
|
||||
#endif
|
||||
|
@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = {
|
|||
.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 {
|
|||
Opt_soft, Opt_hard, Opt_intr,
|
||||
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_acl, Opt_noacl,
|
||||
/* Error token */
|
||||
Opt_err
|
||||
};
|
||||
|
@ -158,6 +159,8 @@ static match_table_t __initdata tokens = {
|
|||
{Opt_udp, "udp"},
|
||||
{Opt_tcp, "proto=tcp"},
|
||||
{Opt_tcp, "tcp"},
|
||||
{Opt_acl, "acl"},
|
||||
{Opt_noacl, "noacl"},
|
||||
{Opt_err, NULL}
|
||||
|
||||
};
|
||||
|
@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf)
|
|||
case Opt_tcp:
|
||||
nfs_data.flags |= NFS_MOUNT_TCP;
|
||||
break;
|
||||
case Opt_acl:
|
||||
nfs_data.flags &= ~NFS_MOUNT_NOACL;
|
||||
break;
|
||||
case Opt_noacl:
|
||||
nfs_data.flags |= NFS_MOUNT_NOACL;
|
||||
break;
|
||||
default :
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -301,6 +301,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/
|
|||
* linux/fs/nfs/file.c
|
||||
*/
|
||||
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 address_space_operations nfs_file_aops;
|
||||
|
||||
|
@ -315,6 +318,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file)
|
|||
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
|
||||
*/
|
||||
|
@ -329,6 +348,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
|
|||
* linux/fs/nfs/dir.c
|
||||
*/
|
||||
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 dentry_operations nfs_dentry_operations;
|
||||
|
||||
|
@ -449,6 +471,15 @@ static inline void nfs_readdata_free(struct nfs_read_data *p)
|
|||
|
||||
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
|
||||
* (Used only by nfsroot module)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
struct nfs_server {
|
||||
struct rpc_clnt * client; /* RPC client handle */
|
||||
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 backing_dev_info backing_dev_info;
|
||||
int flags; /* various flags */
|
||||
|
|
|
@ -58,6 +58,7 @@ struct nfs_mount_data {
|
|||
#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
|
||||
#define NFS_MOUNT_NONLM 0x0200 /* 3 */
|
||||
#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
|
||||
#define NFS_MOUNT_NOACL 0x0800 /* 4 */
|
||||
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
|
||||
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
|
||||
#define NFS_MOUNT_FLAGMASK 0xFFFF
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _LINUX_NFS_XDR_H
|
||||
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/nfsacl.h>
|
||||
|
||||
struct nfs4_fsid {
|
||||
__u64 major;
|
||||
|
@ -368,6 +369,20 @@ struct nfs_readdirargs {
|
|||
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_fh * fh;
|
||||
struct nfs_fattr * fattr;
|
||||
|
@ -491,6 +506,15 @@ struct nfs3_readdirres {
|
|||
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
|
||||
|
||||
typedef u64 clientid4;
|
||||
|
@ -748,4 +772,7 @@ extern struct rpc_version nfs_version2;
|
|||
extern struct rpc_version nfs_version3;
|
||||
extern struct rpc_version nfs_version4;
|
||||
|
||||
extern struct rpc_version nfsacl_version3;
|
||||
extern struct rpc_program nfsacl_program;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue