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: David Howells <dhowells@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
committed by
Trond Myklebust
parent
e9326dcab4
commit
24c8dbbb5f
@ -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 @@ out:
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user