Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 333179
b: refs/heads/master
c: 05f4c35
h: refs/heads/master
i:
  333177: eddfc54
  333175: 81ac6f4
v: v3
  • Loading branch information
Chuck Lever authored and Trond Myklebust committed Oct 1, 2012
1 parent ebccb96 commit 3fcd09a
Show file tree
Hide file tree
Showing 8 changed files with 456 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e984a55a7418f777407c7edbb2bdf5eb9559b5e2
refs/heads/master: 05f4c350ee02e9461c6ae3a880ea326a06835e37
3 changes: 2 additions & 1 deletion trunk/fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
return nfs_found_client(cl_init, clp);
}
if (new) {
list_add(&new->cl_share_link, &nn->nfs_client_list);
list_add_tail(&new->cl_share_link,
&nn->nfs_client_list);
spin_unlock(&nn->nfs_client_lock);
new->cl_flags = cl_init->init_flags;
return rpc_ops->init_client(new, timeparms, ip_addr,
Expand Down
6 changes: 6 additions & 0 deletions trunk/fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
int cache_reply);
extern int nfs40_walk_client_list(struct nfs_client *clp,
struct nfs_client **result,
struct rpc_cred *cred);
extern int nfs41_walk_client_list(struct nfs_client *clp,
struct nfs_client **result,
struct rpc_cred *cred);

/*
* Determine the device name as a string
Expand Down
8 changes: 8 additions & 0 deletions trunk/fs/nfs/nfs4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ struct nfs4_state_recovery_ops {
int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
int (*reclaim_complete)(struct nfs_client *);
int (*detect_trunking)(struct nfs_client *, struct nfs_client **,
struct rpc_cred *);
};

struct nfs4_state_maintenance_ops {
Expand Down Expand Up @@ -320,9 +322,15 @@ extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
int nfs4_discover_server_trunking(struct nfs_client *clp,
struct nfs_client **);
int nfs40_discover_server_trunking(struct nfs_client *clp,
struct nfs_client **, struct rpc_cred *);
#if defined(CONFIG_NFS_V4_1)
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
int nfs41_discover_server_trunking(struct nfs_client *clp,
struct nfs_client **, struct rpc_cred *);
extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
#else
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
Expand Down
253 changes: 253 additions & 0 deletions trunk/fs/nfs/nfs4client.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
rpc_authflavor_t authflavour)
{
char buf[INET6_ADDRSTRLEN + 1];
struct nfs_client *old;
int error;

if (clp->cl_cons_state == NFS_CS_READY) {
Expand Down Expand Up @@ -230,6 +231,17 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,

if (!nfs4_has_session(clp))
nfs_mark_client_ready(clp, NFS_CS_READY);

error = nfs4_discover_server_trunking(clp, &old);
if (error < 0)
goto error;
if (clp != old) {
clp->cl_preserve_clid = true;
nfs_put_client(clp);
clp = old;
atomic_inc(&clp->cl_count);
}

return clp;

error:
Expand All @@ -239,6 +251,247 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
return ERR_PTR(error);
}

/*
* Returns true if the client IDs match
*/
static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
{
if (a->cl_clientid != b->cl_clientid) {
dprintk("NFS: --> %s client ID %llx does not match %llx\n",
__func__, a->cl_clientid, b->cl_clientid);
return false;
}
dprintk("NFS: --> %s client ID %llx matches %llx\n",
__func__, a->cl_clientid, b->cl_clientid);
return true;
}

/*
* SETCLIENTID just did a callback update with the callback ident in
* "drop," but server trunking discovery claims "drop" and "keep" are
* actually the same server. Swap the callback IDs so that "keep"
* will continue to use the callback ident the server now knows about,
* and so that "keep"'s original callback ident is destroyed when
* "drop" is freed.
*/
static void nfs4_swap_callback_idents(struct nfs_client *keep,
struct nfs_client *drop)
{
struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
unsigned int save = keep->cl_cb_ident;

if (keep->cl_cb_ident == drop->cl_cb_ident)
return;

dprintk("%s: keeping callback ident %u and dropping ident %u\n",
__func__, keep->cl_cb_ident, drop->cl_cb_ident);

spin_lock(&nn->nfs_client_lock);

idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
keep->cl_cb_ident = drop->cl_cb_ident;

idr_replace(&nn->cb_ident_idr, drop, save);
drop->cl_cb_ident = save;

spin_unlock(&nn->nfs_client_lock);
}

/**
* nfs40_walk_client_list - Find server that recognizes a client ID
*
* @new: nfs_client with client ID to test
* @result: OUT: found nfs_client, or new
* @cred: credential to use for trunking test
*
* Returns zero, a negative errno, or a negative NFS4ERR status.
* If zero is returned, an nfs_client pointer is planted in "result."
*
* NB: nfs40_walk_client_list() relies on the new nfs_client being
* the last nfs_client on the list.
*/
int nfs40_walk_client_list(struct nfs_client *new,
struct nfs_client **result,
struct rpc_cred *cred)
{
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
struct nfs_client *pos, *n, *prev = NULL;
struct nfs4_setclientid_res clid = {
.clientid = new->cl_clientid,
.confirm = new->cl_confirm,
};
int status;

spin_lock(&nn->nfs_client_lock);
list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
/* If "pos" isn't marked ready, we can't trust the
* remaining fields in "pos" */
if (pos->cl_cons_state < NFS_CS_READY)
continue;

if (pos->rpc_ops != new->rpc_ops)
continue;

if (pos->cl_proto != new->cl_proto)
continue;

if (pos->cl_minorversion != new->cl_minorversion)
continue;

if (pos->cl_clientid != new->cl_clientid)
continue;

atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);

if (prev)
nfs_put_client(prev);

status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
if (status == 0) {
nfs4_swap_callback_idents(pos, new);

nfs_put_client(pos);
*result = pos;
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
__func__, pos, atomic_read(&pos->cl_count));
return 0;
}
if (status != -NFS4ERR_STALE_CLIENTID) {
nfs_put_client(pos);
dprintk("NFS: <-- %s status = %d, no result\n",
__func__, status);
return status;
}

