Commit bf5344dc authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] A basic NFSv4 client for 2.5.x

Now that all the hooks are in place, this large patch imports all
of the new code for the NFSv4 client.
  nfs4proc.c   - procedure vectors
  nfs4xdr.c    - XDR
  nfs4state.c  - state bookkeeping (very minimal for now)
  nfs4renewd.c - a daemon (implemented as an rpc_task) to keep
                 state from expiring on the server

Note: The RPCSEC_GSS authentication code is not yet included here.
  For the moment we make do with AUTH_UNIX aka. AUTH_SYS.

  Neither is the code to do upcalls to userland in order to do
  uid/gid <-> name mappings. Instead, stubs have been added to
  translate everything to 'nobody:nobody' == '-2:-2'
parent ee17e0d6
...@@ -8,6 +8,7 @@ nfs-y := dir.o file.o flushd.o inode.o nfs2xdr.o pagelist.o \ ...@@ -8,6 +8,7 @@ nfs-y := dir.o file.o flushd.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_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-objs := $(nfs-y) nfs-objs := $(nfs-y)
......
...@@ -259,6 +259,12 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -259,6 +259,12 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if (!inode) if (!inode)
return -EINVAL; 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 */ /* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return -ENOLCK; return -ENOLCK;
......
...@@ -77,8 +77,13 @@ static struct rpc_version * nfs_version[] = { ...@@ -77,8 +77,13 @@ static struct rpc_version * nfs_version[] = {
NULL, NULL,
NULL, NULL,
&nfs_version2, &nfs_version2,
#ifdef CONFIG_NFS_V3 #if defined(CONFIG_NFS_V3)
&nfs_version3, &nfs_version3,
#elif defined(CONFIG_NFS_V4)
NULL,
#endif
#if defined(CONFIG_NFS_V4)
&nfs_version4,
#endif #endif
}; };
......
This diff is collapsed.
/*
* fs/nfs/nfs4renewd.c
*
* Copyright (c) 2002 The Regents of the University of Michigan.
* All rights reserved.
*
* Kendrick Smith <kmsmith@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Implementation of the NFSv4 "renew daemon", which wakes up periodically to
* send a RENEW, to keep state alive on the server. The daemon is implemented
* as an rpc_task, not a real kernel thread, so it always runs in rpciod's
* context. There is one renewd per nfs_server.
*
* TODO: If the send queue gets backlogged (e.g., if the server goes down),
* we will keep filling the queue with periodic RENEW requests. We need a
* mechanism for ensuring that if renewd successfully sends off a request,
* then it only wakes up when the request is finished. Maybe use the
* child task framework of the RPC layer?
*/
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
static RPC_WAITQ(nfs4_renewd_queue, "nfs4_renewd_queue");
static void
renewd(struct rpc_task *task)
{
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;
if (!server->nfs4_state)
timeout = (2 * lease) / 3;
else if (jiffies < last + lease/3)
timeout = (2 * lease) / 3 + last - jiffies;
else {
/* Queue an asynchronous RENEW. */
nfs4_proc_renew(server);
timeout = (2 * lease) / 3;
}
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;
}
int
nfs4_init_renewd(struct nfs_server *server)
{
struct rpc_task *task;
int status;
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);
out:
unlock_kernel();
return status;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/*
* fs/nfs/nfs4state.c
*
* Client-side XDR for NFSv4.
*
* Copyright (c) 2002 The Regents of the University of Michigan.
* All rights reserved.
*
* Kendrick Smith <kmsmith@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Implementation of the NFSv4 state model. For the time being,
* this is minimal, but will be made much more complex in a
* subsequent patch.
*/
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/nfs_fs.h>
/*
* nfs4_get_client(): returns an empty client structure
* nfs4_put_client(): drops reference to client structure
*
* Since these are allocated/deallocated very rarely, we don't
* bother putting them in a slab cache...
*/
struct nfs4_client *
nfs4_get_client(void)
{
struct nfs4_client *clp;
if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
atomic_set(&clp->cl_count, 1);
clp->cl_clientid = 0;
INIT_LIST_HEAD(&clp->cl_lockowners);
}
return clp;
}
void
nfs4_put_client(struct nfs4_client *clp)
{
BUG_ON(!clp);
BUG_ON(!atomic_read(&clp->cl_count));
if (atomic_dec_and_test(&clp->cl_count)) {
BUG_ON(!list_empty(&clp->cl_lockowners));
kfree(clp);
}
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
This diff is collapsed.
...@@ -472,6 +472,25 @@ extern void * nfs_root_data(void); ...@@ -472,6 +472,25 @@ extern void * nfs_root_data(void);
#define NFS_JUKEBOX_RETRY_TIME (5 * HZ) #define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
#ifdef CONFIG_NFS_V4
struct nfs4_client {
atomic_t cl_count; /* refcount */
u64 cl_clientid; /* constant */
nfs4_verifier cl_confirm;
/*
* Starts a list of lockowners, linked through lo_list.
*/
struct list_head cl_lockowners; /* protected by state_spinlock */
};
/* nfs4proc.c */
extern int nfs4_proc_renew(struct nfs_server *server);
/* nfs4renewd.c */
extern int nfs4_init_renewd(struct nfs_server *server);
#endif /* CONFIG_NFS_V4 */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern struct nfs4_client *nfs4_get_client(void); extern struct nfs4_client *nfs4_get_client(void);
......
...@@ -325,6 +325,219 @@ struct nfs3_readdirres { ...@@ -325,6 +325,219 @@ struct nfs3_readdirres {
int plus; int plus;
}; };
#ifdef CONFIG_NFS_V4
typedef u64 clientid4;
struct nfs4_change_info {
u32 atomic;
u64 before;
u64 after;
};
struct nfs4_access {
u32 ac_req_access; /* request */
u32 * ac_resp_supported; /* response */
u32 * ac_resp_access; /* response */
};
struct nfs4_close {
char * cl_stateid; /* request */
u32 cl_seqid; /* request */
};
struct nfs4_commit {
u64 co_start; /* request */
u32 co_len; /* request */
struct nfs_writeverf * co_verifier; /* response */
};
struct nfs4_create {
u32 cr_ftype; /* request */
union { /* request */
struct {
u32 textlen;
const char * text;
} symlink; /* NF4LNK */
struct {
u32 specdata1;
u32 specdata2;
} device; /* NF4BLK, NF4CHR */
} u;
u32 cr_namelen; /* request */
const char * cr_name; /* request */
struct iattr * cr_attrs; /* request */
struct nfs4_change_info * cr_cinfo; /* response */
};
#define cr_textlen u.symlink.textlen
#define cr_text u.symlink.text
#define cr_specdata1 u.device.specdata1
#define cr_specdata2 u.device.specdata2
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 */
u32 * gt_bmres; /* response */
};
struct nfs4_getfh {
struct nfs_fh * gf_fhandle; /* response */
};
struct nfs4_link {
u32 ln_namelen; /* request */
const char * ln_name; /* request */
struct nfs4_change_info * ln_cinfo; /* response */
};
struct nfs4_lookup {
struct qstr * lo_name; /* request */
};
struct nfs4_open {
u32 op_share_access; /* request */
u32 op_opentype; /* request */
u32 op_createmode; /* request */
union { /* request */
struct iattr * attrs; /* UNCHECKED, GUARDED */
nfs4_verifier verifier; /* EXCLUSIVE */
} u;
struct qstr * op_name; /* request */
char * op_stateid; /* response */
struct nfs4_change_info * op_cinfo; /* response */
u32 * op_rflags; /* response */
};
#define op_attrs u.attrs
#define op_verifier u.verifier
struct nfs4_open_confirm {
char * oc_stateid; /* request */
};
struct nfs4_putfh {
struct nfs_fh * pf_fhandle; /* request */
};
struct nfs4_read {
u64 rd_offset; /* request */
u32 rd_length; /* request */
u32 *rd_eof; /* response */
u32 *rd_bytes_read; /* response */
struct page ** rd_pages; /* zero-copy data */
unsigned int rd_pgbase; /* zero-copy data */
};
struct nfs4_readdir {
u64 rd_cookie; /* request */
nfs4_verifier rd_req_verifier; /* request */
u32 rd_count; /* request */
u32 rd_bmval[2]; /* request */
nfs4_verifier rd_resp_verifier; /* response */
struct page ** rd_pages; /* zero-copy data */
unsigned int rd_pgbase; /* zero-copy data */
};
struct nfs4_readlink {
u32 rl_count; /* zero-copy data */
struct page ** rl_pages; /* zero-copy data */
};
struct nfs4_remove {
u32 rm_namelen; /* request */
const char * rm_name; /* request */
struct nfs4_change_info * rm_cinfo; /* response */
};
struct nfs4_rename {
u32 rn_oldnamelen; /* request */
const char * rn_oldname; /* request */
u32 rn_newnamelen; /* request */
const char * rn_newname; /* request */
struct nfs4_change_info * rn_src_cinfo; /* response */
struct nfs4_change_info * rn_dst_cinfo; /* response */
};
struct nfs4_setattr {
char * st_stateid; /* request */
struct iattr * st_iap; /* request */
};
struct nfs4_setclientid {
nfs4_verifier sc_verifier; /* request */
char * sc_name; /* request */
u32 sc_prog; /* request */
char sc_netid[4]; /* request */
char sc_uaddr[24]; /* request */
u32 sc_cb_ident; /* request */
};
struct nfs4_write {
u64 wr_offset; /* request */
u32 wr_stable_how; /* request */
u32 wr_len; /* request */
u32 * wr_bytes_written; /* response */
struct nfs_writeverf * wr_verf; /* response */
struct page ** wr_pages; /* zero-copy data */
unsigned int wr_pgbase; /* zero-copy data */
};
struct nfs4_op {
u32 opnum;
u32 nfserr;
union {
struct nfs4_access access;
struct nfs4_close close;
struct nfs4_commit commit;
struct nfs4_create create;
struct nfs4_getattr getattr;
struct nfs4_getfh getfh;
struct nfs4_link link;
struct nfs4_lookup lookup;
struct nfs4_open open;
struct nfs4_open_confirm open_confirm;
struct nfs4_putfh putfh;
struct nfs4_read read;
struct nfs4_readdir readdir;
struct nfs4_readlink readlink;
struct nfs4_remove remove;
struct nfs4_rename rename;
struct nfs4_setattr setattr;
struct nfs4_setclientid setclientid;
struct nfs4_write write;
} u;
};
struct nfs4_compound {
unsigned int flags; /* defined below */
struct nfs_server * server;
/* RENEW information */
int renew_index;
unsigned long timestamp;
/* scratch variables for XDR encode/decode */
int nops;
u32 * p;
u32 * end;
/* the individual COMPOUND operations */
struct nfs4_op *ops;
/* request */
int req_nops;
u32 taglen;
char * tag;
/* response */
int resp_nops;
int toplevel_status;
};
#endif /* CONFIG_NFS_V4 */
struct nfs_read_data { struct nfs_read_data {
struct rpc_task task; struct rpc_task task;
struct inode *inode; struct inode *inode;
...@@ -338,7 +551,12 @@ struct nfs_read_data { ...@@ -338,7 +551,12 @@ struct nfs_read_data {
struct nfs_readres res; struct nfs_readres res;
} v3; /* also v2 */ } v3; /* also v2 */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
/* NFSv4 data will come here... */ struct {
struct nfs4_compound compound;
struct nfs4_op ops[3];
u32 res_count;
u32 res_eof;
} v4;
#endif #endif
} u; } u;
}; };
...@@ -353,11 +571,17 @@ struct nfs_write_data { ...@@ -353,11 +571,17 @@ struct nfs_write_data {
struct page *pagevec[NFS_WRITE_MAXIOV]; struct page *pagevec[NFS_WRITE_MAXIOV];
union { union {
struct { struct {
struct nfs_writeargs args; struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; struct nfs_writeres res; /* result struct */
} v3; } v3;
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
/* NFSv4 data to come here... */ struct {
struct nfs4_compound compound;
struct nfs4_op ops[3];
u32 arg_count;
u32 arg_stable;
u32 res_count;
} v4;
#endif #endif
} u; } u;
}; };
...@@ -430,8 +654,10 @@ struct nfs_rpc_ops { ...@@ -430,8 +654,10 @@ struct nfs_rpc_ops {
*/ */
extern struct nfs_rpc_ops nfs_v2_clientops; extern struct nfs_rpc_ops nfs_v2_clientops;
extern struct nfs_rpc_ops nfs_v3_clientops; extern struct nfs_rpc_ops nfs_v3_clientops;
extern struct nfs_rpc_ops nfs_v4_clientops;
extern struct rpc_version nfs_version2; 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_program nfs_program; extern struct rpc_program nfs_program;
extern struct rpc_stat nfs_rpcstat; extern struct rpc_stat nfs_rpcstat;
......
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