Commit 9f261e01 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.linux-nfs.org/pub/linux/nfs-2.6

* git://git.linux-nfs.org/pub/linux/nfs-2.6: (74 commits)
  NFS: unmark NFS direct I/O as experimental
  NFS: add comments clarifying the use of nfs_post_op_update()
  NFSv4: rpc_mkpipe creating socket inodes w/out sk buffers
  NFS: Use SEEK_END instead of hardcoded value
  NFSv4: When mounting with a port=0 argument, substitute port=2049
  NFSv4: Poll more aggressively when handling NFS4ERR_DELAY
  NFSv4: Handle the condition NFS4ERR_FILE_OPEN
  NFSv4: Retry lease recovery if it failed during a synchronous operation.
  NFS: Don't invalidate the symlink we just stuffed into the cache
  NFS: Make read() return an ESTALE if the file has been deleted
  NFSv4: It's perfectly legal for clp to be NULL here....
  NFS: nfs_lookup - don't hash dentry when optimising away the lookup
  SUNRPC: Fix Oops in pmap_getport_done
  SUNRPC: Add refcounting to the struct rpc_xprt
  SUNRPC: Clean up soft task error handling
  SUNRPC: Handle ENETUNREACH, EHOSTUNREACH and EHOSTDOWN socket errors
  SUNRPC: rpc_delay() should not clobber the rpc_task->tk_status
  Fix a referral error Oops
  NFS: NFS_ROOT should use the new rpc_create API
  NFS: Fix up compiler warnings on 64-bit platforms in client.c
  ...