spin_lock(&nn->nfs_client_lock);
prev = pos;
}

/*
* No matching nfs_client found. This should be impossible,
* because the new nfs_client has already been added to
* nfs_client_list by nfs_get_client().
*
* Don't BUG(), since the caller is holding a mutex.
*/
if (prev)
nfs_put_client(prev);
spin_unlock(&nn->nfs_client_lock);
pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
return -NFS4ERR_STALE_CLIENTID;
}

#ifdef CONFIG_NFS_V4_1
/*
* Returns true if the server owners match
*/
static bool
nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
{
struct nfs41_server_owner *o1 = a->cl_serverowner;
struct nfs41_server_owner *o2 = b->cl_serverowner;

if (o1->minor_id != o2->minor_id) {
dprintk("NFS: --> %s server owner minor IDs do not match\n",
__func__);
return false;
}

if (o1->major_id_sz != o2->major_id_sz)
goto out_major_mismatch;
if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
goto out_major_mismatch;

dprintk("NFS: --> %s server owners match\n", __func__);
return true;

out_major_mismatch:
dprintk("NFS: --> %s server owner major IDs do not match\n",
__func__);
return false;
}

/**
* nfs41_walk_client_list - Find nfs_client that matches a client/server owner
*
* @new: nfs_client with client ID to test
* @result: OUT: found nfs_client, or new
* @cred: credential to use for trunking test
*
* Returns zero, a negative errno, or a negative NFS4ERR status.
* If zero is returned, an nfs_client pointer is planted in "result."
*
* NB: nfs41_walk_client_list() relies on the new nfs_client being
* the last nfs_client on the list.
*/
int nfs41_walk_client_list(struct nfs_client *new,
struct nfs_client **result,
struct rpc_cred *cred)
{
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
struct nfs_client *pos, *n, *prev = NULL;
int error;

spin_lock(&nn->nfs_client_lock);
list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
/* If "pos" isn't marked ready, we can't trust the
* remaining fields in "pos", especially the client
* ID and serverowner fields. Wait for CREATE_SESSION
* to finish. */
if (pos->cl_cons_state < NFS_CS_READY) {
atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);

if (prev)
nfs_put_client(prev);
prev = pos;

error = nfs_wait_client_init_complete(pos);
if (error < 0) {
nfs_put_client(pos);
continue;
}

spin_lock(&nn->nfs_client_lock);
}

if (pos->rpc_ops != new->rpc_ops)
continue;

if (pos->cl_proto != new->cl_proto)
continue;

if (pos->cl_minorversion != new->cl_minorversion)
continue;

if (!nfs4_match_clientids(pos, new))
continue;

if (!nfs4_match_serverowners(pos, new))
continue;

spin_unlock(&nn->nfs_client_lock);
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
__func__, pos, atomic_read(&pos->cl_count));

*result = pos;
return 0;
}

/*
* No matching nfs_client found. This should be impossible,
* because the new nfs_client has already been added to
* nfs_client_list by nfs_get_client().
*
* Don't BUG(), since the caller is holding a mutex.
*/
spin_unlock(&nn->nfs_client_lock);
pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
return -NFS4ERR_STALE_CLIENTID;
}
#endif /* CONFIG_NFS_V4_1 */

static void nfs4_destroy_server(struct nfs_server *server)
{
nfs_server_return_all_delegations(server);
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5458,6 +5458,8 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
goto out;
if (clp->cl_exchange_flags == 0)
goto out;
if (clp->cl_preserve_clid)
goto out;
cred = nfs4_get_exchange_id_cred(clp);
ret = nfs4_proc_destroy_clientid(clp, cred);
if (cred)
Expand Down Expand Up @@ -6871,6 +6873,7 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
.recover_lock = nfs4_lock_reclaim,
.establish_clid = nfs4_init_clientid,
.get_clid_cred = nfs4_get_setclientid_cred,
.detect_trunking = nfs40_discover_server_trunking,
};

#if defined(CONFIG_NFS_V4_1)
Expand All @@ -6882,6 +6885,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
.establish_clid = nfs41_init_clientid,
.get_clid_cred = nfs4_get_exchange_id_cred,
.reclaim_complete = nfs41_proc_reclaim_complete,
.detect_trunking = nfs41_discover_server_trunking,
};
#endif /* CONFIG_NFS_V4_1 */

Expand Down
Loading

0 comments on commit 3fcd09a

Please sign in to comment.