mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 07:33:19 +02:00
NFS: Split out the nfs40_reboot_recovery_ops into nfs40client.c
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
This commit is contained in:
parent
e5e45ea615
commit
c96c05fcfe
|
|
@ -27,7 +27,7 @@ CFLAGS_nfs4trace.o += -I$(src)
|
|||
nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
|
||||
delegation.o nfs4idmap.o callback.o callback_xdr.o callback_proc.o \
|
||||
nfs4namespace.o nfs4getroot.o nfs4client.o nfs4session.o \
|
||||
dns_resolve.o nfs4trace.o nfs40proc.o
|
||||
dns_resolve.o nfs4trace.o nfs40proc.o nfs40client.o
|
||||
nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o
|
||||
nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
|
||||
nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o pnfs_nfs.o
|
||||
|
|
|
|||
|
|
@ -739,9 +739,6 @@ extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset);
|
|||
/* nfs4proc.c */
|
||||
extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
|
||||
const struct nfs_client_initdata *);
|
||||
extern int nfs40_walk_client_list(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
extern int nfs41_walk_client_list(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
#define __LINUX_FS_NFS_NFS4_0_H
|
||||
|
||||
|
||||
/* nfs40proc.c */
|
||||
extern const struct rpc_call_ops nfs40_call_sync_ops;
|
||||
extern const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops;
|
||||
|
||||
/* nfs40state.c */
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
|
||||
#endif /* __LINUX_FS_NFS_NFS4_0_H */
|
||||
|
|
|
|||
186
fs/nfs/nfs40client.c
Normal file
186
fs/nfs/nfs40client.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/nfs_fs.h>
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
#include "internal.h"
|
||||
#include "netns.h"
|
||||
#include "nfs40.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CLIENT
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
|
||||
{
|
||||
return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static int nfs40_walk_client_list(struct nfs_client *new,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
|
||||
struct nfs_client *pos, *prev = NULL;
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = new->cl_clientid,
|
||||
.confirm = new->cl_confirm,
|
||||
};
|
||||
int status = -NFS4ERR_STALE_CLIENTID;
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
|
||||
|
||||
if (pos == new)
|
||||
goto found;
|
||||
|
||||
status = nfs4_match_client(pos, new, &prev, nn);
|
||||
if (status < 0)
|
||||
goto out_unlock;
|
||||
if (status != 0)
|
||||
continue;
|
||||
/*
|
||||
* We just sent a new SETCLIENTID, which should have
|
||||
* caused the server to return a new cl_confirm. So if
|
||||
* cl_confirm is the same, then this is a different
|
||||
* server that just returned the same cl_confirm by
|
||||
* coincidence:
|
||||
*/
|
||||
if ((new != pos) && nfs4_same_verifier(&pos->cl_confirm,
|
||||
&new->cl_confirm))
|
||||
continue;
|
||||
/*
|
||||
* But if the cl_confirm's are different, then the only
|
||||
* way that a SETCLIENTID_CONFIRM to pos can succeed is
|
||||
* if new and pos point to the same server:
|
||||
*/
|
||||
found:
|
||||
refcount_inc(&pos->cl_count);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
nfs_put_client(prev);
|
||||
prev = pos;
|
||||
|
||||
status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
|
||||
switch (status) {
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
break;
|
||||
case 0:
|
||||
nfs4_swap_callback_idents(pos, new);
|
||||
pos->cl_confirm = new->cl_confirm;
|
||||
nfs_mark_client_ready(pos, NFS_CS_READY);
|
||||
|
||||
prev = NULL;
|
||||
*result = pos;
|
||||
goto out;
|
||||
case -ERESTARTSYS:
|
||||
case -ETIMEDOUT:
|
||||
/* The callback path may have been inadvertently
|
||||
* changed. Schedule recovery!
|
||||
*/
|
||||
nfs4_schedule_path_down_recovery(pos);
|
||||
goto out;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
/* No match found. The server lost our clientid */
|
||||
out:
|
||||
nfs_put_client(prev);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
|
||||
*
|
||||
* @clp: nfs_client under test
|
||||
* @result: OUT: found nfs_client, or clp
|
||||
* @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".
|
||||
*
|
||||
* Note: The returned client may not yet be marked ready.
|
||||
*/
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = clp->cl_clientid,
|
||||
.confirm = clp->cl_confirm,
|
||||
};
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
unsigned short port;
|
||||
int status;
|
||||
|
||||
port = nn->nfs_callback_tcpport;
|
||||
if (clp->cl_addr.ss_family == AF_INET6)
|
||||
port = nn->nfs_callback_tcpport6;
|
||||
|
||||
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
clp->cl_clientid = clid.clientid;
|
||||
clp->cl_confirm = clid.confirm;
|
||||
|
||||
status = nfs40_walk_client_list(clp, result, cred);
|
||||
if (status == 0) {
|
||||
/* Sustain the lease, even if it's empty. If the clientid4
|
||||
* goes stale it's of no use for trunking discovery. */
|
||||
nfs4_schedule_state_renewal(*result);
|
||||
|
||||
/* If the client state need to recover, do it. */
|
||||
if (clp->cl_state)
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
|
@ -22,3 +22,12 @@ const struct rpc_call_ops nfs40_call_sync_ops = {
|
|||
.rpc_call_prepare = nfs40_call_sync_prepare,
|
||||
.rpc_call_done = nfs40_call_sync_done,
|
||||
};
|
||||
|
||||
const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
|
||||
.state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
|
||||
.recover_open = nfs4_open_reclaim,
|
||||
.recover_lock = nfs4_lock_reclaim,
|
||||
.establish_clid = nfs4_init_clientid,
|
||||
.detect_trunking = nfs40_discover_server_trunking,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -277,6 +277,11 @@ int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
|
|||
/* fs_context.c */
|
||||
extern struct file_system_type nfs4_fs_type;
|
||||
|
||||
/* nfs4client.c */
|
||||
struct nfs_net;
|
||||
int nfs4_match_client(struct nfs_client *pos, struct nfs_client *new,
|
||||
struct nfs_client **prev, struct nfs_net *nn);
|
||||
|
||||
/* nfs4namespace.c */
|
||||
struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
|
||||
const struct qstr *);
|
||||
|
|
@ -345,6 +350,8 @@ extern void nfs4_update_changeattr(struct inode *dir,
|
|||
unsigned long cache_validity);
|
||||
extern int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||
struct page **pages);
|
||||
extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
|
||||
extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request);
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
|
||||
|
|
|
|||
|
|
@ -490,37 +490,6 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
|
|||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
|
||||
const struct nfs_client *clp2)
|
||||
{
|
||||
|
|
@ -529,13 +498,8 @@ static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
|
|||
return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0;
|
||||
}
|
||||
|
||||
static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
|
||||
{
|
||||
return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
|
||||
}
|
||||
|
||||
static int nfs4_match_client(struct nfs_client *pos, struct nfs_client *new,
|
||||
struct nfs_client **prev, struct nfs_net *nn)
|
||||
int nfs4_match_client(struct nfs_client *pos, struct nfs_client *new,
|
||||
struct nfs_client **prev, struct nfs_net *nn)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
@ -578,98 +542,6 @@ static int nfs4_match_client(struct nfs_client *pos, struct nfs_client *new,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
|
||||
struct nfs_client *pos, *prev = NULL;
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = new->cl_clientid,
|
||||
.confirm = new->cl_confirm,
|
||||
};
|
||||
int status = -NFS4ERR_STALE_CLIENTID;
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
|
||||
|
||||
if (pos == new)
|
||||
goto found;
|
||||
|
||||
status = nfs4_match_client(pos, new, &prev, nn);
|
||||
if (status < 0)
|
||||
goto out_unlock;
|
||||
if (status != 0)
|
||||
continue;
|
||||
/*
|
||||
* We just sent a new SETCLIENTID, which should have
|
||||
* caused the server to return a new cl_confirm. So if
|
||||
* cl_confirm is the same, then this is a different
|
||||
* server that just returned the same cl_confirm by
|
||||
* coincidence:
|
||||
*/
|
||||
if ((new != pos) && nfs4_same_verifier(&pos->cl_confirm,
|
||||
&new->cl_confirm))
|
||||
continue;
|
||||
/*
|
||||
* But if the cl_confirm's are different, then the only
|
||||
* way that a SETCLIENTID_CONFIRM to pos can succeed is
|
||||
* if new and pos point to the same server:
|
||||
*/
|
||||
found:
|
||||
refcount_inc(&pos->cl_count);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
nfs_put_client(prev);
|
||||
prev = pos;
|
||||
|
||||
status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
|
||||
switch (status) {
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
break;
|
||||
case 0:
|
||||
nfs4_swap_callback_idents(pos, new);
|
||||
pos->cl_confirm = new->cl_confirm;
|
||||
nfs_mark_client_ready(pos, NFS_CS_READY);
|
||||
|
||||
prev = NULL;
|
||||
*result = pos;
|
||||
goto out;
|
||||
case -ERESTARTSYS:
|
||||
case -ETIMEDOUT:
|
||||
/* The callback path may have been inadvertently
|
||||
* changed. Schedule recovery!
|
||||
*/
|
||||
nfs4_schedule_path_down_recovery(pos);
|
||||
goto out;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
/* No match found. The server lost our clientid */
|
||||
out:
|
||||
nfs_put_client(prev);
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4_1
|
||||
/*
|
||||
* Returns true if the server major ids match
|
||||
|
|
|
|||
|
|
@ -2331,7 +2331,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
||||
int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
||||
{
|
||||
struct nfs_open_context *ctx;
|
||||
int ret;
|
||||
|
|
@ -7649,7 +7649,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
|
||||
int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||
struct nfs4_exception exception = {
|
||||
|
|
@ -10804,15 +10804,6 @@ static bool nfs4_match_stateid(const nfs4_stateid *s1,
|
|||
}
|
||||
|
||||
|
||||
static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
|
||||
.state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
|
||||
.recover_open = nfs4_open_reclaim,
|
||||
.recover_lock = nfs4_lock_reclaim,
|
||||
.establish_clid = nfs4_init_clientid,
|
||||
.detect_trunking = nfs40_discover_server_trunking,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
|
||||
|
|
|
|||
|
|
@ -142,55 +142,6 @@ int nfs4_init_clientid(struct nfs_client *clp, const struct cred *cred)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
|
||||
*
|
||||
* @clp: nfs_client under test
|
||||
* @result: OUT: found nfs_client, or clp
|
||||
* @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".
|
||||
*
|
||||
* Note: The returned client may not yet be marked ready.
|
||||
*/
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = clp->cl_clientid,
|
||||
.confirm = clp->cl_confirm,
|
||||
};
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
unsigned short port;
|
||||
int status;
|
||||
|
||||
port = nn->nfs_callback_tcpport;
|
||||
if (clp->cl_addr.ss_family == AF_INET6)
|
||||
port = nn->nfs_callback_tcpport6;
|
||||
|
||||
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
clp->cl_clientid = clid.clientid;
|
||||
clp->cl_confirm = clid.confirm;
|
||||
|
||||
status = nfs40_walk_client_list(clp, result, cred);
|
||||
if (status == 0) {
|
||||
/* Sustain the lease, even if it's empty. If the clientid4
|
||||
* goes stale it's of no use for trunking discovery. */
|
||||
nfs4_schedule_state_renewal(*result);
|
||||
|
||||
/* If the client state need to recover, do it. */
|
||||
if (clp->cl_state)
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct cred *nfs4_get_machine_cred(struct nfs_client *clp)
|
||||
{
|
||||
return get_cred(rpc_machine_cred());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user