Commit 24c8dbbb authored by David Howells's avatar David Howells Committed by Trond Myklebust

NFS: Generalise the nfs_client structure

Generalise the nfs_client structure by:

 (1) Moving nfs_client to a more general place (nfs_fs_sb.h).

 (2) Renaming its maintenance routines to be non-NFS4 specific.

 (3) Move those maintenance routines to a new non-NFS4 specific file (client.c)
     and move the declarations to internal.h.

 (4) Make nfs_find/get_client() take a full sockaddr_in to include the port
     number (will be required for NFS2/3).

 (5) Make nfs_find/get_client() take the NFS protocol version (again will be
     required to differentiate NFS2, 3 & 4 client records).

Also:

 (6) Make nfs_client construction proceed akin to inodes, marking them as under
     construction and providing a function to indicate completion.

 (7) Make nfs_get_client() wait interruptibly if it finds a client that it can
     share, but that client is currently being constructed.

 (8) Make nfs4_create_client() use (6) and (7) instead of locking cl_sem.
Signed-Off-By: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent e9326dca
......@@ -4,9 +4,9 @@
obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o \
namespace.o
nfs-y := client.o dir.o file.o inode.o super.o nfs2xdr.o \
pagelist.o proc.o read.o symlink.o unlink.o \
write.o namespace.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
......
......@@ -19,6 +19,7 @@
#include "nfs4_fs.h"
#include "callback.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK
......@@ -166,15 +167,15 @@ void nfs_callback_down(void)
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 nfs_client *clp;
/* Don't talk to strangers */
clp = nfs4_find_client(addr);
clp = nfs_find_client(addr, 4);
if (clp == NULL)
return SVC_DROP;
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
nfs4_put_client(clp);
dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr));
nfs_put_client(clp);
switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL)
......
......@@ -10,6 +10,7 @@
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK
......@@ -22,7 +23,7 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
res->bitmap[0] = res->bitmap[1] = 0;
res->status = htonl(NFS4ERR_BADHANDLE);
clp = nfs4_find_client(&args->addr->sin_addr);
clp = nfs_find_client(args->addr, 4);
if (clp == NULL)
goto out;
inode = nfs_delegation_find_inode(clp, &args->fh);
......@@ -48,7 +49,7 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
up_read(&nfsi->rwsem);
iput(inode);
out_putclient:
nfs4_put_client(clp);
nfs_put_client(clp);
out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
return res->status;
......@@ -61,7 +62,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
unsigned res;
res = htonl(NFS4ERR_BADHANDLE);
clp = nfs4_find_client(&args->addr->sin_addr);
clp = nfs_find_client(args->addr, 4);
if (clp == NULL)
goto out;
inode = nfs_delegation_find_inode(clp, &args->fh);
......@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
}
iput(inode);
out_putclient:
nfs4_put_client(clp);
nfs_put_client(clp);
out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
return res;
......
/* client.c: NFS client sharing and management code
*
* 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/sunrpc/metrics.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/inet.h>
#include <linux/nfs_xdr.h>
#include <asm/system.h>
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_CLIENT
static DEFINE_SPINLOCK(nfs_client_lock);
static LIST_HEAD(nfs_client_list);
static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
/*
* Allocate a shared client record
*
* Since these are allocated/deallocated very rarely, we don't
* bother putting them in a slab cache...
*/
static struct nfs_client *nfs_alloc_client(const char *hostname,
const struct sockaddr_in *addr,
int nfsversion)
{
struct nfs_client *clp;
int error;
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
goto error_0;
error = rpciod_up();
if (error < 0) {
dprintk("%s: couldn't start rpciod! Error = %d\n",
__FUNCTION__, error);
__set_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
goto error_1;
}
if (nfsversion == 4) {
if (nfs_callback_up() < 0)
goto error_2;
__set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
}
atomic_set(&clp->cl_count, 1);
clp->cl_cons_state = NFS_CS_INITING;
clp->cl_nfsversion = nfsversion;
memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
if (hostname) {
clp->cl_hostname = kstrdup(hostname, GFP_KERNEL);
if (!clp->cl_hostname)
goto error_3;
}
INIT_LIST_HEAD(&clp->cl_superblocks);
clp->cl_rpcclient = ERR_PTR(-EINVAL);
#ifdef CONFIG_NFS_V4
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);
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
#endif
return clp;
error_3:
nfs_callback_down();
__clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
error_2:
rpciod_down();
__clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
error_1:
kfree(clp);
error_0:
return NULL;
}
/*
* Destroy a shared client record
*/
static void nfs_free_client(struct nfs_client *clp)
{
dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
#ifdef CONFIG_NFS_V4
if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) {
while (!list_empty(&clp->cl_unused)) {
struct nfs4_state_owner *sp;
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);
}
#endif
/* -EIO all pending I/O */
if (!IS_ERR(clp->cl_rpcclient))
rpc_shutdown_client(clp->cl_rpcclient);
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
nfs_callback_down();
if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state))
rpciod_down();
kfree(clp->cl_hostname);
kfree(clp);
dprintk("<-- nfs_free_client()\n");
}
/*
* Release a reference to a shared client record
*/
void nfs_put_client(struct nfs_client *clp)
{
dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
list_del(&clp->cl_share_link);
spin_unlock(&nfs_client_lock);
BUG_ON(!list_empty(&clp->cl_superblocks));
nfs_free_client(clp);
}
}
/*
* Find a client by address
* - caller must hold nfs_client_lock
*/
static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
{
struct nfs_client *clp;
list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
/* Different NFS versions cannot share the same nfs_client */
if (clp->cl_nfsversion != nfsversion)
continue;
if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr,
sizeof(clp->cl_addr.sin_addr)) != 0)
continue;
if (clp->cl_addr.sin_port == addr->sin_port)
goto found;
}
return NULL;
found:
atomic_inc(&clp->cl_count);
return clp;
}
/*
* Find a client by IP address and protocol version
* - returns NULL if no such client
*/
struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
{
struct nfs_client *clp;
spin_lock(&nfs_client_lock);
clp = __nfs_find_client(addr, nfsversion);
spin_unlock(&nfs_client_lock);
BUG_ON(clp->cl_cons_state == 0);
return clp;
}
/*
* Look up a client by IP address and protocol version
* - creates a new record if one doesn't yet exist
*/
struct nfs_client *nfs_get_client(const char *hostname,
const struct sockaddr_in *addr,
int nfsversion)
{
struct nfs_client *clp, *new = NULL;
int error;
dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n",
hostname ?: "", NIPQUAD(addr->sin_addr),
addr->sin_port, nfsversion);
/* see if the client already exists */
do {
spin_lock(&nfs_client_lock);
clp = __nfs_find_client(addr, nfsversion);
if (clp)
goto found_client;
if (new)
goto install_client;
spin_unlock(&nfs_client_lock);
new = nfs_alloc_client(hostname, addr, nfsversion);
} while (new);
return ERR_PTR(-ENOMEM);
/* install a new client and return with it unready */
install_client:
clp = new;
list_add(&clp->cl_share_link, &nfs_client_list);
spin_unlock(&nfs_client_lock);
dprintk("--> nfs_get_client() = %p [new]\n", clp);
return clp;
/* found an existing client
* - make sure it's ready before returning
*/
found_client:
spin_unlock(&nfs_client_lock);
if (new)
nfs_free_client(new);
if (clp->cl_cons_state == NFS_CS_INITING) {
DECLARE_WAITQUEUE(myself, current);
add_wait_queue(&nfs_client_active_wq, &myself);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current) ||
clp->cl_cons_state > NFS_CS_READY)
break;
schedule();
}
remove_wait_queue(&nfs_client_active_wq, &myself);
if (signal_pending(current)) {
nfs_put_client(clp);
return ERR_PTR(-ERESTARTSYS);
}
}
if (clp->cl_cons_state < NFS_CS_READY) {
error = clp->cl_cons_state;
nfs_put_client(clp);
return ERR_PTR(error);
}
dprintk("--> nfs_get_client() = %p [share]\n", clp);
return clp;
}
/*
* Mark a server as ready or failed
*/
void nfs_mark_client_ready(struct nfs_client *clp, int state)
{
clp->cl_cons_state = state;
wake_up_all(&nfs_client_active_wq);
}
......@@ -18,6 +18,7 @@
#include "nfs4_fs.h"
#include "delegation.h"
#include "internal.h"
static struct nfs_delegation *nfs_alloc_delegation(void)
{
......@@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
sizeof(delegation->stateid)) != 0 ||
delegation->type != nfsi->delegation->type) {
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;
}
}
......@@ -254,7 +255,7 @@ int nfs_do_expire_all_delegations(void *ptr)
}
out:
spin_unlock(&clp->cl_lock);
nfs4_put_client(clp);
nfs_put_client(clp);
module_put_and_exit(0);
}
......@@ -266,10 +267,10 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
atomic_inc(&clp->cl_count);
task = kthread_run(nfs_do_expire_all_delegations, clp,
"%u.%u.%u.%u-delegreturn",
NIPQUAD(clp->cl_addr));
NIPQUAD(clp->cl_addr.sin_addr));
if (!IS_ERR(task))
return;
nfs4_put_client(clp);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
......
......@@ -15,6 +15,12 @@ struct nfs_clone_mount {
rpc_authflavor_t authflavor;
};
/* client.c */
extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
extern struct nfs_client *nfs_get_client(const char *, const struct sockaddr_in *, int);
extern void nfs_mark_client_ready(struct nfs_client *, int);
/* nfs4namespace.c */
#ifdef CONFIG_NFS_V4
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
......
......@@ -42,55 +42,6 @@ enum nfs4_client_state {
NFS4CLNT_LEASE_EXPIRED,
};
/*
* The nfs_client identifies our client state to the server.
*/
struct nfs_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
* order that they appear on the list.
......@@ -239,9 +190,6 @@ extern void nfs4_renew_state(void *);
/* nfs4state.c */
extern void init_nfsv4_state(struct nfs_server *);
extern void destroy_nfsv4_state(struct nfs_server *);
extern struct nfs_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs_client *clp);
extern struct nfs_client *nfs4_find_client(struct in_addr *);
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
......
......@@ -2968,7 +2968,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po
for(;;) {
setclientid.sc_name_len = scnprintf(setclientid.sc_name,
sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u",
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr),
clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr),
cred->cr_ops->cr_name,
clp->cl_id_uniquifier);
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
......
......@@ -50,12 +50,12 @@
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "internal.h"
#define OPENOWNER_POOL_SIZE 8
const nfs4_stateid zero_stateid;
static DEFINE_SPINLOCK(state_spinlock);
static LIST_HEAD(nfs4_clientid_list);
void
......@@ -71,127 +71,11 @@ destroy_nfsv4_state(struct nfs_server *server)
kfree(server->mnt_path);
server->mnt_path = NULL;
if (server->nfs_client) {
nfs4_put_client(server->nfs_client);
nfs_put_client(server->nfs_client);
server->nfs_client = 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 nfs_client *
nfs4_alloc_client(struct in_addr *addr)
{
struct nfs_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 nfs_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 nfs_client *__nfs4_find_client(struct in_addr *addr)
{
struct nfs_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 nfs_client *nfs4_find_client(struct in_addr *addr)
{
struct nfs_client *clp;
spin_lock(&state_spinlock);
clp = __nfs4_find_client(addr);
spin_unlock(&state_spinlock);
return clp;
}
struct nfs_client *
nfs4_get_client(struct in_addr *addr)
{
struct nfs_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 nfs_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 nfs_client *clp, struct rpc_cred *cred)
{
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
......@@ -771,11 +655,11 @@ static void nfs4_recover_state(struct nfs_client *clp)
__module_get(THIS_MODULE);
atomic_inc(&clp->cl_count);
task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
NIPQUAD(clp->cl_addr));
NIPQUAD(clp->cl_addr.sin_addr));
if (!IS_ERR(task))
return;
nfs4_clear_recover_bit(clp);
nfs4_put_client(clp);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
......@@ -970,12 +854,12 @@ static int reclaimer(void *ptr)
if (status == -NFS4ERR_CB_PATH_DOWN)
nfs_handle_cb_pathdown(clp);
nfs4_clear_recover_bit(clp);
nfs4_put_client(clp);
nfs_put_client(clp);
module_put_and_exit(0);
return 0;
out_error:
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);
goto out;
}
......
......@@ -1104,47 +1104,46 @@ static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
struct rpc_clnt *clnt = NULL;
int err = -EIO;
clp = nfs4_get_client(&server->addr.sin_addr);
clp = nfs_get_client(server->hostname, &server->addr, 4);
if (!clp) {
dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
return ERR_PTR(err);
}
/* Now create transport and client */
down_write(&clp->cl_sem);
if (IS_ERR(clp->cl_rpcclient)) {
if (clp->cl_cons_state == NFS_CS_INITING) {
xprt = xprt_create_proto(proto, &server->addr, timeparms);
if (IS_ERR(xprt)) {
up_write(&clp->cl_sem);
err = PTR_ERR(xprt);
dprintk("%s: cannot create RPC transport. Error = %d\n",
__FUNCTION__, err);
goto out_fail;
goto client_init_error;
}
/* Bind to a reserved port! */
xprt->resvport = 1;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
server->rpc_ops->version, flavor);
if (IS_ERR(clnt)) {
up_write(&clp->cl_sem);
err = PTR_ERR(clnt);
dprintk("%s: cannot create RPC client. Error = %d\n",
__FUNCTION__, err);
goto out_fail;
goto client_init_error;
}
clnt->cl_intr = 1;
clnt->cl_softrtry = 1;
clp->cl_rpcclient = clnt;
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
if (nfs_idmap_new(clp) < 0)
goto out_fail;
err = nfs_idmap_new(clp);
if (err < 0) {
dprintk("%s: failed to create idmapper.\n",
__FUNCTION__);
goto client_init_error;
}
__set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
nfs_mark_client_ready(clp, 0);
}
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
clnt = rpc_clone_client(clp->cl_rpcclient);
if (!IS_ERR(clnt))
server->nfs_client = clp;
up_write(&clp->cl_sem);
clp = NULL;
if (IS_ERR(clnt)) {
dprintk("%s: cannot create RPC client. Error = %d\n",
......@@ -1152,11 +1151,6 @@ static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
return clnt;
}
if (server->nfs_client->cl_idmap == NULL) {
dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
return ERR_PTR(-ENOMEM);
}
if (clnt->cl_auth->au_flavor != flavor) {
struct rpc_auth *auth;
......@@ -1166,11 +1160,16 @@ static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
return (struct rpc_clnt *)auth;
}
}
server->nfs_client = clp;
down_write(&clp->cl_sem);
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
up_write(&clp->cl_sem);
return clnt;
out_fail:
if (clp)
nfs4_put_client(clp);
client_init_error:
nfs_mark_client_ready(clp, err);
nfs_put_client(clp);
return ERR_PTR(err);
}
......@@ -1329,14 +1328,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
goto out_free;
}
/* Fire up rpciod if not yet running */
error = rpciod_up();
if (error < 0) {
dprintk("%s: couldn't start rpciod! Error = %d\n",
__FUNCTION__, error);
goto out_free;
}
s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
......@@ -1383,8 +1374,6 @@ static void nfs4_kill_super(struct super_block *sb)
destroy_nfsv4_state(server);
rpciod_down();
nfs_free_iostats(server->io_stats);
kfree(server->hostname);
kfree(server);
......
......@@ -586,6 +586,7 @@ extern void * nfs_root_data(void);
#define NFSDBG_FILE 0x0040
#define NFSDBG_ROOT 0x0080
#define NFSDBG_CALLBACK 0x0100
#define NFSDBG_CLIENT 0x0200
#define NFSDBG_ALL 0xFFFF
#ifdef __KERNEL__
......
......@@ -6,6 +6,66 @@
struct nfs_iostats;
/*
* The nfs_client identifies our client state to the server.
*/
struct nfs_client {
atomic_t cl_count;
int cl_cons_state; /* current construction state (-ve: init error) */
#define NFS_CS_READY 0 /* ready to be used */
#define NFS_CS_INITING 1 /* busy initialising */
int cl_nfsversion; /* NFS protocol version */
unsigned long cl_res_state; /* NFS resources state */
#define NFS_CS_RPCIOD 0 /* - rpciod started */
#define NFS_CS_CALLBACK 1 /* - callback started */
#define NFS_CS_IDMAP 2 /* - idmap started */
struct sockaddr_in cl_addr; /* server identifier */
char * cl_hostname; /* hostname of server */
struct list_head cl_share_link; /* link in global client list */
struct list_head cl_superblocks; /* List of nfs_server structs */
struct rpc_clnt * cl_rpcclient;
#ifdef CONFIG_NFS_V4
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;
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;
#endif
};
/*
* NFS client parameters stored in the superblock.
*/
......
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