Manually resolved conflict in net/sunrpc/xprtsock.c
parents a4c12d6c 026ed5c9
...@@ -2734,6 +2734,18 @@ long blk_congestion_wait(int rw, long timeout) ...@@ -2734,6 +2734,18 @@ long blk_congestion_wait(int rw, long timeout)
EXPORT_SYMBOL(blk_congestion_wait); EXPORT_SYMBOL(blk_congestion_wait);
/**
* blk_congestion_end - wake up sleepers on a congestion queue
* @rw: READ or WRITE
*/
void blk_congestion_end(int rw)
{
wait_queue_head_t *wqh = &congestion_wqh[rw];
if (waitqueue_active(wqh))
wake_up(wqh);
}
/* /*
* Has to be called with the request spinlock acquired * Has to be called with the request spinlock acquired
*/ */
......
...@@ -1471,8 +1471,8 @@ config NFS_V4 ...@@ -1471,8 +1471,8 @@ config NFS_V4
If unsure, say N. If unsure, say N.
config NFS_DIRECTIO config NFS_DIRECTIO
bool "Allow direct I/O on NFS files (EXPERIMENTAL)" bool "Allow direct I/O on NFS files"
depends on NFS_FS && EXPERIMENTAL depends on NFS_FS
help help
This option enables applications to perform uncached I/O on files This option enables applications to perform uncached I/O on files
in NFS file systems using the O_DIRECT open() flag. When O_DIRECT in NFS file systems using the O_DIRECT open() flag. When O_DIRECT
......
...@@ -828,17 +828,19 @@ void d_instantiate(struct dentry *entry, struct inode * inode) ...@@ -828,17 +828,19 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
* (or otherwise set) by the caller to indicate that it is now * (or otherwise set) by the caller to indicate that it is now
* in use by the dcache. * in use by the dcache.
*/ */
struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) static struct dentry *__d_instantiate_unique(struct dentry *entry,
struct inode *inode)
{ {
struct dentry *alias; struct dentry *alias;
int len = entry->d_name.len; int len = entry->d_name.len;
const char *name = entry->d_name.name; const char *name = entry->d_name.name;
unsigned int hash = entry->d_name.hash; unsigned int hash = entry->d_name.hash;
BUG_ON(!list_empty(&entry->d_alias)); if (!inode) {
spin_lock(&dcache_lock); entry->d_inode = NULL;
if (!inode) return NULL;
goto do_negative; }
list_for_each_entry(alias, &inode->i_dentry, d_alias) { list_for_each_entry(alias, &inode->i_dentry, d_alias) {
struct qstr *qstr = &alias->d_name; struct qstr *qstr = &alias->d_name;
...@@ -851,19 +853,35 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) ...@@ -851,19 +853,35 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
if (memcmp(qstr->name, name, len)) if (memcmp(qstr->name, name, len))
continue; continue;
dget_locked(alias); dget_locked(alias);
spin_unlock(&dcache_lock);
BUG_ON(!d_unhashed(alias));
iput(inode);
return alias; return alias;
} }
list_add(&entry->d_alias, &inode->i_dentry); list_add(&entry->d_alias, &inode->i_dentry);
do_negative:
entry->d_inode = inode; entry->d_inode = inode;
fsnotify_d_instantiate(entry, inode); fsnotify_d_instantiate(entry, inode);
return NULL;
}
struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
{
struct dentry *result;
BUG_ON(!list_empty(&entry->d_alias));
spin_lock(&dcache_lock);
result = __d_instantiate_unique(entry, inode);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
if (!result) {
security_d_instantiate(entry, inode); security_d_instantiate(entry, inode);
return NULL; return NULL;
}
BUG_ON(!d_unhashed(result));
iput(inode);
return result;
} }
EXPORT_SYMBOL(d_instantiate_unique); EXPORT_SYMBOL(d_instantiate_unique);
/** /**
...@@ -1235,6 +1253,11 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) ...@@ -1235,6 +1253,11 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list)
hlist_add_head_rcu(&entry->d_hash, list); hlist_add_head_rcu(&entry->d_hash, list);
} }
static void _d_rehash(struct dentry * entry)
{
__d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
}
/** /**
* d_rehash - add an entry back to the hash * d_rehash - add an entry back to the hash
* @entry: dentry to add to the hash * @entry: dentry to add to the hash
...@@ -1244,11 +1267,9 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) ...@@ -1244,11 +1267,9 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list)
void d_rehash(struct dentry * entry) void d_rehash(struct dentry * entry)
{ {
struct hlist_head *list = d_hash(entry->d_parent, entry->d_name.hash);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
spin_lock(&entry->d_lock); spin_lock(&entry->d_lock);
__d_rehash(entry, list); _d_rehash(entry);
spin_unlock(&entry->d_lock); spin_unlock(&entry->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
...@@ -1386,6 +1407,120 @@ void d_move(struct dentry * dentry, struct dentry * target) ...@@ -1386,6 +1407,120 @@ void d_move(struct dentry * dentry, struct dentry * target)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
/*
* Prepare an anonymous dentry for life in the superblock's dentry tree as a
* named dentry in place of the dentry to be replaced.
*/
static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
{
struct dentry *dparent, *aparent;
switch_names(dentry, anon);
do_switch(dentry->d_name.len, anon->d_name.len);
do_switch(dentry->d_name.hash, anon->d_name.hash);
dparent = dentry->d_parent;
aparent = anon->d_parent;
dentry->d_parent = (aparent == anon) ? dentry : aparent;
list_del(&dentry->d_u.d_child);
if (!IS_ROOT(dentry))
list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
else
INIT_LIST_HEAD(&dentry->d_u.d_child);
anon->d_parent = (dparent == dentry) ? anon : dparent;
list_del(&anon->d_u.d_child);
if (!IS_ROOT(anon))
list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs);
else
INIT_LIST_HEAD(&anon->d_u.d_child);
anon->d_flags &= ~DCACHE_DISCONNECTED;
}
/**
* d_materialise_unique - introduce an inode into the tree
* @dentry: candidate dentry
* @inode: inode to bind to the dentry, to which aliases may be attached
*
* Introduces an dentry into the tree, substituting an extant disconnected
* root directory alias in its place if there is one
*/
struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
{
struct dentry *alias, *actual;
BUG_ON(!d_unhashed(dentry));
spin_lock(&dcache_lock);
if (!inode) {
actual = dentry;
dentry->d_inode = NULL;
goto found_lock;
}
/* See if a disconnected directory already exists as an anonymous root
* that we should splice into the tree instead */
if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) {
spin_lock(&alias->d_lock);
/* Is this a mountpoint that we could splice into our tree? */
if (IS_ROOT(alias))
goto connect_mountpoint;
if (alias->d_name.len == dentry->d_name.len &&
alias->d_parent == dentry->d_parent &&
memcmp(alias->d_name.name,
dentry->d_name.name,
dentry->d_name.len) == 0)
goto replace_with_alias;
spin_unlock(&alias->d_lock);
/* Doh! Seem to be aliasing directories for some reason... */
dput(alias);
}
/* Add a unique reference */
actual = __d_instantiate_unique(dentry, inode);
if (!actual)
actual = dentry;
else if (unlikely(!d_unhashed(actual)))
goto shouldnt_be_hashed;
found_lock:
spin_lock(&actual->d_lock);
found:
_d_rehash(actual);
spin_unlock(&actual->d_lock);
spin_unlock(&dcache_lock);
if (actual == dentry) {
security_d_instantiate(dentry, inode);
return NULL;
}
iput(inode);
return actual;
/* Convert the anonymous/root alias into an ordinary dentry */
connect_mountpoint:
__d_materialise_dentry(dentry, alias);
/* Replace the candidate dentry with the alias in the tree */
replace_with_alias:
__d_drop(alias);
actual = alias;
goto found;
shouldnt_be_hashed:
spin_unlock(&dcache_lock);
BUG();
goto shouldnt_be_hashed;
}
/** /**
* d_path - return the path of a dentry * d_path - return the path of a dentry
* @dentry: dentry to report * @dentry: dentry to report
...@@ -1784,6 +1919,7 @@ EXPORT_SYMBOL(d_instantiate); ...@@ -1784,6 +1919,7 @@ EXPORT_SYMBOL(d_instantiate);
EXPORT_SYMBOL(d_invalidate); EXPORT_SYMBOL(d_invalidate);
EXPORT_SYMBOL(d_lookup); EXPORT_SYMBOL(d_lookup);
EXPORT_SYMBOL(d_move); EXPORT_SYMBOL(d_move);
EXPORT_SYMBOL_GPL(d_materialise_unique);
EXPORT_SYMBOL(d_path); EXPORT_SYMBOL(d_path);
EXPORT_SYMBOL(d_prune_aliases); EXPORT_SYMBOL(d_prune_aliases);
EXPORT_SYMBOL(d_rehash); EXPORT_SYMBOL(d_rehash);
......
...@@ -151,11 +151,13 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) ...@@ -151,11 +151,13 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
int int
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
{ {
struct rpc_clnt *client = NFS_CLIENT(inode);
struct sockaddr_in addr;
struct nlm_host *host; struct nlm_host *host;
struct nlm_rqst *call; struct nlm_rqst *call;
sigset_t oldset; sigset_t oldset;
unsigned long flags; unsigned long flags;
int status, proto, vers; int status, vers;
vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
if (NFS_PROTO(inode)->version > 3) { if (NFS_PROTO(inode)->version > 3) {
...@@ -163,10 +165,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -163,10 +165,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
return -ENOLCK; return -ENOLCK;
} }
/* Retrieve transport protocol from NFS client */ rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
proto = NFS_CLIENT(inode)->cl_xprt->prot; host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers);
host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
if (host == NULL) if (host == NULL)
return -ENOLCK; return -ENOLCK;
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#define NLM_HOST_REBIND (60 * HZ) #define NLM_HOST_REBIND (60 * HZ)
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
#define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr)
static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
static unsigned long next_gc; static unsigned long next_gc;
...@@ -167,7 +166,6 @@ struct rpc_clnt * ...@@ -167,7 +166,6 @@ struct rpc_clnt *
nlm_bind_host(struct nlm_host *host) nlm_bind_host(struct nlm_host *host)
{ {
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct rpc_xprt *xprt;
dprintk("lockd: nlm_bind_host(%08x)\n", dprintk("lockd: nlm_bind_host(%08x)\n",
(unsigned)ntohl(host->h_addr.sin_addr.s_addr)); (unsigned)ntohl(host->h_addr.sin_addr.s_addr));
...@@ -179,7 +177,6 @@ nlm_bind_host(struct nlm_host *host) ...@@ -179,7 +177,6 @@ nlm_bind_host(struct nlm_host *host)
* RPC rebind is required * RPC rebind is required
*/ */
if ((clnt = host->h_rpcclnt) != NULL) { if ((clnt = host->h_rpcclnt) != NULL) {
xprt = clnt->cl_xprt;
if (time_after_eq(jiffies, host->h_nextrebind)) { if (time_after_eq(jiffies, host->h_nextrebind)) {
rpc_force_rebind(clnt); rpc_force_rebind(clnt);
host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_nextrebind = jiffies + NLM_HOST_REBIND;
...@@ -187,31 +184,37 @@ nlm_bind_host(struct nlm_host *host) ...@@ -187,31 +184,37 @@ nlm_bind_host(struct nlm_host *host)
host->h_nextrebind - jiffies); host->h_nextrebind - jiffies);
} }
} else { } else {
xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); unsigned long increment = nlmsvc_timeout * HZ;
if (IS_ERR(xprt)) struct rpc_timeout timeparms = {
goto forgetit; .to_initval = increment,
.to_increment = increment,
xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); .to_maxval = increment * 6UL,
xprt->resvport = 1; /* NLM requires a reserved port */ .to_retries = 5U,
};
/* Existing NLM servers accept AUTH_UNIX only */ struct rpc_create_args args = {
clnt = rpc_new_client(xprt, host->h_name, &nlm_program, .protocol = host->h_proto,
host->h_version, RPC_AUTH_UNIX); .address = (struct sockaddr *)&host->h_addr,
if (IS_ERR(clnt)) .addrsize = sizeof(host->h_addr),
goto forgetit; .timeout = &timeparms,
clnt->cl_autobind = 1; /* turn on pmap queries */ .servername = host->h_name,
clnt->cl_softrtry = 1; /* All queries are soft */ .program = &nlm_program,
.version = host->h_version,
.authflavor = RPC_AUTH_UNIX,
.flags = (RPC_CLNT_CREATE_HARDRTRY |
RPC_CLNT_CREATE_AUTOBIND),
};
clnt = rpc_create(&args);
if (!IS_ERR(clnt))
host->h_rpcclnt = clnt; host->h_rpcclnt = clnt;
else {
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
clnt = NULL;
}
} }
mutex_unlock(&host->h_mutex); mutex_unlock(&host->h_mutex);
return clnt; return clnt;
forgetit:
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
mutex_unlock(&host->h_mutex);
return NULL;
} }
/* /*
......
...@@ -109,30 +109,23 @@ nsm_unmonitor(struct nlm_host *host) ...@@ -109,30 +109,23 @@ nsm_unmonitor(struct nlm_host *host)
static struct rpc_clnt * static struct rpc_clnt *
nsm_create(void) nsm_create(void)
{ {
struct rpc_xprt *xprt; struct sockaddr_in sin = {
struct rpc_clnt *clnt; .sin_family = AF_INET,
struct sockaddr_in sin; .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
.sin_port = 0,
sin.sin_family = AF_INET; };
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); struct rpc_create_args args = {
sin.sin_port = 0; .protocol = IPPROTO_UDP,
.address = (struct sockaddr *)&sin,
xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); .addrsize = sizeof(sin),
if (IS_ERR(xprt)) .servername = "localhost",
return (struct rpc_clnt *)xprt; .program = &nsm_program,
xprt->resvport = 1; /* NSM requires a reserved port */ .version = SM_VERSION,
.authflavor = RPC_AUTH_NULL,
clnt = rpc_create_client(xprt, "localhost", .flags = (RPC_CLNT_CREATE_ONESHOT),
&nsm_program, SM_VERSION, };
RPC_AUTH_NULL);
if (IS_ERR(clnt)) return rpc_create(&args);
goto out_err;
clnt->cl_softrtry = 1;
clnt->cl_oneshot = 1;
return clnt;
out_err:
return clnt;
} }
/* /*
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
obj-$(CONFIG_NFS_FS) += nfs.o obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \ nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
proc.o read.o symlink.o unlink.o write.o \ pagelist.o proc.o read.o symlink.o unlink.o \
namespace.o write.o namespace.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_V3_ACL) += nfs3acl.o
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK #define NFSDBG_FACILITY NFSDBG_CALLBACK
...@@ -36,6 +37,21 @@ static struct svc_program nfs4_callback_program; ...@@ -36,6 +37,21 @@ static struct svc_program nfs4_callback_program;
unsigned int nfs_callback_set_tcpport; unsigned int nfs_callback_set_tcpport;
unsigned short nfs_callback_tcpport; unsigned short nfs_callback_tcpport;
static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535;
static int param_set_port(const char *val, struct kernel_param *kp)
{
char *endp;
int num = simple_strtol(val, &endp, 0);
if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
return -EINVAL;
*((int *)kp->arg) = num;
return 0;
}
module_param_call(callback_tcpport, param_set_port, param_get_int,
&nfs_callback_set_tcpport, 0644);
/* /*
* This is the callback kernel thread. * This is the callback kernel thread.
...@@ -134,10 +150,8 @@ int nfs_callback_up(void) ...@@ -134,10 +150,8 @@ int nfs_callback_up(void)
/* /*
* Kill the server process if it is not already up. * Kill the server process if it is not already up.
*/ */
int nfs_callback_down(void) void nfs_callback_down(void)
{ {
int ret = 0;
lock_kernel(); lock_kernel();
mutex_lock(&nfs_callback_mutex); mutex_lock(&nfs_callback_mutex);
nfs_callback_info.users--; nfs_callback_info.users--;
...@@ -149,20 +163,19 @@ int nfs_callback_down(void) ...@@ -149,20 +163,19 @@ int nfs_callback_down(void)
} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
mutex_unlock(&nfs_callback_mutex); mutex_unlock(&nfs_callback_mutex);
unlock_kernel(); unlock_kernel();
return ret;
} }
static int nfs_callback_authenticate(struct svc_rqst *rqstp) static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{ {
struct in_addr *addr = &rqstp->rq_addr.sin_addr; struct sockaddr_in *addr = &rqstp->rq_addr;
struct nfs4_client *clp; struct nfs_client *clp;
/* Don't talk to strangers */ /* Don't talk to strangers */
clp = nfs4_find_client(addr); clp = nfs_find_client(addr, 4);
if (clp == NULL) if (clp == NULL)
return SVC_DROP; return SVC_DROP;
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr)); dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr));
nfs4_put_client(clp); nfs_put_client(clp);
switch (rqstp->rq_authop->flavour) { switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL: case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL) if (rqstp->rq_proc != CB_NULL)
......
...@@ -62,8 +62,13 @@ struct cb_recallargs { ...@@ -62,8 +62,13 @@ struct cb_recallargs {
extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
#ifdef CONFIG_NFS_V4
extern int nfs_callback_up(void); extern int nfs_callback_up(void);
extern int nfs_callback_down(void); extern void nfs_callback_down(void);
#else
#define nfs_callback_up() (0)
#define nfs_callback_down() do {} while(0)
#endif
extern unsigned int nfs_callback_set_tcpport; extern unsigned int nfs_callback_set_tcpport;
extern unsigned short nfs_callback_tcpport; extern unsigned short nfs_callback_tcpport;
......
...@@ -10,19 +10,20 @@ ...@@ -10,19 +10,20 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
#include "delegation.h" #include "delegation.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK #define NFSDBG_FACILITY NFSDBG_CALLBACK
unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
{ {
struct nfs4_client *clp; struct nfs_client *clp;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct nfs_inode *nfsi; struct nfs_inode *nfsi;
struct inode *inode; struct inode *inode;
res->bitmap[0] = res->bitmap[1] = 0; res->bitmap[0] = res->bitmap[1] = 0;
res->status = htonl(NFS4ERR_BADHANDLE); res->status = htonl(NFS4ERR_BADHANDLE);
clp = nfs4_find_client(&args->addr->sin_addr); clp = nfs_find_client(args->addr, 4);
if (clp == NULL) if (clp == NULL)
goto out; goto out;
inode = nfs_delegation_find_inode(clp, &args->fh); inode = nfs_delegation_find_inode(clp, &args->fh);
...@@ -48,7 +49,7 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres ...@@ -48,7 +49,7 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
up_read(&nfsi->rwsem); up_read(&nfsi->rwsem);
iput(inode); iput(inode);
out_putclient: out_putclient:
nfs4_put_client(clp); nfs_put_client(clp);
out: out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
return res->status; return res->status;
...@@ -56,12 +57,12 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres ...@@ -56,12 +57,12 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
{ {
struct nfs4_client *clp; struct nfs_client *clp;
struct inode *inode; struct inode *inode;
unsigned res; unsigned res;
res = htonl(NFS4ERR_BADHANDLE); res = htonl(NFS4ERR_BADHANDLE);
clp = nfs4_find_client(&args->addr->sin_addr); clp = nfs_find_client(args->addr, 4);
if (clp == NULL) if (clp == NULL)
goto out; goto out;
inode = nfs_delegation_find_inode(clp, &args->fh); inode = nfs_delegation_find_inode(clp, &args->fh);
...@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) ...@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
} }
iput(inode); iput(inode);
out_putclient: out_putclient:
nfs4_put_client(clp); nfs_put_client(clp);
out: out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
return res; return res;
......
This diff is collapsed.
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h" #include "delegation.h"
#include "internal.h"
static struct nfs_delegation *nfs_alloc_delegation(void) static struct nfs_delegation *nfs_alloc_delegation(void)
{ {
...@@ -52,7 +53,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ ...@@ -52,7 +53,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */ /* kill_proc(fl->fl_pid, SIGLOST, 1); */
case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_CLIENTID:
nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state); nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client);
goto out_err; goto out_err;
} }
} }
...@@ -114,7 +115,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st ...@@ -114,7 +115,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
*/ */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{ {
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
int status = 0; int status = 0;
...@@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct ...@@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
sizeof(delegation->stateid)) != 0 || sizeof(delegation->stateid)) != 0 ||
delegation->type != nfsi->delegation->type) { delegation->type != nfsi->delegation->type) {
printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
__FUNCTION__, NIPQUAD(clp->cl_addr)); __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr));
status = -EIO; status = -EIO;
} }
} }
...@@ -176,7 +177,7 @@ static void nfs_msync_inode(struct inode *inode) ...@@ -176,7 +177,7 @@ static void nfs_msync_inode(struct inode *inode)
*/ */
int __nfs_inode_return_delegation(struct inode *inode) int __nfs_inode_return_delegation(struct inode *inode)
{ {
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
int res = 0; int res = 0;
...@@ -208,7 +209,7 @@ int __nfs_inode_return_delegation(struct inode *inode) ...@@ -208,7 +209,7 @@ int __nfs_inode_return_delegation(struct inode *inode)
*/ */
void nfs_return_all_delegations(struct super_block *sb) void nfs_return_all_delegations(struct super_block *sb)
{ {
struct nfs4_client *clp = NFS_SB(sb)->nfs4_state; struct nfs_client *clp = NFS_SB(sb)->nfs_client;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct inode *inode; struct inode *inode;
...@@ -232,7 +233,7 @@ void nfs_return_all_delegations(struct super_block *sb) ...@@ -232,7 +233,7 @@ void nfs_return_all_delegations(struct super_block *sb)
int nfs_do_expire_all_delegations(void *ptr) int nfs_do_expire_all_delegations(void *ptr)
{ {
struct nfs4_client *clp = ptr; struct nfs_client *clp = ptr;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct inode *inode; struct inode *inode;
...@@ -254,11 +255,11 @@ int nfs_do_expire_all_delegations(void *ptr) ...@@ -254,11 +255,11 @@ int nfs_do_expire_all_delegations(void *ptr)
} }
out: out:
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
nfs4_put_client(clp); nfs_put_client(clp);
module_put_and_exit(0); module_put_and_exit(0);
} }
void nfs_expire_all_delegations(struct nfs4_client *clp) void nfs_expire_all_delegations(struct nfs_client *clp)
{ {
struct task_struct *task; struct task_struct *task;
...@@ -266,17 +267,17 @@ void nfs_expire_all_delegations(struct nfs4_client *clp) ...@@ -266,17 +267,17 @@ void nfs_expire_all_delegations(struct nfs4_client *clp)
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
task = kthread_run(nfs_do_expire_all_delegations, clp, task = kthread_run(nfs_do_expire_all_delegations, clp,
"%u.%u.%u.%u-delegreturn", "%u.%u.%u.%u-delegreturn",
NIPQUAD(clp->cl_addr)); NIPQUAD(clp->cl_addr.sin_addr));
if (!IS_ERR(task)) if (!IS_ERR(task))
return; return;
nfs4_put_client(clp); nfs_put_client(clp);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
/* /*
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error. * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
*/ */
void nfs_handle_cb_pathdown(struct nfs4_client *clp) void nfs_handle_cb_pathdown(struct nfs_client *clp)
{ {
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct inode *inode; struct inode *inode;
...@@ -299,7 +300,7 @@ void nfs_handle_cb_pathdown(struct nfs4_client *clp) ...@@ -299,7 +300,7 @@ void nfs_handle_cb_pathdown(struct nfs4_client *clp)
struct recall_threadargs { struct recall_threadargs {
struct inode *inode; struct inode *inode;
struct nfs4_client *clp; struct nfs_client *clp;
const nfs4_stateid *stateid; const nfs4_stateid *stateid;
struct completion started; struct completion started;
...@@ -310,7 +311,7 @@ static int recall_thread(void *data) ...@@ -310,7 +311,7 @@ static int recall_thread(void *data)
{ {
struct recall_threadargs *args = (struct recall_threadargs *)data; struct recall_threadargs *args = (struct recall_threadargs *)data;
struct inode *inode = igrab(args->inode); struct inode *inode = igrab(args->inode);
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
...@@ -371,7 +372,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s ...@@ -371,7 +372,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
/* /*
* Retrieve the inode associated with a delegation * Retrieve the inode associated with a delegation
*/ */
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle) struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle)
{ {
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct inode *res = NULL; struct inode *res = NULL;
...@@ -389,7 +390,7 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf ...@@ -389,7 +390,7 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf
/* /*
* Mark all delegations as needing to be reclaimed * Mark all delegations as needing to be reclaimed
*/ */
void nfs_delegation_mark_reclaim(struct nfs4_client *clp) void nfs_delegation_mark_reclaim(struct nfs_client *clp)
{ {
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
...@@ -401,7 +402,7 @@ void nfs_delegation_mark_reclaim(struct nfs4_client *clp) ...@@ -401,7 +402,7 @@ void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
/* /*
* Reap all unclaimed delegations after reboot recovery is done * Reap all unclaimed delegations after reboot recovery is done
*/ */
void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
{ {
struct nfs_delegation *delegation, *n; struct nfs_delegation *delegation, *n;
LIST_HEAD(head); LIST_HEAD(head);
...@@ -423,7 +424,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) ...@@ -423,7 +424,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{ {
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
int res = 0; int res = 0;
......
...@@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st ...@@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
int __nfs_inode_return_delegation(struct inode *inode); int __nfs_inode_return_delegation(struct inode *inode);
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
void nfs_return_all_delegations(struct super_block *sb); void nfs_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs4_client *clp); void nfs_expire_all_delegations(struct nfs_client *clp);
void nfs_handle_cb_pathdown(struct nfs4_client *clp); void nfs_handle_cb_pathdown(struct nfs_client *clp);
void nfs_delegation_mark_reclaim(struct nfs4_client *clp); void nfs_delegation_mark_reclaim(struct nfs_client *clp);
void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
/* NFSv4 delegation-related procedures */ /* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
......
This diff is collapsed.
...@@ -111,7 +111,7 @@ nfs_file_open(struct inode *inode, struct file *filp) ...@@ -111,7 +111,7 @@ nfs_file_open(struct inode *inode, struct file *filp)
nfs_inc_stats(inode, NFSIOS_VFSOPEN); nfs_inc_stats(inode, NFSIOS_VFSOPEN);
lock_kernel(); lock_kernel();
res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp); res = NFS_PROTO(inode)->file_open(inode, filp);
unlock_kernel(); unlock_kernel();
return res; return res;
} }
...@@ -157,7 +157,7 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) ...@@ -157,7 +157,7 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
{ {
/* origin == SEEK_END => we must revalidate the cached file length */ /* origin == SEEK_END => we must revalidate the cached file length */
if (origin == 2) { if (origin == SEEK_END) {
struct inode *inode = filp->f_mapping->host; struct inode *inode = filp->f_mapping->host;
int retval = nfs_revalidate_file_size(inode, filp); int retval = nfs_revalidate_file_size(inode, filp);
if (retval < 0) if (retval < 0)
......
/* getroot.c: get the root dentry for an NFS mount
*
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
#include <linux/namei.h>
#include <linux/namespace.h>
#include <linux/security.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "nfs4_fs.h"
#include "delegation.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CLIENT
#define NFS_PARANOIA 1
/*
* get an NFS2/NFS3 root dentry from the root filehandle
*/
struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
{
struct nfs_server *server = NFS_SB(sb);
struct nfs_fsinfo fsinfo;
struct nfs_fattr fattr;
struct dentry *mntroot;
struct inode *inode;
int error;
/* create a dummy root dentry with dummy inode for this superblock */
if (!sb->s_root) {
struct nfs_fh dummyfh;
struct dentry *root;
struct inode *iroot;
memset(&dummyfh, 0, sizeof(dummyfh));
memset(&fattr, 0, sizeof(fattr));
nfs_fattr_init(&fattr);
fattr.valid = NFS_ATTR_FATTR;
fattr.type = NFDIR;
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
fattr.nlink = 2;
iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
return ERR_PTR(PTR_ERR(iroot));
root = d_alloc_root(iroot);
if (!root) {
iput(iroot);
return ERR_PTR(-ENOMEM);
}
sb->s_root = root;
}
/* get the actual root for this mount */
fsinfo.fattr = &fattr;
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
if (error < 0) {
dprintk("nfs_get_root: getattr error = %d\n", -error);
return ERR_PTR(error);
}
inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
return ERR_PTR(PTR_ERR(inode));
}
/* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already
* exists, we'll pick it up at this point and use it as the root
*/
mntroot = d_alloc_anon(inode);
if (!mntroot) {
iput(inode);
dprintk("nfs_get_root: get root dentry failed\n");
return ERR_PTR(-ENOMEM);
}
security_d_instantiate(mntroot, inode);
if (!mntroot->d_op)
mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
return mntroot;
}
#ifdef CONFIG_NFS_V4
/*
* Do a simple pathwalk from the root FH of the server to the nominated target
* of the mountpoint
* - give error on symlinks
* - give error on ".." occurring in the path
* - follow traversals
*/
int nfs4_path_walk(struct nfs_server *server,
struct nfs_fh *mntfh,
const char *path)
{
struct nfs_fsinfo fsinfo;
struct nfs_fattr fattr;
struct nfs_fh lastfh;
struct qstr name;
int ret;
//int referral_count = 0;
dprintk("--> nfs4_path_walk(,,%s)\n", path);
fsinfo.fattr = &fattr;
nfs_fattr_init(&fattr);
if (*path++ != '/') {
dprintk("nfs4_get_root: Path does not begin with a slash\n");
return -EINVAL;
}
/* Start by getting the root filehandle from the server */
ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
if (ret < 0) {
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
return ret;
}
if (fattr.type != NFDIR) {
printk(KERN_ERR "nfs4_get_root:"
" getroot encountered non-directory\n");
return -ENOTDIR;
}
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
printk(KERN_ERR "nfs4_get_root:"
" getroot obtained referral\n");
return -EREMOTE;
}
next_component:
dprintk("Next: %s\n", path);
/* extract the next bit of the path */
if (!*path)
goto path_walk_complete;
name.name = path;
while (*path && *path != '/')
path++;
name.len = path - (const char *) name.name;
eat_dot_dir:
while (*path == '/')
path++;
if (path[0] == '.' && (path[1] == '/' || !path[1])) {
path += 2;
goto eat_dot_dir;
}
if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
) {
printk(KERN_ERR "nfs4_get_root:"
" Mount path contains reference to \"..\"\n");
return -EINVAL;
}
/* lookup the next FH in the sequence */
memcpy(&lastfh, mntfh, sizeof(lastfh));
dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
mntfh, &fattr);
if (ret < 0) {
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
return ret;
}
if (fattr.type != NFDIR) {
printk(KERN_ERR "nfs4_get_root:"
" lookupfh encountered non-directory\n");
return -ENOTDIR;
}
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
printk(KERN_ERR "nfs4_get_root:"
" lookupfh obtained referral\n");
return -EREMOTE;
}
goto next_component;
path_walk_complete:
memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
dprintk("<-- nfs4_path_walk() = 0\n");
return 0;
}
/*
* get an NFS4 root dentry from the root filehandle
*/
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
{
struct nfs_server *server = NFS_SB(sb);
struct nfs_fattr fattr;
struct dentry *mntroot;
struct inode *inode;
int error;
dprintk("--> nfs4_get_root()\n");
/* create a dummy root dentry with dummy inode for this superblock */
if (!sb->s_root) {
struct nfs_fh dummyfh;
struct dentry *root;
struct inode *iroot;
memset(&dummyfh, 0, sizeof(dummyfh));
memset(&fattr, 0, sizeof(fattr));
nfs_fattr_init(&fattr);
fattr.valid = NFS_ATTR_FATTR;
fattr.type = NFDIR;
fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
fattr.nlink = 2;
iroot = nfs_fhget(sb, &dummyfh, &fattr);
if (IS_ERR(iroot))
return ERR_PTR(PTR_ERR(iroot));
root = d_alloc_root(iroot);
if (!root) {
iput(iroot);
return ERR_PTR(-ENOMEM);
}
sb->s_root = root;
}
/* get the info about the server and filesystem */
error = nfs4_server_capabilities(server, mntfh);
if (error < 0) {
dprintk("nfs_get_root: getcaps error = %d\n",
-error);
return ERR_PTR(error);
}
/* get the actual root for this mount */
error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
if (error < 0) {
dprintk("nfs_get_root: getattr error = %d\n", -error);
return ERR_PTR(error);
}
inode = nfs_fhget(sb, mntfh, &fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
return ERR_PTR(PTR_ERR(inode));
}
/* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already
* exists, we'll pick it up at this point and use it as the root
*/
mntroot = d_alloc_anon(inode);
if (!mntroot) {
iput(inode);
dprintk("nfs_get_root: get root dentry failed\n");
return ERR_PTR(-ENOMEM);
}
security_d_instantiate(mntroot, inode);
if (!mntroot->d_op)
mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
dprintk("<-- nfs4_get_root()\n");
return mntroot;
}
#endif /* CONFIG_NFS_V4 */
...@@ -57,6 +57,20 @@ ...@@ -57,6 +57,20 @@
/* Default cache timeout is 10 minutes */ /* Default cache timeout is 10 minutes */
unsigned int nfs_idmap_cache_timeout = 600 * HZ; unsigned int nfs_idmap_cache_timeout = 600 * HZ;
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
{
char *endp;
int num = simple_strtol(val, &endp, 0);
int jif = num * HZ;
if (endp == val || *endp || num < 0 || jif < num)
return -EINVAL;
*((int *)kp->arg) = jif;
return 0;
}
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
&nfs_idmap_cache_timeout, 0644);
struct idmap_hashent { struct idmap_hashent {
unsigned long ih_expires; unsigned long ih_expires;
__u32 ih_id; __u32 ih_id;
...@@ -70,7 +84,6 @@ struct idmap_hashtable { ...@@ -70,7 +84,6 @@ struct idmap_hashtable {
}; };
struct idmap { struct idmap {
char idmap_path[48];
struct dentry *idmap_dentry; struct dentry *idmap_dentry;
wait_queue_head_t idmap_wq; wait_queue_head_t idmap_wq;
struct idmap_msg idmap_im; struct idmap_msg idmap_im;
...@@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_ops = { ...@@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_ops = {
.destroy_msg = idmap_pipe_destroy_msg, .destroy_msg = idmap_pipe_destroy_msg,
}; };
void int
nfs_idmap_new(struct nfs4_client *clp) nfs_idmap_new(struct nfs_client *clp)
{ {
struct idmap *idmap; struct idmap *idmap;
int error;
if (clp->cl_idmap != NULL) BUG_ON(clp->cl_idmap != NULL);
return;
if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
return;
snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
"%s/idmap", clp->cl_rpcclient->cl_pathname); return -ENOMEM;
idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap",
idmap, &idmap_upcall_ops, 0); idmap, &idmap_upcall_ops, 0);
if (IS_ERR(idmap->idmap_dentry)) { if (IS_ERR(idmap->idmap_dentry)) {
error = PTR_ERR(idmap->idmap_dentry);
kfree(idmap); kfree(idmap);
return; return error;
} }
mutex_init(&idmap->idmap_lock); mutex_init(&idmap->idmap_lock);
...@@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp) ...@@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp)
idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
clp->cl_idmap = idmap; clp->cl_idmap = idmap;
return 0;
} }
void void
nfs_idmap_delete(struct nfs4_client *clp) nfs_idmap_delete(struct nfs_client *clp)
{ {
struct idmap *idmap = clp->cl_idmap; struct idmap *idmap = clp->cl_idmap;
...@@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) ...@@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
return (hash); return (hash);
} }
int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
{ {
struct idmap *idmap = clp->cl_idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
} }
int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
{ {
struct idmap *idmap = clp->cl_idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
} }
int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf) int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
{ {
struct idmap *idmap = clp->cl_idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
} }
int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf) int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
{ {
struct idmap *idmap = clp->cl_idmap; struct idmap *idmap = clp->cl_idmap;
......
...@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync) ...@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync)
void nfs_clear_inode(struct inode *inode) void nfs_clear_inode(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode);
struct rpc_cred *cred;
/* /*
* The following should never happen... * The following should never happen...
*/ */
BUG_ON(nfs_have_writebacks(inode)); BUG_ON(nfs_have_writebacks(inode));
BUG_ON (!list_empty(&nfsi->open_files)); BUG_ON(!list_empty(&NFS_I(inode)->open_files));
BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
nfs_zap_acl_cache(inode); nfs_zap_acl_cache(inode);
cred = nfsi->cache_access.cred; nfs_access_zap_cache(inode);
if (cred)
put_rpccred(cred);
BUG_ON(atomic_read(&nfsi->data_updates) != 0);
} }
/** /**
...@@ -242,13 +237,13 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -242,13 +237,13 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
/* Why so? Because we want revalidate for devices/FIFOs, and /* Why so? Because we want revalidate for devices/FIFOs, and
* that's precisely what we have in nfs_file_inode_operations. * that's precisely what we have in nfs_file_inode_operations.
*/ */
inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
inode->i_fop = &nfs_file_operations; inode->i_fop = &nfs_file_operations;
inode->i_data.a_ops = &nfs_file_aops; inode->i_data.a_ops = &nfs_file_aops;
inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops; inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
inode->i_fop = &nfs_dir_operations; inode->i_fop = &nfs_dir_operations;
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
&& fattr->size <= NFS_LIMIT_READDIRPLUS) && fattr->size <= NFS_LIMIT_READDIRPLUS)
...@@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies; nfsi->attrtimeo_timestamp = jiffies;
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
nfsi->cache_access.cred = NULL; nfsi->access_cache = RB_ROOT;
unlock_new_inode(inode); unlock_new_inode(inode);
} else } else
...@@ -722,14 +717,12 @@ void nfs_end_data_update(struct inode *inode) ...@@ -722,14 +717,12 @@ void nfs_end_data_update(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
if (!nfs_have_delegation(inode, FMODE_READ)) { /* Directories: invalidate page cache */
/* Directories and symlinks: invalidate page cache */ if (S_ISDIR(inode->i_mode)) {
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
}
nfsi->cache_change_attribute = jiffies; nfsi->cache_change_attribute = jiffies;
atomic_dec(&nfsi->data_updates); atomic_dec(&nfsi->data_updates);
} }
...@@ -847,6 +840,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -847,6 +840,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
* *
* After an operation that has changed the inode metadata, mark the * After an operation that has changed the inode metadata, mark the
* attribute cache as being invalid, then try to update it. * attribute cache as being invalid, then try to update it.
*
* NB: if the server didn't return any post op attributes, this
* function will force the retrieval of attributes before the next
* NFS request. Thus it should be used only for operations that
* are expected to change one or more attributes, to avoid
* unnecessary NFS requests and trips through nfs_update_inode().
*/ */
int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{ {
...@@ -1025,7 +1024,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1025,7 +1024,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
out_fileid: out_fileid:
printk(KERN_ERR "NFS: server %s error: fileid changed\n" printk(KERN_ERR "NFS: server %s error: fileid changed\n"
"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
NFS_SERVER(inode)->hostname, inode->i_sb->s_id, NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
(long long)nfsi->fileid, (long long)fattr->fileid); (long long)nfsi->fileid, (long long)fattr->fileid);
goto out_err; goto out_err;
} }
...@@ -1109,6 +1108,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) ...@@ -1109,6 +1108,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
INIT_LIST_HEAD(&nfsi->dirty); INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit); INIT_LIST_HEAD(&nfsi->commit);
INIT_LIST_HEAD(&nfsi->open_files); INIT_LIST_HEAD(&nfsi->open_files);
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0); atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0; nfsi->ndirty = 0;
...@@ -1144,6 +1145,10 @@ static int __init init_nfs_fs(void) ...@@ -1144,6 +1145,10 @@ static int __init init_nfs_fs(void)
{ {
int err; int err;
err = nfs_fs_proc_init();
if (err)
goto out5;
err = nfs_init_nfspagecache(); err = nfs_init_nfspagecache();
if (err) if (err)
goto out4; goto out4;
...@@ -1184,6 +1189,8 @@ static int __init init_nfs_fs(void) ...@@ -1184,6 +1189,8 @@ static int __init init_nfs_fs(void)
out3: out3:
nfs_destroy_nfspagecache(); nfs_destroy_nfspagecache();
out4: out4:
nfs_fs_proc_exit();
out5:
return err; return err;
} }
...@@ -1198,6 +1205,7 @@ static void __exit exit_nfs_fs(void) ...@@ -1198,6 +1205,7 @@ static void __exit exit_nfs_fs(void)
rpc_proc_unregister("nfs"); rpc_proc_unregister("nfs");
#endif #endif
unregister_nfs_fs(); unregister_nfs_fs();
nfs_fs_proc_exit();
} }
/* Not quite true; I just maintain it */ /* Not quite true; I just maintain it */
......
...@@ -4,6 +4,18 @@ ...@@ -4,6 +4,18 @@
#include <linux/mount.h> #include <linux/mount.h>
struct nfs_string;
struct nfs_mount_data;
struct nfs4_mount_data;
/* Maximum number of readahead requests
* FIXME: this should really be a sysctl so that users may tune it to suit
* their needs. People that do NFS over a slow network, might for
* instance want to reduce it to something closer to 1 for improved
* interactive response.
*/
#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
struct nfs_clone_mount { struct nfs_clone_mount {
const struct super_block *sb; const struct super_block *sb;
const struct dentry *dentry; const struct dentry *dentry;
...@@ -15,7 +27,40 @@ struct nfs_clone_mount { ...@@ -15,7 +27,40 @@ struct nfs_clone_mount {
rpc_authflavor_t authflavor; rpc_authflavor_t authflavor;
}; };
/* namespace-nfs4.c */ /* client.c */
extern struct rpc_program nfs_program;
extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
struct nfs_fh *);
extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
const char *,
const struct sockaddr_in *,
const char *,
const char *,
rpc_authflavor_t,
struct nfs_fh *);
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
struct nfs_fh *);
extern void nfs_free_server(struct nfs_server *server);
extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *,
struct nfs_fattr *);
#ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void);
#else
static inline int nfs_fs_proc_init(void)
{
return 0;
}
static inline void nfs_fs_proc_exit(void)
{
}
#endif
/* nfs4namespace.c */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
#else #else
...@@ -46,6 +91,7 @@ extern void nfs_destroy_directcache(void); ...@@ -46,6 +91,7 @@ extern void nfs_destroy_directcache(void);
#endif #endif
/* nfs2xdr.c */ /* nfs2xdr.c */
extern int nfs_stat_to_errno(int);
extern struct rpc_procinfo nfs_procedures[]; extern struct rpc_procinfo nfs_procedures[];
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
...@@ -54,8 +100,9 @@ extern struct rpc_procinfo nfs3_procedures[]; ...@@ -54,8 +100,9 @@ extern struct rpc_procinfo nfs3_procedures[];
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
/* nfs4xdr.c */ /* nfs4xdr.c */
extern int nfs_stat_to_errno(int); #ifdef CONFIG_NFS_V4
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
#endif
/* nfs4proc.c */ /* nfs4proc.c */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
...@@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, ...@@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
struct page *page); struct page *page);
#endif #endif
/* dir.c */
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
/* inode.c */ /* inode.c */
extern struct inode *nfs_alloc_inode(struct super_block *sb); extern struct inode *nfs_alloc_inode(struct super_block *sb);
extern void nfs_destroy_inode(struct inode *); extern void nfs_destroy_inode(struct inode *);
...@@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inode *); ...@@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inode *);
#endif #endif
/* super.c */ /* super.c */
extern struct file_system_type nfs_referral_nfs4_fs_type; extern struct file_system_type nfs_xdev_fs_type;
extern struct file_system_type clone_nfs_fs_type;
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern struct file_system_type clone_nfs4_fs_type; extern struct file_system_type nfs4_xdev_fs_type;
extern struct file_system_type nfs4_referral_fs_type;
#endif #endif
extern struct rpc_stat nfs_rpcstat; extern struct rpc_stat nfs_rpcstat;
...@@ -88,21 +138,20 @@ extern int __init register_nfs_fs(void); ...@@ -88,21 +138,20 @@ extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void); extern void __exit unregister_nfs_fs(void);
/* namespace.c */ /* namespace.c */
extern char *nfs_path(const char *base, const struct dentry *dentry, extern char *nfs_path(const char *base,
const struct dentry *droot,
const struct dentry *dentry,
char *buffer, ssize_t buflen); char *buffer, ssize_t buflen);
/* /* getroot.c */
* Determine the mount path as a string extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
*/
static inline char *
nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
{
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen); extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
#else
return NULL; extern int nfs4_path_walk(struct nfs_server *server,
struct nfs_fh *mntfh,
const char *path);
#endif #endif
}
/* /*
* Determine the device name as a string * Determine the device name as a string
...@@ -111,7 +160,8 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent, ...@@ -111,7 +160,8 @@ static inline char *nfs_devname(const struct vfsmount *mnt_parent,
const struct dentry *dentry, const struct dentry *dentry,
char *buffer, ssize_t buflen) char *buffer, ssize_t buflen)
{ {
return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen); return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
dentry, buffer, buflen);
} }
/* /*
...@@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize) ...@@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
} }
/*
* Check if the string represents a "valid" IPv4 address
*/
static inline int valid_ipaddr4(const char *buf)
{
int rc, count, in[4];
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
if (rc != 4)
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
return -EINVAL;
}
return 0;
}
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/net.h> #include <linux/net.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
...@@ -77,22 +76,19 @@ static struct rpc_clnt * ...@@ -77,22 +76,19 @@ static struct rpc_clnt *
mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
int protocol) int protocol)
{ {
struct rpc_xprt *xprt; struct rpc_create_args args = {
struct rpc_clnt *clnt; .protocol = protocol,
.address = (struct sockaddr *)srvaddr,
xprt = xprt_create_proto(protocol, srvaddr, NULL); .addrsize = sizeof(*srvaddr),
if (IS_ERR(xprt)) .servername = hostname,
return (struct rpc_clnt *)xprt; .program = &mnt_program,
.version = version,
clnt = rpc_create_client(xprt, hostname, .authflavor = RPC_AUTH_UNIX,
&mnt_program, version, .flags = (RPC_CLNT_CREATE_ONESHOT |
RPC_AUTH_UNIX); RPC_CLNT_CREATE_INTR),
if (!IS_ERR(clnt)) { };
clnt->cl_softrtry = 1;
clnt->cl_oneshot = 1; return rpc_create(&args);
clnt->cl_intr = 1;
}
return clnt;
} }
/* /*
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* linux/fs/nfs/namespace.c * linux/fs/nfs/namespace.c
* *
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
* - Modified by David Howells <dhowells@redhat.com>
* *
* NFS namespace * NFS namespace
*/ */
...@@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; ...@@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
/* /*
* nfs_path - reconstruct the path given an arbitrary dentry * nfs_path - reconstruct the path given an arbitrary dentry
* @base - arbitrary string to prepend to the path * @base - arbitrary string to prepend to the path
* @droot - pointer to root dentry for mountpoint
* @dentry - pointer to dentry * @dentry - pointer to dentry
* @buffer - result buffer * @buffer - result buffer
* @buflen - length of buffer * @buflen - length of buffer
...@@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; ...@@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
* This is mainly for use in figuring out the path on the * This is mainly for use in figuring out the path on the
* server side when automounting on top of an existing partition. * server side when automounting on top of an existing partition.
*/ */
char *nfs_path(const char *base, const struct dentry *dentry, char *nfs_path(const char *base,
const struct dentry *droot,
const struct dentry *dentry,
char *buffer, ssize_t buflen) char *buffer, ssize_t buflen)
{ {
char *end = buffer+buflen; char *end = buffer+buflen;
...@@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry, ...@@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry,
*--end = '\0'; *--end = '\0';
buflen--; buflen--;
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
while (!IS_ROOT(dentry)) { while (!IS_ROOT(dentry) && dentry != droot) {
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen + 1; buflen -= namelen + 1;
if (buflen < 0) if (buflen < 0)
...@@ -96,15 +100,18 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -96,15 +100,18 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
struct nfs_fattr fattr; struct nfs_fattr fattr;
int err; int err;
dprintk("--> nfs_follow_mountpoint()\n");
BUG_ON(IS_ROOT(dentry)); BUG_ON(IS_ROOT(dentry));
dprintk("%s: enter\n", __FUNCTION__); dprintk("%s: enter\n", __FUNCTION__);
dput(nd->dentry); dput(nd->dentry);
nd->dentry = dget(dentry); nd->dentry = dget(dentry);
if (d_mountpoint(nd->dentry))
goto out_follow;
/* Look it up again */ /* Look it up again */
parent = dget_parent(nd->dentry); parent = dget_parent(nd->dentry);
err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr); err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
&nd->dentry->d_name,
&fh, &fattr);
dput(parent); dput(parent);
if (err != 0) if (err != 0)
goto out_err; goto out_err;
...@@ -132,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -132,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
out: out:
dprintk("%s: done, returned %d\n", __FUNCTION__, err); dprintk("%s: done, returned %d\n", __FUNCTION__, err);
dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
return ERR_PTR(err); return ERR_PTR(err);
out_err: out_err:
path_release(nd); path_release(nd);
...@@ -172,22 +181,23 @@ void nfs_release_automount_timer(void) ...@@ -172,22 +181,23 @@ void nfs_release_automount_timer(void)
/* /*
* Clone a mountpoint of the appropriate type * Clone a mountpoint of the appropriate type
*/ */
static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname, static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
const char *devname,
struct nfs_clone_mount *mountdata) struct nfs_clone_mount *mountdata)
{ {
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
struct vfsmount *mnt = NULL; struct vfsmount *mnt = NULL;
switch (server->rpc_ops->version) { switch (server->nfs_client->cl_nfsversion) {
case 2: case 2:
case 3: case 3:
mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
break; break;
case 4: case 4:
mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata); mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata);
} }
return mnt; return mnt;
#else #else
return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
#endif #endif
} }
...@@ -213,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, ...@@ -213,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
char *page = (char *) __get_free_page(GFP_USER); char *page = (char *) __get_free_page(GFP_USER);
char *devname; char *devname;
dprintk("--> nfs_do_submount()\n");
dprintk("%s: submounting on %s/%s\n", __FUNCTION__, dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
dentry->d_parent->d_name.name, dentry->d_parent->d_name.name,
dentry->d_name.name); dentry->d_name.name);
...@@ -227,5 +239,7 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, ...@@ -227,5 +239,7 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
free_page((unsigned long)page); free_page((unsigned long)page);
out: out:
dprintk("%s: done\n", __FUNCTION__); dprintk("%s: done\n", __FUNCTION__);
dprintk("<-- nfs_do_submount() = %p\n", mnt);
return mnt; return mnt;
} }
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
#define NFS_readdirargs_sz (NFS_fhandle_sz+2) #define NFS_readdirargs_sz (NFS_fhandle_sz+2)
#define NFS_attrstat_sz (1+NFS_fattr_sz) #define NFS_attrstat_sz (1+NFS_fattr_sz)
...@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) ...@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
static int static int
nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
{ {
struct xdr_buf *sndbuf = &req->rq_snd_buf;
size_t pad;
p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen); p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_array(p, args->topath, args->tolen); *p++ = htonl(args->pathlen);
sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
/*
* xdr_encode_pages may have added a few bytes to ensure the
* pathname ends on a 4-byte boundary. Start encoding the
* attributes after the pad bytes.
*/
pad = sndbuf->tail->iov_len;
if (pad > 0)
p++;
p = xdr_encode_sattr(p, args->sattr); p = xdr_encode_sattr(p, args->sattr);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
return 0; return 0;
} }
......
...@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, ...@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
} }
/* /*
* Bare-bones access to getattr: this is for nfs_read_super. * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
*/ */
static int static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
...@@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
int status; int status;
status = do_proc_get_root(server->client, fhandle, info); status = do_proc_get_root(server->client, fhandle, info);
if (status && server->client_sys != server->client) if (status && server->nfs_client->cl_rpcclient != server->client)
status = do_proc_get_root(server->client_sys, fhandle, info); status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info);
return status; return status;
} }
...@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) ...@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
} }
static int static int
nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
struct iattr *sattr, struct nfs_fh *fhandle, unsigned int len, struct iattr *sattr)
struct nfs_fattr *fattr)
{ {
struct nfs_fattr dir_attr; struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_attr;
struct nfs3_symlinkargs arg = { struct nfs3_symlinkargs arg = {
.fromfh = NFS_FH(dir), .fromfh = NFS_FH(dir),
.fromname = name->name, .fromname = dentry->d_name.name,
.fromlen = name->len, .fromlen = dentry->d_name.len,
.topath = path->name, .pages = &page,
.tolen = path->len, .pathlen = len,
.sattr = sattr .sattr = sattr
}; };
struct nfs3_diropres res = { struct nfs3_diropres res = {
.dir_attr = &dir_attr, .dir_attr = &dir_attr,
.fh = fhandle, .fh = &fhandle,
.fattr = fattr .fattr = &fattr
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
...@@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, ...@@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS3_MAXPATHLEN) if (len > NFS3_MAXPATHLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
dprintk("NFS call symlink %s\n", dentry->d_name.name);
nfs_fattr_init(&dir_attr); nfs_fattr_init(&dir_attr);
nfs_fattr_init(fattr); nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_post_op_update_inode(dir, &dir_attr); nfs_post_op_update_inode(dir, &dir_attr);
if (status != 0)
goto out;
status = nfs_instantiate(dentry, &fhandle, &fattr);
out:
dprintk("NFS reply symlink: %d\n", status); dprintk("NFS reply symlink: %d\n", status);
return status; return status;
} }
...@@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
dprintk("NFS call fsinfo\n"); dprintk("NFS call fsinfo\n");
nfs_fattr_init(info->fattr); nfs_fattr_init(info->fattr);
status = rpc_call_sync(server->client_sys, &msg, 0); status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
dprintk("NFS reply fsinfo: %d\n", status); dprintk("NFS reply fsinfo: %d\n", status);
return status; return status;
} }
...@@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
} }
struct nfs_rpc_ops nfs_v3_clientops = { const 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 = &nfs3_dir_inode_operations, .dir_inode_ops = &nfs3_dir_inode_operations,
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#define NFS3_writeargs_sz (NFS3_fh_sz+5) #define NFS3_writeargs_sz (NFS3_fh_sz+5)
#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
...@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args ...@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args
p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen); p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_sattr(p, args->sattr); p = xdr_encode_sattr(p, args->sattr);
p = xdr_encode_array(p, args->topath, args->tolen); *p++ = htonl(args->pathlen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* Copy the page */
xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
return 0; return 0;
} }
......
...@@ -42,55 +42,6 @@ enum nfs4_client_state { ...@@ -42,55 +42,6 @@ enum nfs4_client_state {
NFS4CLNT_LEASE_EXPIRED, NFS4CLNT_LEASE_EXPIRED,
}; };
/*
* The nfs4_client identifies our client state to the server.
*/
struct nfs4_client {
struct list_head cl_servers; /* Global list of servers */
struct in_addr cl_addr; /* Server identifier */
u64 cl_clientid; /* constant */
nfs4_verifier cl_confirm;
unsigned long cl_state;
u32 cl_lockowner_id;
/*
* The following rwsem ensures exclusive access to the server
* while we recover the state following a lease expiration.
*/
struct rw_semaphore cl_sem;
struct list_head cl_delegations;
struct list_head cl_state_owners;
struct list_head cl_unused;
int cl_nunused;
spinlock_t cl_lock;
atomic_t cl_count;
struct rpc_clnt * cl_rpcclient;
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;
struct rpc_wait_queue cl_rpcwaitq;
/* used for the setclientid verifier */
struct timespec cl_boot_time;
/* 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];
unsigned char cl_id_uniquifier;
};
/* /*
* struct rpc_sequence ensures that RPC calls are sent in the exact * struct rpc_sequence ensures that RPC calls are sent in the exact
* order that they appear on the list. * order that they appear on the list.
...@@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status ...@@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
struct nfs4_state_owner { struct nfs4_state_owner {
spinlock_t so_lock; spinlock_t so_lock;
struct list_head so_list; /* per-clientid list of state_owners */ struct list_head so_list; /* per-clientid list of state_owners */
struct nfs4_client *so_client; struct nfs_client *so_client;
u32 so_id; /* 32-bit identifier, unique */ u32 so_id; /* 32-bit identifier, unique */
atomic_t so_count; atomic_t so_count;
...@@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); ...@@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_map_errors(int err); extern int nfs4_map_errors(int err);
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *); extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *);
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *); extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *); extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *); extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
...@@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2]; ...@@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2];
extern const u32 nfs4_fs_locations_bitmap[2]; extern const u32 nfs4_fs_locations_bitmap[2];
/* nfs4renewd.c */ /* nfs4renewd.c */
extern void nfs4_schedule_state_renewal(struct nfs4_client *); extern void nfs4_schedule_state_renewal(struct nfs_client *);
extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);
extern void nfs4_kill_renewd(struct nfs4_client *); extern void nfs4_kill_renewd(struct nfs_client *);
extern void nfs4_renew_state(void *); extern void nfs4_renew_state(void *);
/* nfs4state.c */ /* nfs4state.c */
extern void init_nfsv4_state(struct nfs_server *); struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
extern void destroy_nfsv4_state(struct nfs_server *); extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
extern struct nfs4_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs4_client *clp);
extern struct nfs4_client *nfs4_find_client(struct in_addr *);
struct rpc_cred *nfs4_get_renew_cred(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 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 void nfs4_put_state_owner(struct nfs4_state_owner *);
...@@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state ...@@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state
extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct nfs4_state *, mode_t); extern void nfs4_close_state(struct nfs4_state *, mode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
extern void nfs4_schedule_state_recovery(struct nfs4_client *); extern void nfs4_schedule_state_recovery(struct nfs_client *);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
...@@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_version1; ...@@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_version1;
#else #else
#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_close_state(a, b) do { } while (0) #define nfs4_close_state(a, b) do { } while (0)
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* linux/fs/nfs/nfs4namespace.c * linux/fs/nfs/nfs4namespace.c
* *
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
* - Modified by David Howells <dhowells@redhat.com>
* *
* NFSv4 namespace * NFSv4 namespace
*/ */
...@@ -23,7 +24,7 @@ ...@@ -23,7 +24,7 @@
/* /*
* Check if fs_root is valid * Check if fs_root is valid
*/ */
static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
char *buffer, ssize_t buflen) char *buffer, ssize_t buflen)
{ {
char *end = buffer + buflen; char *end = buffer + buflen;
...@@ -34,7 +35,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, ...@@ -34,7 +35,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
n = pathname->ncomponents; n = pathname->ncomponents;
while (--n >= 0) { while (--n >= 0) {
struct nfs4_string *component = &pathname->components[n]; const struct nfs4_string *component = &pathname->components[n];
buflen -= component->len + 1; buflen -= component->len + 1;
if (buflen < 0) if (buflen < 0)
goto Elong; goto Elong;
...@@ -47,6 +48,68 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, ...@@ -47,6 +48,68 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
} }
/*
* Determine the mount path as a string
*/
static char *nfs4_path(const struct vfsmount *mnt_parent,
const struct dentry *dentry,
char *buffer, ssize_t buflen)
{
const char *srvpath;
srvpath = strchr(mnt_parent->mnt_devname, ':');
if (srvpath)
srvpath++;
else
srvpath = mnt_parent->mnt_devname;
return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
}
/*
* Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
* believe to be the server path to this dentry
*/
static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
const struct dentry *dentry,
const struct nfs4_fs_locations *locations,
char *page, char *page2)
{
const char *path, *fs_path;
path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
if (IS_ERR(path))
return PTR_ERR(path);
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
if (IS_ERR(fs_path))
return PTR_ERR(fs_path);
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
dprintk("%s: path %s does not begin with fsroot %s\n",
__FUNCTION__, path, fs_path);
return -ENOENT;
}
return 0;
}
/*
* Check if the string represents a "valid" IPv4 address
*/
static inline int valid_ipaddr4(const char *buf)
{
int rc, count, in[4];
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
if (rc != 4)
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
return -EINVAL;
}
return 0;
}
/** /**
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
...@@ -60,7 +123,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, ...@@ -60,7 +123,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
*/ */
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
const struct dentry *dentry, const struct dentry *dentry,
struct nfs4_fs_locations *locations) const struct nfs4_fs_locations *locations)
{ {
struct vfsmount *mnt = ERR_PTR(-ENOENT); struct vfsmount *mnt = ERR_PTR(-ENOENT);
struct nfs_clone_mount mountdata = { struct nfs_clone_mount mountdata = {
...@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, ...@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
.dentry = dentry, .dentry = dentry,
.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
}; };
char *page, *page2; char *page = NULL, *page2 = NULL;
char *path, *fs_path;
char *devname; char *devname;
int loc, s; int loc, s, error;
if (locations == NULL || locations->nlocations <= 0) if (locations == NULL || locations->nlocations <= 0)
goto out; goto out;
...@@ -79,36 +141,30 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, ...@@ -79,36 +141,30 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
dprintk("%s: referral at %s/%s\n", __FUNCTION__, dprintk("%s: referral at %s/%s\n", __FUNCTION__,
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
/* Ensure fs path is a prefix of current dentry path */
page = (char *) __get_free_page(GFP_USER); page = (char *) __get_free_page(GFP_USER);
if (page == NULL) if (!page)
goto out; goto out;
page2 = (char *) __get_free_page(GFP_USER); page2 = (char *) __get_free_page(GFP_USER);
if (page2 == NULL) if (!page2)
goto out; goto out;
path = nfs4_path(dentry, page, PAGE_SIZE); /* Ensure fs path is a prefix of current dentry path */
if (IS_ERR(path)) error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
goto out_free; if (error < 0) {
mnt = ERR_PTR(error);
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); goto out;
if (IS_ERR(fs_path))
goto out_free;
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
goto out_free;
} }
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
if (IS_ERR(devname)) { if (IS_ERR(devname)) {
mnt = (struct vfsmount *)devname; mnt = (struct vfsmount *)devname;
goto out_free; goto out;
} }
loc = 0; loc = 0;
while (loc < locations->nlocations && IS_ERR(mnt)) { while (loc < locations->nlocations && IS_ERR(mnt)) {
struct nfs4_fs_location *location = &locations->locations[loc]; const struct nfs4_fs_location *location = &locations->locations[loc];
char *mnt_path; char *mnt_path;
if (location == NULL || location->nservers <= 0 || if (location == NULL || location->nservers <= 0 ||
...@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, ...@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
addr.sin_port = htons(NFS_PORT); addr.sin_port = htons(NFS_PORT);
mountdata.addr = &addr; mountdata.addr = &addr;
mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata); mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata);
if (!IS_ERR(mnt)) { if (!IS_ERR(mnt)) {
break; break;
} }
...@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, ...@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
loc++; loc++;
} }
out_free:
free_page((unsigned long)page);
free_page((unsigned long)page2);
out: out:
free_page((unsigned long) page);
free_page((unsigned long) page2);
dprintk("%s: done\n", __FUNCTION__); dprintk("%s: done\n", __FUNCTION__);
return mnt; return mnt;
} }
...@@ -165,7 +220,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, ...@@ -165,7 +220,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
*/ */
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
{ {
struct vfsmount *mnt = ERR_PTR(-ENOENT); struct vfsmount *mnt = ERR_PTR(-ENOMEM);
struct dentry *parent; struct dentry *parent;
struct nfs4_fs_locations *fs_locations = NULL; struct nfs4_fs_locations *fs_locations = NULL;
struct page *page; struct page *page;
...@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr ...@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr
goto out_free; goto out_free;
/* Get locations */ /* Get locations */
mnt = ERR_PTR(-ENOENT);
parent = dget_parent(dentry); parent = dget_parent(dentry);
dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); dprintk("%s: getting locations for %s/%s\n",
__FUNCTION__, parent->d_name.name, dentry->d_name.name);
err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
dput(parent); dput(parent);
if (err != 0 || fs_locations->nlocations <= 0 || if (err != 0 ||
fs_locations->nlocations <= 0 ||
fs_locations->fs_path.ncomponents <= 0) fs_locations->fs_path.ncomponents <= 0)
goto out_free; goto out_free;
......
This diff is collapsed.
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
void void
nfs4_renew_state(void *data) nfs4_renew_state(void *data)
{ {
struct nfs4_client *clp = (struct nfs4_client *)data; struct nfs_client *clp = (struct nfs_client *)data;
struct rpc_cred *cred; struct rpc_cred *cred;
long lease, timeout; long lease, timeout;
unsigned long last, now; unsigned long last, now;
...@@ -108,7 +108,7 @@ nfs4_renew_state(void *data) ...@@ -108,7 +108,7 @@ nfs4_renew_state(void *data)
/* Must be called with clp->cl_sem locked for writes */ /* Must be called with clp->cl_sem locked for writes */
void void
nfs4_schedule_state_renewal(struct nfs4_client *clp) nfs4_schedule_state_renewal(struct nfs_client *clp)
{ {
long timeout; long timeout;
...@@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_client *clp) ...@@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_client *clp)
__FUNCTION__, (timeout + HZ - 1) / HZ); __FUNCTION__, (timeout + HZ - 1) / HZ);
cancel_delayed_work(&clp->cl_renewd); cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout); schedule_delayed_work(&clp->cl_renewd, timeout);
set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
void void
nfs4_renewd_prepare_shutdown(struct nfs_server *server) nfs4_renewd_prepare_shutdown(struct nfs_server *server)
{ {
struct nfs4_client *clp = server->nfs4_state;
if (!clp)
return;
flush_scheduled_work(); 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 void
nfs4_kill_renewd(struct nfs4_client *clp) nfs4_kill_renewd(struct nfs_client *clp)
{ {
down_read(&clp->cl_sem); down_read(&clp->cl_sem);
if (!list_empty(&clp->cl_superblocks)) {
up_read(&clp->cl_sem);
return;
}
cancel_delayed_work(&clp->cl_renewd); cancel_delayed_work(&clp->cl_renewd);
up_read(&clp->cl_sem); up_read(&clp->cl_sem);
flush_scheduled_work(); flush_scheduled_work();
......
...@@ -50,149 +50,15 @@ ...@@ -50,149 +50,15 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
#include "delegation.h" #include "delegation.h"
#include "internal.h"
#define OPENOWNER_POOL_SIZE 8 #define OPENOWNER_POOL_SIZE 8
const nfs4_stateid zero_stateid; const nfs4_stateid zero_stateid;
static DEFINE_SPINLOCK(state_spinlock);
static LIST_HEAD(nfs4_clientid_list); static LIST_HEAD(nfs4_clientid_list);
void static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
init_nfsv4_state(struct nfs_server *server)
{
server->nfs4_state = NULL;
INIT_LIST_HEAD(&server->nfs4_siblings);
}
void
destroy_nfsv4_state(struct nfs_server *server)
{
kfree(server->mnt_path);
server->mnt_path = NULL;
if (server->nfs4_state) {
nfs4_put_client(server->nfs4_state);
server->nfs4_state = NULL;
}
}
/*
* 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...
*/
static struct nfs4_client *
nfs4_alloc_client(struct in_addr *addr)
{
struct nfs4_client *clp;
if (nfs_callback_up() < 0)
return NULL;
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
nfs_callback_down();
return NULL;
}
memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_state_owners);
INIT_LIST_HEAD(&clp->cl_unused);
spin_lock_init(&clp->cl_lock);
atomic_set(&clp->cl_count, 1);
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
INIT_LIST_HEAD(&clp->cl_superblocks);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_rpcclient = ERR_PTR(-EINVAL);
clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
return clp;
}
static void
nfs4_free_client(struct nfs4_client *clp)
{
struct nfs4_state_owner *sp;
while (!list_empty(&clp->cl_unused)) {
sp = list_entry(clp->cl_unused.next,
struct nfs4_state_owner,
so_list);
list_del(&sp->so_list);
kfree(sp);
}
BUG_ON(!list_empty(&clp->cl_state_owners));
nfs_idmap_delete(clp);
if (!IS_ERR(clp->cl_rpcclient))
rpc_shutdown_client(clp->cl_rpcclient);
kfree(clp);
nfs_callback_down();
}
static struct nfs4_client *__nfs4_find_client(struct in_addr *addr)
{
struct nfs4_client *clp;
list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) {
atomic_inc(&clp->cl_count);
return clp;
}
}
return NULL;
}
struct nfs4_client *nfs4_find_client(struct in_addr *addr)
{
struct nfs4_client *clp;
spin_lock(&state_spinlock);
clp = __nfs4_find_client(addr);
spin_unlock(&state_spinlock);
return clp;
}
struct nfs4_client *
nfs4_get_client(struct in_addr *addr)
{
struct nfs4_client *clp, *new = NULL;
spin_lock(&state_spinlock);
for (;;) {
clp = __nfs4_find_client(addr);
if (clp != NULL)
break;
clp = new;
if (clp != NULL) {
list_add(&clp->cl_servers, &nfs4_clientid_list);
new = NULL;
break;
}
spin_unlock(&state_spinlock);
new = nfs4_alloc_client(addr);
spin_lock(&state_spinlock);
if (new == NULL)
break;
}
spin_unlock(&state_spinlock);
if (new)
nfs4_free_client(new);
return clp;
}
void
nfs4_put_client(struct nfs4_client *clp)
{
if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock))
return;
list_del(&clp->cl_servers);
spin_unlock(&state_spinlock);
BUG_ON(!list_empty(&clp->cl_superblocks));
rpc_wake_up(&clp->cl_rpcwaitq);
nfs4_kill_renewd(clp);
nfs4_free_client(clp);
}
static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
{ {
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
nfs_callback_tcpport, cred); nfs_callback_tcpport, cred);
...@@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) ...@@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
} }
u32 u32
nfs4_alloc_lockowner_id(struct nfs4_client *clp) nfs4_alloc_lockowner_id(struct nfs_client *clp)
{ {
return clp->cl_lockowner_id ++; return clp->cl_lockowner_id ++;
} }
static struct nfs4_state_owner * static struct nfs4_state_owner *
nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred)
{ {
struct nfs4_state_owner *sp = NULL; struct nfs4_state_owner *sp = NULL;
...@@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) ...@@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
return sp; return sp;
} }
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct rpc_cred *cred = NULL; struct rpc_cred *cred = NULL;
...@@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) ...@@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
return cred; return cred;
} }
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
...@@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) ...@@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
} }
static struct nfs4_state_owner * static struct nfs4_state_owner *
nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
{ {
struct nfs4_state_owner *sp, *res = NULL; struct nfs4_state_owner *sp, *res = NULL;
...@@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void) ...@@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void)
void void
nfs4_drop_state_owner(struct nfs4_state_owner *sp) nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{ {
struct nfs4_client *clp = sp->so_client; struct nfs_client *clp = sp->so_client;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
list_del_init(&sp->so_list); list_del_init(&sp->so_list);
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
...@@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) ...@@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
*/ */
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{ {
struct nfs4_client *clp = server->nfs4_state; struct nfs_client *clp = server->nfs_client;
struct nfs4_state_owner *sp, *new; struct nfs4_state_owner *sp, *new;
get_rpccred(cred); get_rpccred(cred);
...@@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct ...@@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
*/ */
void nfs4_put_state_owner(struct nfs4_state_owner *sp) void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{ {
struct nfs4_client *clp = sp->so_client; struct nfs_client *clp = sp->so_client;
struct rpc_cred *cred = sp->so_cred; struct rpc_cred *cred = sp->so_cred;
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
...@@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) ...@@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{ {
struct nfs4_lock_state *lsp; struct nfs4_lock_state *lsp;
struct nfs4_client *clp = state->owner->so_client; struct nfs_client *clp = state->owner->so_client;
lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
if (lsp == NULL) if (lsp == NULL)
...@@ -752,7 +618,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) ...@@ -752,7 +618,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
static int reclaimer(void *); static int reclaimer(void *);
static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) static inline void nfs4_clear_recover_bit(struct nfs_client *clp)
{ {
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
...@@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) ...@@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
/* /*
* State recovery routine * State recovery routine
*/ */
static void nfs4_recover_state(struct nfs4_client *clp) static void nfs4_recover_state(struct nfs_client *clp)
{ {
struct task_struct *task; struct task_struct *task;
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
NIPQUAD(clp->cl_addr)); NIPQUAD(clp->cl_addr.sin_addr));
if (!IS_ERR(task)) if (!IS_ERR(task))
return; return;
nfs4_clear_recover_bit(clp); nfs4_clear_recover_bit(clp);
nfs4_put_client(clp); nfs_put_client(clp);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
/* /*
* Schedule a state recovery attempt * Schedule a state recovery attempt
*/ */
void nfs4_schedule_state_recovery(struct nfs4_client *clp) void nfs4_schedule_state_recovery(struct nfs_client *clp)
{ {
if (!clp) if (!clp)
return; return;
...@@ -879,7 +745,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n ...@@ -879,7 +745,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n
return status; return status;
} }
static void nfs4_state_mark_reclaim(struct nfs4_client *clp) static void nfs4_state_mark_reclaim(struct nfs_client *clp)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct nfs4_state *state; struct nfs4_state *state;
...@@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) ...@@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
static int reclaimer(void *ptr) static int reclaimer(void *ptr)
{ {
struct nfs4_client *clp = ptr; struct nfs_client *clp = ptr;
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct nfs4_state_recovery_ops *ops; struct nfs4_state_recovery_ops *ops;
struct rpc_cred *cred; struct rpc_cred *cred;
...@@ -970,12 +836,12 @@ static int reclaimer(void *ptr) ...@@ -970,12 +836,12 @@ static int reclaimer(void *ptr)
if (status == -NFS4ERR_CB_PATH_DOWN) if (status == -NFS4ERR_CB_PATH_DOWN)
nfs_handle_cb_pathdown(clp); nfs_handle_cb_pathdown(clp);
nfs4_clear_recover_bit(clp); nfs4_clear_recover_bit(clp);
nfs4_put_client(clp); nfs_put_client(clp);
module_put_and_exit(0); module_put_and_exit(0);
return 0; return 0;
out_error: out_error:
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
NIPQUAD(clp->cl_addr.s_addr), -status); NIPQUAD(clp->cl_addr.sin_addr), -status);
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
goto out; goto out;
} }
......
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
/* Mapping from NFS error code to "errno" error code. */ /* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO #define errno_NFSERR_IO EIO
static int nfs_stat_to_errno(int); static int nfs4_stat_to_errno(int);
/* NFSv4 COMPOUND tags are only wanted for debugging purposes */ /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
#ifdef DEBUG #ifdef DEBUG
...@@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int); ...@@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int);
#define decode_link_maxsz (op_decode_hdr_maxsz + 5) #define decode_link_maxsz (op_decode_hdr_maxsz + 5)
#define encode_symlink_maxsz (op_encode_hdr_maxsz + \ #define encode_symlink_maxsz (op_encode_hdr_maxsz + \
1 + nfs4_name_maxsz + \ 1 + nfs4_name_maxsz + \
nfs4_path_maxsz + \ 1 + \
nfs4_fattr_maxsz) nfs4_fattr_maxsz)
#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
#define encode_create_maxsz (op_encode_hdr_maxsz + \ #define encode_create_maxsz (op_encode_hdr_maxsz + \
...@@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
if (iap->ia_valid & ATTR_MODE) if (iap->ia_valid & ATTR_MODE)
len += 4; len += 4;
if (iap->ia_valid & ATTR_UID) { if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name); owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
if (owner_namelen < 0) { if (owner_namelen < 0) {
printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
iap->ia_uid); iap->ia_uid);
...@@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
len += 4 + (XDR_QUADLEN(owner_namelen) << 2); len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
} }
if (iap->ia_valid & ATTR_GID) { if (iap->ia_valid & ATTR_GID) {
owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group); owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
if (owner_grouplen < 0) { if (owner_grouplen < 0) {
printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
iap->ia_gid); iap->ia_gid);
...@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c ...@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
switch (create->ftype) { switch (create->ftype) {
case NF4LNK: case NF4LNK:
RESERVE_SPACE(4 + create->u.symlink->len); RESERVE_SPACE(4);
WRITE32(create->u.symlink->len); WRITE32(create->u.symlink.len);
WRITEMEM(create->u.symlink->name, create->u.symlink->len); xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
break; break;
case NF4BLK: case NF4CHR: case NF4BLK: case NF4CHR:
...@@ -1160,7 +1160,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con ...@@ -1160,7 +1160,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con
return 0; return 0;
} }
static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid) static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
{ {
uint32_t *p; uint32_t *p;
...@@ -1246,7 +1246,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien ...@@ -1246,7 +1246,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien
return 0; return 0;
} }
static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state) static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
{ {
uint32_t *p; uint32_t *p;
...@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str ...@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str
/* /*
* a RENEW request * a RENEW request
*/ */
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
...@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf ...@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf
/* /*
* a SETCLIENTID_CONFIRM request * a SETCLIENTID_CONFIRM request
*/ */
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
...@@ -2127,12 +2127,12 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) ...@@ -2127,12 +2127,12 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
} }
READ32(nfserr); READ32(nfserr);
if (nfserr != NFS_OK) if (nfserr != NFS_OK)
return -nfs_stat_to_errno(nfserr); return -nfs4_stat_to_errno(nfserr);
return 0; return 0;
} }
/* Dummy routine */ /* Dummy routine */
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
{ {
uint32_t *p; uint32_t *p;
unsigned int strlen; unsigned int strlen;
...@@ -2636,7 +2636,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t ...@@ -2636,7 +2636,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
return 0; return 0;
} }
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid) static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid)
{ {
uint32_t len, *p; uint32_t len, *p;
...@@ -2660,7 +2660,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf ...@@ -2660,7 +2660,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
return 0; return 0;
} }
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid) static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid)
{ {
uint32_t len, *p; uint32_t len, *p;
...@@ -3051,9 +3051,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons ...@@ -3051,9 +3051,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
fattr->mode |= fmode; fattr->mode |= fmode;
if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
goto xdr_error; goto xdr_error;
if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0) if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
goto xdr_error; goto xdr_error;
if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0) if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
goto xdr_error; goto xdr_error;
if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
goto xdr_error; goto xdr_error;
...@@ -3254,7 +3254,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) ...@@ -3254,7 +3254,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
if (decode_space_limit(xdr, &res->maxsize) < 0) if (decode_space_limit(xdr, &res->maxsize) < 0)
return -EIO; return -EIO;
} }
return decode_ace(xdr, NULL, res->server->nfs4_state); return decode_ace(xdr, NULL, res->server->nfs_client);
} }
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
...@@ -3565,7 +3565,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) ...@@ -3565,7 +3565,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
return 0; return 0;
} }
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
{ {
uint32_t *p; uint32_t *p;
uint32_t opnum; uint32_t opnum;
...@@ -3598,7 +3598,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) ...@@ -3598,7 +3598,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
READ_BUF(len); READ_BUF(len);
return -NFSERR_CLID_INUSE; return -NFSERR_CLID_INUSE;
} else } else
return -nfs_stat_to_errno(nfserr); return -nfs4_stat_to_errno(nfserr);
return 0; return 0;
} }
...@@ -4256,7 +4256,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi ...@@ -4256,7 +4256,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi
if (!status) if (!status)
status = decode_fsinfo(&xdr, fsinfo); status = decode_fsinfo(&xdr, fsinfo);
if (!status) if (!status)
status = -nfs_stat_to_errno(hdr.status); status = -nfs4_stat_to_errno(hdr.status);
return status; return status;
} }
...@@ -4335,7 +4335,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) ...@@ -4335,7 +4335,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
* a SETCLIENTID request * a SETCLIENTID request
*/ */
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
struct nfs4_client *clp) struct nfs_client *clp)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr; struct compound_hdr hdr;
...@@ -4346,7 +4346,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, ...@@ -4346,7 +4346,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
if (!status) if (!status)
status = decode_setclientid(&xdr, clp); status = decode_setclientid(&xdr, clp);
if (!status) if (!status)
status = -nfs_stat_to_errno(hdr.status); status = -nfs4_stat_to_errno(hdr.status);
return status; return status;
} }
...@@ -4368,7 +4368,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s ...@@ -4368,7 +4368,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
if (!status) if (!status)
status = decode_fsinfo(&xdr, fsinfo); status = decode_fsinfo(&xdr, fsinfo);
if (!status) if (!status)
status = -nfs_stat_to_errno(hdr.status); status = -nfs4_stat_to_errno(hdr.status);
return status; return status;
} }
...@@ -4521,7 +4521,7 @@ static struct { ...@@ -4521,7 +4521,7 @@ static struct {
* This one is used jointly by NFSv2 and NFSv3. * This one is used jointly by NFSv2 and NFSv3.
*/ */
static int static int
nfs_stat_to_errno(int stat) nfs4_stat_to_errno(int stat)
{ {
int i; int i;
for (i = 0; nfs_errtbl[i].stat != -1; i++) { for (i = 0; nfs_errtbl[i].stat != -1; i++) {
......
...@@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
dprintk("%s: call getattr\n", __FUNCTION__); dprintk("%s: call getattr\n", __FUNCTION__);
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(server->client_sys, &msg, 0); status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
if (status) if (status)
return status; return status;
dprintk("%s: call statfs\n", __FUNCTION__); dprintk("%s: call statfs\n", __FUNCTION__);
msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS];
msg.rpc_resp = &fsinfo; msg.rpc_resp = &fsinfo;
status = rpc_call_sync(server->client_sys, &msg, 0); status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); dprintk("%s: reply statfs: %d\n", __FUNCTION__, status);
if (status) if (status)
return status; return status;
...@@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) ...@@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
} }
static int static int
nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
struct iattr *sattr, struct nfs_fh *fhandle, unsigned int len, struct iattr *sattr)
struct nfs_fattr *fattr)
{ {
struct nfs_fh fhandle;
struct nfs_fattr fattr;
struct nfs_symlinkargs arg = { struct nfs_symlinkargs arg = {
.fromfh = NFS_FH(dir), .fromfh = NFS_FH(dir),
.fromname = name->name, .fromname = dentry->d_name.name,
.fromlen = name->len, .fromlen = dentry->d_name.len,
.topath = path->name, .pages = &page,
.tolen = path->len, .pathlen = len,
.sattr = sattr .sattr = sattr
}; };
struct rpc_message msg = { struct rpc_message msg = {
...@@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, ...@@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS2_MAXPATHLEN) if (len > NFS2_MAXPATHLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
nfs_fattr_init(fattr); dprintk("NFS call symlink %s\n", dentry->d_name.name);
fhandle->size = 0;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir); nfs_mark_for_revalidate(dir);
/*
* V2 SYMLINK requests don't return any attributes. Setting the
* filehandle size to zero indicates to nfs_instantiate that it
* should fill in the data with a LOOKUP call on the wire.
*/
if (status == 0) {
nfs_fattr_init(&fattr);
fhandle.size = 0;
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
dprintk("NFS reply symlink: %d\n", status); dprintk("NFS reply symlink: %d\n", status);
return status; return status;
} }
...@@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
} }
struct nfs_rpc_ops nfs_v2_clientops = { const struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */ .version = 2, /* protocol version */
.dentry_ops = &nfs_dentry_operations, .dentry_ops = &nfs_dentry_operations,
.dir_inode_ops = &nfs_dir_inode_operations, .dir_inode_ops = &nfs_dir_inode_operations,
......
This diff is collapsed.
This diff is collapsed.
...@@ -396,6 +396,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) ...@@ -396,6 +396,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
out: out:
clear_bit(BDI_write_congested, &bdi->state); clear_bit(BDI_write_congested, &bdi->state);
wake_up_all(&nfs_write_congestion); wake_up_all(&nfs_write_congestion);
writeback_congestion_end();
return err; return err;
} }
...@@ -1252,7 +1253,13 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -1252,7 +1253,13 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
dprintk("NFS: %4d nfs_writeback_done (status %d)\n", dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
task->tk_pid, task->tk_status); task->tk_pid, task->tk_status);
/* Call the NFS version-specific code */ /*
* ->write_done will attempt to use post-op attributes to detect
* conflicting writes by other clients. A strict interpretation
* of close-to-open would allow us to continue caching even if
* another writer had changed the file, but some applications
* depend on tighter cache coherency when writing.
*/
status = NFS_PROTO(data->inode)->write_done(task, data); status = NFS_PROTO(data->inode)->write_done(task, data);
if (status != 0) if (status != 0)
return status; return status;
...@@ -1273,7 +1280,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -1273,7 +1280,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
if (time_before(complain, jiffies)) { if (time_before(complain, jiffies)) {
dprintk("NFS: faulty NFS server %s:" dprintk("NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)\n", " (committed = %d) != (stable = %d)\n",
NFS_SERVER(data->inode)->hostname, NFS_SERVER(data->inode)->nfs_client->cl_hostname,
resp->verf->committed, argp->stable); resp->verf->committed, argp->stable);
complain = jiffies + 300 * HZ; complain = jiffies + 300 * HZ;
} }
......
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.
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