Commit 7b51a623 authored by Trond Myklebust's avatar Trond Myklebust

Merge http://nfsclient.bkbits.net/linux-2.5

into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.5
parents d9a9168b 3f1990d3
......@@ -72,6 +72,26 @@ struct inode_operations nfs_dir_inode_operations = {
.setattr = nfs_setattr,
};
#ifdef CONFIG_NFS_V4
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
struct inode_operations nfs4_dir_inode_operations = {
.create = nfs_create,
.lookup = nfs_atomic_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,
};
#endif /* CONFIG_NFS_V4 */
/*
* Open file
*/
......@@ -670,7 +690,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
goto out;
error = -ENOMEM;
dentry->d_op = &nfs_dentry_operations;
dentry->d_op = NFS_PROTO(dir)->dentry_ops;
lock_kernel();
......@@ -702,6 +722,119 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
return ERR_PTR(error);
}
#ifdef CONFIG_NFS_V4
static int nfs_open_revalidate(struct dentry *, struct nameidata *);
struct dentry_operations nfs4_dentry_operations = {
.d_revalidate = nfs_open_revalidate,
.d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
};
static int is_atomic_open(struct inode *dir, struct nameidata *nd)
{
if (!nd)
return 0;
/* Check that we are indeed trying to open this file */
if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN))
return 0;
/* NFS does not (yet) have a stateful open for directories */
if (nd->flags & LOOKUP_DIRECTORY)
return 0;
/* Are we trying to write to a read only partition? */
if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
return 0;
return 1;
}
static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = NULL;
int error = 0;
/* Check that we are indeed trying to open this file */
if (!is_atomic_open(dir, nd))
goto no_open;
if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
error = -ENAMETOOLONG;
goto out;
}
dentry->d_op = NFS_PROTO(dir)->dentry_ops;
/* Let vfs_create() deal with O_EXCL */
if (nd->intent.open.flags & O_EXCL)
goto no_entry;
/* Open the file on the server */
lock_kernel();
inode = nfs4_atomic_open(dir, dentry, nd);
unlock_kernel();
if (IS_ERR(inode)) {
error = PTR_ERR(inode);
switch (error) {
/* Make a negative dentry */
case -ENOENT:
inode = NULL;
break;
/* This turned out not to be a regular file */
case -ELOOP:
if (!(nd->intent.open.flags & O_NOFOLLOW))
goto no_open;
/* case -EISDIR: */
/* case -EINVAL: */
default:
goto out;
}
}
no_entry:
d_add(dentry, inode);
nfs_renew_times(dentry);
out:
BUG_ON(error > 0);
return ERR_PTR(error);
no_open:
return nfs_lookup(dir, dentry, nd);
}
static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct dentry *parent = NULL;
struct inode *inode = dentry->d_inode;
int openflags, ret = 0;
/* NFS only supports OPEN for regular files */
if (inode && !S_ISREG(inode->i_mode))
goto no_open;
parent = dget_parent(dentry);
if (!is_atomic_open(parent->d_inode, nd))
goto no_open;
openflags = nd->intent.open.flags;
if (openflags & O_CREAT) {
/* If this is a negative dentry, just drop it */
if (!inode)
goto out;
/* If this is exclusive open, just revalidate */
if (openflags & O_EXCL)
goto no_open;
}
/* We can't create new files, or truncate existing ones here */
openflags &= ~(O_CREAT|O_TRUNC);
lock_kernel();
ret = nfs4_open_revalidate(parent->d_inode, dentry, openflags);
unlock_kernel();
out:
dput(parent);
if (!ret)
d_drop(dentry);
return ret;
no_open:
dput(parent);
return nfs_lookup_revalidate(dentry, nd);
}
#endif /* CONFIG_NFSV4 */
static inline
int find_dirent_name(nfs_readdir_descriptor_t *desc, struct page *page, struct dentry *dentry)
{
......@@ -1306,6 +1439,9 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
/* We only need to check permissions on file open() and access() */
if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))
return 0;
/* NFSv4 has atomic_open... */
if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN))
return 0;
}
lock_kernel();
......
......@@ -26,7 +26,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
......@@ -278,22 +277,18 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if (!inode)
return -EINVAL;
/* This will be in a forthcoming patch. */
if (NFS_PROTO(inode)->version == 4) {
printk(KERN_INFO "NFS: file locking over NFSv4 is not yet supported\n");
return -EIO;
}
/* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return -ENOLCK;
if (NFS_PROTO(inode)->version != 4) {
/* Fake OK code if mounted without NLM support */
if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) {
if (IS_GETLK(cmd))
status = LOCK_USE_CLNT;
goto out_ok;
}
}
/*
* No BSD flocks over NFS allowed.
......@@ -302,7 +297,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* Not sure whether that would be unique, though, or whether
* that would break in other places.
*/
if (!fl->fl_owner || (fl->fl_flags & FL_POSIX) != FL_POSIX)
if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
return -ENOLCK;
/*
......@@ -322,7 +317,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
return status;
lock_kernel();
status = nlmclnt_proc(inode, cmd, fl);
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
unlock_kernel();
if (status < 0)
return status;
......
This diff is collapsed.
......@@ -158,10 +158,7 @@ nfs_put_super(struct super_block *sb)
{
struct nfs_server *server = NFS_SB(sb);
#ifdef CONFIG_NFS_V4
if (server->idmap != NULL)
nfs_idmap_delete(server);
#endif /* CONFIG_NFS_V4 */
nfs4_renewd_prepare_shutdown(server);
if (server->client != NULL)
rpc_shutdown_client(server->client);
......@@ -301,7 +298,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
server = NFS_SB(sb);
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
/* Did getting the root inode fail? */
if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0)
......@@ -310,7 +306,7 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
if (!sb->s_root)
goto out_no_root;
sb->s_root->d_op = &nfs_dentry_operations;
sb->s_root->d_op = server->rpc_ops->dentry_ops;
/* Get some general file system info */
if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
......@@ -493,10 +489,17 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
server->client = nfs_create_client(server, data);
if (server->client == NULL)
goto out_fail;
data->pseudoflavor = RPC_AUTH_UNIX; /* RFC 2623, sec 2.3.2 */
server->client_sys = nfs_create_client(server, data);
/* RFC 2623, sec 2.3.2 */
if (authflavor != RPC_AUTH_UNIX) {
server->client_sys = rpc_clone_client(server->client);
if (server->client_sys == NULL)
goto out_shutdown;
if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys))
goto out_shutdown;
} else {
atomic_inc(&server->client->cl_count);
server->client_sys = server->client;
}
/* Fire up rpciod if not yet running */
if (rpciod_up() != 0) {
......@@ -504,6 +507,7 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
goto out_shutdown;
}
sb->s_op = &nfs_sops;
err = nfs_sb_init(sb, authflavor);
if (err != 0)
goto out_noinit;
......@@ -736,7 +740,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_data.a_ops = &nfs_file_aops;
inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &nfs_dir_inode_operations;
inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops;
inode->i_fop = &nfs_dir_operations;
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
&& fattr->size <= NFS_LIMIT_READDIRPLUS)
......@@ -828,7 +832,12 @@ printk("nfs_setattr: revalidate failed, error=%d\n", error);
filemap_fdatawait(inode->i_mapping);
if (error)
goto out;
/* Optimize away unnecessary truncates */
if ((attr->ia_valid & ATTR_SIZE) && i_size_read(inode) == attr->ia_size)
attr->ia_valid &= ~ATTR_SIZE;
}
if (!attr->ia_valid)
goto out;
error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error)
......@@ -1274,6 +1283,8 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
if (!server)
return ERR_PTR(-ENOMEM);
memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */
init_nfsv4_state(server);
root = &server->fh;
memcpy(root, &data->root, sizeof(*root));
......@@ -1346,9 +1357,52 @@ static struct file_system_type nfs_fs_type = {
#ifdef CONFIG_NFS_V4
static void nfs4_clear_inode(struct inode *);
static struct super_operations nfs4_sops = {
.alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode,
.write_inode = nfs_write_inode,
.delete_inode = nfs_delete_inode,
.put_super = nfs_put_super,
.statfs = nfs_statfs,
.clear_inode = nfs4_clear_inode,
.umount_begin = nfs_umount_begin,
.show_options = nfs_show_options,
};
/*
* Clean out any remaining NFSv4 state that might be left over due
* to open() calls that passed nfs_atomic_lookup, but failed to call
* nfs_open().
*/
static void nfs4_clear_inode(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
while (!list_empty(&nfsi->open_states)) {
struct nfs4_state *state;
state = list_entry(nfsi->open_states.next,
struct nfs4_state,
inode_states);
dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n",
__FUNCTION__,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
state);
list_del(&state->inode_states);
nfs4_put_open_state(state);
}
/* Now call standard NFS clear_inode() code */
nfs_clear_inode(inode);
}
static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
{
struct nfs_server *server;
struct nfs4_client *clp = NULL;
struct rpc_xprt *xprt = NULL;
struct rpc_clnt *clnt = NULL;
struct rpc_timeout timeparms;
......@@ -1398,13 +1452,13 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
return -EINVAL;
}
/* Now create transport and client */
xprt = xprt_create_proto(proto, &server->addr, &timeparms);
if (xprt == NULL) {
printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
clp = nfs4_get_client(&server->addr.sin_addr);
if (!clp) {
printk(KERN_WARNING "NFS: failed to create NFS4 client.\n");
goto out_fail;
}
/* Now create transport and client */
authflavour = RPC_AUTH_UNIX;
if (data->auth_flavourlen != 0) {
if (data->auth_flavourlen > 1)
......@@ -1414,41 +1468,78 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
goto out_fail;
}
}
down_write(&clp->cl_sem);
if (clp->cl_rpcclient == NULL) {
xprt = xprt_create_proto(proto, &server->addr, &timeparms);
if (xprt == NULL) {
up_write(&clp->cl_sem);
printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
goto out_fail;
}
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
server->rpc_ops->version, authflavour);
if (clnt == NULL) {
up_write(&clp->cl_sem);
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
xprt_destroy(xprt);
goto out_fail;
}
clnt->cl_chatty = 1;
clp->cl_rpcclient = clnt;
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp);
}
if (list_empty(&clp->cl_superblocks))
clear_bit(NFS4CLNT_OK, &clp->cl_state);
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
clnt = rpc_clone_client(clp->cl_rpcclient);
server->nfs4_state = clp;
up_write(&clp->cl_sem);
clp = NULL;
if (clnt == NULL) {
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
goto out_remove_list;
}
if (server->nfs4_state->cl_idmap == NULL) {
printk(KERN_WARNING "NFS: failed to create idmapper.\n");
goto out_shutdown;
}
clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
if (clnt->cl_auth->au_flavor != authflavour) {
if (rpcauth_create(authflavour, clnt) == NULL) {
printk(KERN_WARNING "NFS: couldn't create credcache!\n");
goto out_shutdown;
}
}
/* Fire up rpciod if not yet running */
if (rpciod_up() != 0) {
printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
goto out_shutdown;
}
if (create_nfsv4_state(server, data))
goto out_shutdown;
if ((server->idmap = nfs_idmap_new(server)) == NULL)
printk(KERN_WARNING "NFS: couldn't start IDmap\n");
sb->s_op = &nfs4_sops;
err = nfs_sb_init(sb, authflavour);
if (err == 0)
return 0;
rpciod_down();
destroy_nfsv4_state(server);
if (server->idmap != NULL)
nfs_idmap_delete(server);
out_shutdown:
rpc_shutdown_client(server->client);
out_remove_list:
down_write(&server->nfs4_state->cl_sem);
list_del_init(&server->nfs4_siblings);
up_write(&server->nfs4_state->cl_sem);
destroy_nfsv4_state(server);
out_fail:
if (clp)
nfs4_put_client(clp);
return err;
}
......@@ -1505,6 +1596,8 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
if (!server)
return ERR_PTR(-ENOMEM);
memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */
init_nfsv4_state(server);
if (data->version != NFS4_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
......
......@@ -15,6 +15,7 @@
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC
......@@ -896,8 +897,16 @@ nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
return 1;
}
static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
}
struct nfs_rpc_ops nfs_v3_clientops = {
.version = 3, /* protocol version */
.dentry_ops = &nfs_dentry_operations,
.dir_inode_ops = &nfs_dir_inode_operations,
.getroot = nfs3_proc_get_root,
.getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr,
......@@ -929,4 +938,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.file_release = nfs_release,
.request_init = nfs3_request_init,
.request_compatible = nfs3_request_compatible,
.lock = nfs3_proc_lock,
};
This diff is collapsed.
......@@ -54,53 +54,91 @@
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
static RPC_WAITQ(nfs4_renewd_queue, "nfs4_renewd_queue");
#define NFSDBG_FACILITY NFSDBG_PROC
static void
renewd(struct rpc_task *task)
void
nfs4_renew_state(void *data)
{
struct nfs_server *server = (struct nfs_server *)task->tk_calldata;
unsigned long lease = server->lease_time;
unsigned long last = server->last_renewal;
unsigned long timeout;
struct nfs4_client *clp = (struct nfs4_client *)data;
long lease, timeout;
unsigned long last, now;
if (!server->nfs4_state)
timeout = (2 * lease) / 3;
else if (jiffies < last + lease/3)
timeout = (2 * lease) / 3 + last - jiffies;
else {
down_read(&clp->cl_sem);
dprintk("%s: start\n", __FUNCTION__);
/* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks))
goto out;
spin_lock(&clp->cl_lock);
lease = clp->cl_lease_time;
last = clp->cl_last_renewal;
now = jiffies;
timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */
if (time_after(now, last + lease/3)) {
spin_unlock(&clp->cl_lock);
/* Queue an asynchronous RENEW. */
nfs4_proc_renew(server);
nfs4_proc_async_renew(clp);
timeout = (2 * lease) / 3;
}
spin_lock(&clp->cl_lock);
} else
dprintk("%s: failed to call renewd. Reason: lease not expired \n",
__FUNCTION__);
if (timeout < 5 * HZ) /* safeguard */
timeout = 5 * HZ;
task->tk_timeout = timeout;
task->tk_action = renewd;
task->tk_exit = NULL;
rpc_sleep_on(&nfs4_renewd_queue, task, NULL, NULL);
return;
dprintk("%s: requeueing work. Lease period = %ld\n",
__FUNCTION__, (timeout + HZ - 1) / HZ);
cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout);
spin_unlock(&clp->cl_lock);
out:
up_read(&clp->cl_sem);
dprintk("%s: done\n", __FUNCTION__);
}
int
nfs4_init_renewd(struct nfs_server *server)
/* Must be called with clp->cl_sem locked for writes */
void
nfs4_schedule_state_renewal(struct nfs4_client *clp)
{
struct rpc_task *task;
int status;
long timeout;
lock_kernel();
status = -ENOMEM;
task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC);
if (!task)
goto out;
task->tk_calldata = server;
task->tk_action = renewd;
status = rpc_execute(task);
spin_lock(&clp->cl_lock);
timeout = (2 * clp->cl_lease_time) / 3 + (long)clp->cl_last_renewal
- (long)jiffies;
if (timeout < 5 * HZ)
timeout = 5 * HZ;
dprintk("%s: requeueing work. Lease period = %ld\n",
__FUNCTION__, (timeout + HZ - 1) / HZ);
cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout);
spin_unlock(&clp->cl_lock);
}
out:
unlock_kernel();
return status;
void
nfs4_renewd_prepare_shutdown(struct nfs_server *server)
{
struct nfs4_client *clp = server->nfs4_state;
if (!clp)
return;
flush_scheduled_work();
down_write(&clp->cl_sem);
if (!list_empty(&server->nfs4_siblings))
list_del_init(&server->nfs4_siblings);
up_write(&clp->cl_sem);
}
/* Must be called with clp->cl_sem locked for writes */
void
nfs4_kill_renewd(struct nfs4_client *clp)
{
down_read(&clp->cl_sem);
if (!list_empty(&clp->cl_superblocks)) {
up_read(&clp->cl_sem);
return;
}
cancel_delayed_work(&clp->cl_renewd);
up_read(&clp->cl_sem);
flush_scheduled_work();
}
/*
......
This diff is collapsed.
This diff is collapsed.
......@@ -42,6 +42,7 @@
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC
......@@ -653,9 +654,17 @@ nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *pag
return 1;
}
static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
}
struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */
.dentry_ops = &nfs_dentry_operations,
.dir_inode_ops = &nfs_dir_inode_operations,
.getroot = nfs_proc_get_root,
.getattr = nfs_proc_getattr,
.setattr = nfs_proc_setattr,
......@@ -687,4 +696,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.file_release = nfs_release,
.request_init = nfs_request_init,
.request_compatible = nfs_request_compatible,
.lock = nfs_proc_lock,
};
......@@ -88,6 +88,76 @@ enum nfs_opnum4 {
OP_WRITE = 38,
};
enum nfsstat4 {
NFS4_OK = 0,
NFS4ERR_PERM = 1,
NFS4ERR_NOENT = 2,
NFS4ERR_IO = 5,
NFS4ERR_NXIO = 6,
NFS4ERR_ACCESS = 13,
NFS4ERR_EXIST = 17,
NFS4ERR_XDEV = 18,
/* Unused/reserved 19 */
NFS4ERR_NOTDIR = 20,
NFS4ERR_ISDIR = 21,
NFS4ERR_INVAL = 22,
NFS4ERR_FBIG = 27,
NFS4ERR_NOSPC = 28,
NFS4ERR_ROFS = 30,
NFS4ERR_MLINK = 31,
NFS4ERR_NAMETOOLONG = 63,
NFS4ERR_NOTEMPTY = 66,
NFS4ERR_DQUOT = 69,
NFS4ERR_STALE = 70,
NFS4ERR_BADHANDLE = 10001,
NFS4ERR_BAD_COOKIE = 10003,
NFS4ERR_NOTSUPP = 10004,
NFS4ERR_TOOSMALL = 10005,
NFS4ERR_SERVERFAULT = 10006,
NFS4ERR_BADTYPE = 10007,
NFS4ERR_DELAY = 10008,
NFS4ERR_SAME = 10009,
NFS4ERR_DENIED = 10010,
NFS4ERR_EXPIRED = 10011,
NFS4ERR_LOCKED = 10012,
NFS4ERR_GRACE = 10013,
NFS4ERR_FHEXPIRED = 10014,
NFS4ERR_SHARE_DENIED = 10015,
NFS4ERR_WRONGSEC = 10016,
NFS4ERR_CLID_INUSE = 10017,
NFS4ERR_RESOURCE = 10018,
NFS4ERR_MOVED = 10019,
NFS4ERR_NOFILEHANDLE = 10020,
NFS4ERR_MINOR_VERS_MISMATCH = 10021,
NFS4ERR_STALE_CLIENTID = 10022,
NFS4ERR_STALE_STATEID = 10023,
NFS4ERR_OLD_STATEID = 10024,
NFS4ERR_BAD_STATEID = 10025,
NFS4ERR_BAD_SEQID = 10026,
NFS4ERR_NOT_SAME = 10027,
NFS4ERR_LOCK_RANGE = 10028,
NFS4ERR_SYMLINK = 10029,
NFS4ERR_RESTOREFH = 10030,
NFS4ERR_LEASE_MOVED = 10031,
NFS4ERR_ATTRNOTSUPP = 10032,
NFS4ERR_NO_GRACE = 10033,
NFS4ERR_RECLAIM_BAD = 10034,
NFS4ERR_RECLAIM_CONFLICT = 10035,
NFS4ERR_BADXDR = 10036,
NFS4ERR_LOCKS_HELD = 10037,
NFS4ERR_OPENMODE = 10038,
NFS4ERR_BADOWNER = 10039,
NFS4ERR_BADCHAR = 10040,
NFS4ERR_BADNAME = 10041,
NFS4ERR_BAD_RANGE = 10042,
NFS4ERR_LOCK_NOTSUPP = 10043,
NFS4ERR_OP_ILLEGAL = 10044,
NFS4ERR_DEADLOCK = 10045,
NFS4ERR_FILE_OPEN = 10046,
NFS4ERR_ADMIN_REVOKED = 10047,
NFS4ERR_CB_PATH_DOWN = 10048
};
/*
* Note: NF4BAD is not actually part of the protocol; it is just used
* internally by nfsd.
......@@ -219,8 +289,17 @@ enum {
NFSPROC4_CLNT_COMMIT,
NFSPROC4_CLNT_OPEN,
NFSPROC4_CLNT_OPEN_CONFIRM,
NFSPROC4_CLNT_OPEN_RECLAIM,
NFSPROC4_CLNT_OPEN_DOWNGRADE,
NFSPROC4_CLNT_CLOSE,
NFSPROC4_CLNT_SETATTR,
NFSPROC4_CLNT_FSINFO,
NFSPROC4_CLNT_RENEW,
NFSPROC4_CLNT_SETCLIENTID,
NFSPROC4_CLNT_SETCLIENTID_CONFIRM,
NFSPROC4_CLNT_LOCK,
NFSPROC4_CLNT_LOCKT,
NFSPROC4_CLNT_LOCKU,
};
#endif
......
......@@ -28,6 +28,7 @@
#include <linux/nfs3.h>
#include <linux/nfs4.h>
#include <linux/nfs_xdr.h>
#include <linux/workqueue.h>
/*
* Enable debugging support for nfs client.
......@@ -437,6 +438,8 @@ extern void * nfs_root_data(void);
#ifdef CONFIG_NFS_V4
struct idmap;
/*
* In a seqid-mutating op, this macro controls which error return
* values trigger incrementation of the seqid.
......@@ -464,6 +467,7 @@ extern void * nfs_root_data(void);
enum nfs4_client_state {
NFS4CLNT_OK = 0,
NFS4CLNT_NEW,
NFS4CLNT_SETUP_STATE,
};
/*
......@@ -474,7 +478,8 @@ struct nfs4_client {
struct in_addr cl_addr; /* Server identifier */
u64 cl_clientid; /* constant */
nfs4_verifier cl_confirm;
enum nfs4_client_state cl_state;
unsigned long cl_state;
long cl_generation;
u32 cl_lockowner_id;
......@@ -489,6 +494,27 @@ struct nfs4_client {
int cl_nunused;
spinlock_t cl_lock;
atomic_t cl_count;
struct rpc_clnt * cl_rpcclient;
struct rpc_cred * cl_cred;
struct list_head cl_superblocks; /* List of nfs_server structs */
unsigned long cl_lease_time;
unsigned long cl_last_renewal;
struct work_struct cl_renewd;
struct work_struct cl_recoverd;
wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq;
/* idmapper */
struct idmap * cl_idmap;
/* Our own IP address, as a null-terminated string.
* This is used to generate the clientid, and the callback address.
*/
char cl_ipaddr[16];
};
/*
......@@ -508,6 +534,7 @@ struct nfs4_state_owner {
u32 so_seqid; /* protected by so_sema */
unsigned int so_flags; /* protected by so_sema */
atomic_t so_count;
long so_generation;
struct rpc_cred *so_cred; /* Associated cred */
struct list_head so_states;
......@@ -515,73 +542,105 @@ struct nfs4_state_owner {
/*
* struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple.
* (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
*
* OPEN:
* In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server,
* we need to know how many files are open for reading or writing on a
* given inode. This information too is stored here.
*
* LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
*/
struct nfs4_lock_state {
struct list_head ls_locks; /* Other lock stateids */
fl_owner_t ls_owner; /* POSIX lock owner */
struct nfs4_state * ls_parent; /* Parent nfs4_state */
u32 ls_seqid;
u32 ls_id;
nfs4_stateid ls_stateid;
atomic_t ls_count;
};
/* bits for nfs4_state->flags */
enum {
LK_STATE_IN_USE,
};
struct nfs4_state {
struct list_head open_states; /* List of states for the same state_owner */
struct list_head inode_states; /* List of states for the same inode */
struct list_head lock_states; /* List of subservient lock stateids */
struct nfs4_state_owner *owner; /* Pointer to the open owner */
struct inode *inode; /* Pointer to the inode */
pid_t pid; /* Thread that called OPEN */
unsigned long flags; /* Do we hold any locks? */
struct semaphore lock_sema; /* Serializes file locking operations */
rwlock_t state_lock; /* Protects the lock_states list */
nfs4_stateid stateid;
unsigned int nreaders;
unsigned int nwriters;
int state; /* State on the server (R,W, or RW) */
atomic_t count;
};
extern struct dentry_operations nfs4_dentry_operations;
extern struct inode_operations nfs4_dir_inode_operations;
/* nfs4proc.c */
extern int nfs4_proc_renew(struct nfs_server *server);
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
extern int nfs4_proc_async_renew(struct nfs4_client *);
extern int nfs4_proc_renew(struct nfs4_client *);
extern int nfs4_do_close(struct inode *, struct nfs4_state *);
int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode);
extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *);
extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);
/* nfs4renewd.c */
extern int nfs4_init_renewd(struct nfs_server *server);
extern void nfs4_schedule_state_renewal(struct nfs4_client *);
extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);
extern void nfs4_kill_renewd(struct nfs4_client *);
/* nfs4state.c */
extern void init_nfsv4_state(struct nfs_server *);
extern void destroy_nfsv4_state(struct nfs_server *);
extern struct nfs4_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs4_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_increment_seqid(u32 status, struct nfs4_state_owner *sp);
extern void nfs4_close_state(struct nfs4_state *, mode_t);
extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);
extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
extern int nfs4_handle_error(struct nfs_server *, int);
extern void nfs4_schedule_state_recovery(struct nfs4_client *);
extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t);
extern struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t);
extern void nfs4_put_lock_state(struct nfs4_lock_state *state);
extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);
extern void nfs4_notify_setlk(struct inode *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_notify_unlck(struct inode *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
struct nfs4_mount_data;
static inline int
create_nfsv4_state(struct nfs_server *server, struct nfs4_mount_data *data)
{
server->nfs4_state = NULL;
return 0;
}
static inline void
destroy_nfsv4_state(struct nfs_server *server)
{
if (server->mnt_path) {
kfree(server->mnt_path);
server->mnt_path = NULL;
}
if (server->nfs4_state) {
nfs4_put_client(server->nfs4_state);
server->nfs4_state = NULL;
}
}
#else
#define create_nfsv4_state(server, data) 0
#define init_nfsv4_state(server) do { } while (0)
#define destroy_nfsv4_state(server) do { } while (0)
#define nfs4_put_state_owner(inode, owner) do { } while (0)
#define nfs4_put_open_state(state) do { } while (0)
#define nfs4_renewd_prepare_shutdown(server) do { } while (0)
#endif
#endif /* __KERNEL__ */
......
......@@ -35,9 +35,9 @@ struct nfs_server {
char ip_addr[16];
char * mnt_path;
struct nfs4_client * nfs4_state; /* all NFSv4 state starts here */
unsigned long lease_time; /* in jiffies */
unsigned long last_renewal; /* in jiffies */
void *idmap;
struct list_head nfs4_siblings; /* List of other nfs_server structs
* that share the same clientid
*/
#endif
};
......
......@@ -52,18 +52,21 @@
#define IDMAP_STATUS_SUCCESS 0x08
struct idmap_msg {
u_int8_t im_type;
u_int8_t im_conv;
__u8 im_type;
__u8 im_conv;
char im_name[IDMAP_NAMESZ];
u_int32_t im_id;
u_int8_t im_status;
__u32 im_id;
__u8 im_status;
};
#ifdef __KERNEL__
void *nfs_idmap_new(struct nfs_server *);
void nfs_idmap_delete(struct nfs_server *);
int nfs_idmap_id(struct nfs_server *, u_int8_t, char *, u_int, uid_t *);
int nfs_idmap_name(struct nfs_server *, u_int8_t, uid_t, char *, u_int *);
void nfs_idmap_new(struct nfs4_client *);
void nfs_idmap_delete(struct nfs4_client *);
int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
#endif /* __KERNEL__ */
#endif /* NFS_IDMAP_H */
......@@ -26,6 +26,7 @@ struct nfs_page {
struct list_head wb_list, /* Defines state of page: */
*wb_list_head; /* read/write/commit */
struct file *wb_file;
fl_owner_t wb_lockowner;
struct inode *wb_inode;
struct rpc_cred *wb_cred;
struct nfs4_state *wb_state;
......
......@@ -109,7 +109,6 @@ struct nfs_openargs {
};
struct nfs_openres {
__u32 status;
nfs4_stateid stateid;
struct nfs_fh fh;
struct nfs4_change_info * cinfo;
......@@ -129,10 +128,22 @@ struct nfs_open_confirmargs {
};
struct nfs_open_confirmres {
__u32 status;
nfs4_stateid stateid;
};
/*
* Arguments to the open_reclaim call.
*/
struct nfs_open_reclaimargs {
struct nfs_fh * fh;
__u64 clientid;
__u32 seqid;
__u32 id;
__u32 share_access;
__u32 claim;
struct nfs4_getattr * f_getattr;
};
/*
* Arguments to the close call.
*/
......@@ -140,13 +151,72 @@ struct nfs_closeargs {
struct nfs_fh * fh;
nfs4_stateid stateid;
__u32 seqid;
__u32 share_access;
};
struct nfs_closeres {
__u32 status;
nfs4_stateid stateid;
};
/*
* * Arguments to the lock,lockt, and locku call.
* */
struct nfs_lowner {
__u64 clientid;
u32 id;
};
struct nfs_open_to_lock {
__u32 open_seqid;
nfs4_stateid open_stateid;
__u32 lock_seqid;
struct nfs_lowner lock_owner;
};
struct nfs_exist_lock {
nfs4_stateid stateid;
__u32 seqid;
};
struct nfs_lock_opargs {
__u32 reclaim;
__u32 new_lock_owner;
union {
struct nfs_open_to_lock *open_lock;
struct nfs_exist_lock *exist_lock;
} u;
};
struct nfs_locku_opargs {
__u32 seqid;
nfs4_stateid stateid;
};
struct nfs_lockargs {
struct nfs_fh * fh;
__u32 type;
__u64 offset;
__u64 length;
union {
struct nfs_lock_opargs *lock; /* LOCK */
struct nfs_lowner *lockt; /* LOCKT */
struct nfs_locku_opargs *locku; /* LOCKU */
} u;
};
struct nfs_lock_denied {
__u64 offset;
__u64 length;
__u32 type;
struct nfs_lowner owner;
};
struct nfs_lockres {
union {
nfs4_stateid stateid;/* LOCK success, LOCKU */
struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */
} u;
struct nfs_server * server;
};
/*
* Arguments to the read call.
......@@ -449,7 +519,6 @@ struct nfs4_getattr {
u32 * gt_bmval; /* request */
struct nfs_fattr * gt_attrs; /* response */
struct nfs_fsstat * gt_fsstat; /* response */
struct nfs_fsinfo * gt_fsinfo; /* response */
struct nfs_pathconf * gt_pathconf; /* response */
};
......@@ -556,8 +625,6 @@ struct nfs4_op {
struct nfs4_rename rename;
struct nfs4_client * renew;
struct nfs4_setattr setattr;
struct nfs4_setclientid setclientid;
struct nfs4_client * setclientid_confirm;
} u;
};
......@@ -594,6 +661,7 @@ struct nfs_read_data {
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
fl_owner_t lockowner;
struct nfs_fattr fattr; /* fattr storage */
struct list_head pages; /* Coalesced read requests */
struct page *pagevec[NFS_READ_MAXIOV];
......@@ -609,6 +677,7 @@ struct nfs_write_data {
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
fl_owner_t lockowner;
struct nfs_fattr fattr;
struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */
......@@ -627,6 +696,8 @@ struct nfs_page;
*/
struct nfs_rpc_ops {
int version; /* Protocol version */
struct dentry_operations *dentry_ops;
struct inode_operations *dir_inode_ops;
int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *);
......@@ -673,6 +744,7 @@ struct nfs_rpc_ops {
int (*file_release) (struct inode *, struct file *);
void (*request_init)(struct nfs_page *, struct file *);
int (*request_compatible)(struct nfs_page *, struct file *, struct page *);
int (*lock)(struct file *, int, struct file_lock *);
};
/*
......
......@@ -73,6 +73,7 @@ struct rpc_auth {
* differ from the flavor in
* au_ops->au_flavor in gss
* case) */
atomic_t au_count; /* Reference counter */
/* per-flavor data */
};
......@@ -102,6 +103,10 @@ struct rpc_credops {
u32 * (*crmarshal)(struct rpc_task *, u32 *, int);
int (*crrefresh)(struct rpc_task *);
u32 * (*crvalidate)(struct rpc_task *, u32 *);
int (*crwrap_req)(struct rpc_task *, kxdrproc_t,
void *, u32 *, void *);
int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t,
void *, u32 *, void *);
};
extern struct rpc_authops authunix_ops;
......@@ -124,6 +129,8 @@ void put_rpccred(struct rpc_cred *);
void rpcauth_unbindcred(struct rpc_task *);
u32 * rpcauth_marshcred(struct rpc_task *, u32 *);
u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj);
int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj);
int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *);
int rpcauth_uptodatecred(struct rpc_task *);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -141,6 +141,10 @@ void xdr_shift_iovec(struct iovec *, int, size_t);
extern int xdr_kmap(struct iovec *, struct xdr_buf *, size_t);
extern void xdr_kunmap(struct xdr_buf *, size_t);
extern void xdr_shift_buf(struct xdr_buf *, size_t);
extern void _copy_from_pages(char *, struct page **, size_t, size_t);
extern void xdr_buf_from_iov(struct iovec *, struct xdr_buf *);
extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int);
extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int);
/*
* Helper structure for copying from an sk_buff.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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