Commit a33e4b03 authored by Weston Andros Adamson's avatar Weston Andros Adamson Committed by Anna Schumaker

pNFS: return status from nfs4_pnfs_ds_connect

The nfs4_pnfs_ds_connect path can call rpc_create which can fail or it
can wait on another context to reach the same failure.

This checks that the rpc_create succeeded and returns the error to the
caller.

When an error is returned, both the files and flexfiles layouts will return
NULL from _prepare_ds(). The flexfiles layout will also return the layout
with the error NFS4ERR_NXIO.
Signed-off-by: default avatarWeston Andros Adamson <dros@primarydata.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 03385332
...@@ -325,10 +325,33 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat ...@@ -325,10 +325,33 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
return NULL; return NULL;
} }
static bool nfs_client_init_is_complete(const struct nfs_client *clp) /*
* Return true if @clp is done initializing, false if still working on it.
*
* Use nfs_client_init_status to check if it was successful.
*/
bool nfs_client_init_is_complete(const struct nfs_client *clp)
{ {
return clp->cl_cons_state <= NFS_CS_READY; return clp->cl_cons_state <= NFS_CS_READY;
} }
EXPORT_SYMBOL_GPL(nfs_client_init_is_complete);
/*
* Return 0 if @clp was successfully initialized, -errno otherwise.
*
* This must be called *after* nfs_client_init_is_complete() returns true,
* otherwise it will pop WARN_ON_ONCE and return -EINVAL
*/
int nfs_client_init_status(const struct nfs_client *clp)
{
/* called without checking nfs_client_init_is_complete */
if (clp->cl_cons_state > NFS_CS_READY) {
WARN_ON_ONCE(1);
return -EINVAL;
}
return clp->cl_cons_state;
}
EXPORT_SYMBOL_GPL(nfs_client_init_status);
int nfs_wait_client_init_complete(const struct nfs_client *clp) int nfs_wait_client_init_complete(const struct nfs_client *clp)
{ {
......
...@@ -266,6 +266,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) ...@@ -266,6 +266,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
struct nfs4_pnfs_ds *ret = ds; struct nfs4_pnfs_ds *ret = ds;
struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
int status;
if (ds == NULL) { if (ds == NULL) {
printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
...@@ -277,9 +278,13 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) ...@@ -277,9 +278,13 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
if (ds->ds_clp) if (ds->ds_clp)
goto out_test_devid; goto out_test_devid;
nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
dataserver_retrans, 4, dataserver_retrans, 4,
s->nfs_client->cl_minorversion); s->nfs_client->cl_minorversion);
if (status) {
ret = NULL;
goto out;
}
out_test_devid: out_test_devid:
if (ret->ds_clp == NULL || if (ret->ds_clp == NULL ||
......
...@@ -384,6 +384,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -384,6 +384,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
struct inode *ino = lseg->pls_layout->plh_inode; struct inode *ino = lseg->pls_layout->plh_inode;
struct nfs_server *s = NFS_SERVER(ino); struct nfs_server *s = NFS_SERVER(ino);
unsigned int max_payload; unsigned int max_payload;
int status;
if (!ff_layout_mirror_valid(lseg, mirror, true)) { if (!ff_layout_mirror_valid(lseg, mirror, true)) {
pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", pr_err_ratelimited("NFS: %s: No data server for offset index %d\n",
...@@ -404,7 +405,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -404,7 +405,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
/* FIXME: For now we assume the server sent only one version of NFS /* FIXME: For now we assume the server sent only one version of NFS
* to use for the DS. * to use for the DS.
*/ */
nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
dataserver_retrans, dataserver_retrans,
mirror->mirror_ds->ds_versions[0].version, mirror->mirror_ds->ds_versions[0].version,
mirror->mirror_ds->ds_versions[0].minor_version); mirror->mirror_ds->ds_versions[0].minor_version);
......
...@@ -186,6 +186,8 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *, ...@@ -186,6 +186,8 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *, struct nfs_fh *,
struct nfs_fattr *, struct nfs_fattr *,
rpc_authflavor_t); rpc_authflavor_t);
extern bool nfs_client_init_is_complete(const struct nfs_client *clp);
extern int nfs_client_init_status(const struct nfs_client *clp);
extern int nfs_wait_client_init_complete(const struct nfs_client *clp); extern int nfs_wait_client_init_complete(const struct nfs_client *clp);
extern void nfs_mark_client_ready(struct nfs_client *clp, int state); extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv, extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
......
...@@ -367,7 +367,7 @@ void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); ...@@ -367,7 +367,7 @@ void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds);
struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs,
gfp_t gfp_flags); gfp_t gfp_flags);
void nfs4_pnfs_v3_ds_connect_unload(void); void nfs4_pnfs_v3_ds_connect_unload(void);
void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo, struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version); unsigned int retrans, u32 version, u32 minor_version);
struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net, struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
......
...@@ -745,9 +745,9 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, ...@@ -745,9 +745,9 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
/* /*
* Create an rpc connection to the nfs4_pnfs_ds data server. * Create an rpc connection to the nfs4_pnfs_ds data server.
* Currently only supports IPv4 and IPv6 addresses. * Currently only supports IPv4 and IPv6 addresses.
* If connection fails, make devid unavailable. * If connection fails, make devid unavailable and return a -errno.
*/ */
void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo, struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version) unsigned int retrans, u32 version, u32 minor_version)
{ {
...@@ -772,6 +772,17 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, ...@@ -772,6 +772,17 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
} else { } else {
nfs4_wait_ds_connect(ds); nfs4_wait_ds_connect(ds);
} }
/*
* At this point the ds->ds_clp should be ready, but it might have
* hit an error.
*/
if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
WARN_ON_ONCE(1);
return -EINVAL;
}
return nfs_client_init_status(ds->ds_clp);
} }
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect); EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
......
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