Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>

authored by

Weston Andros Adamson and committed by
Anna Schumaker
a33e4b03 03385332

+48 -6
+24 -1
fs/nfs/client.c
··· 325 325 return NULL; 326 326 } 327 327 328 - static bool nfs_client_init_is_complete(const struct nfs_client *clp) 328 + /* 329 + * Return true if @clp is done initializing, false if still working on it. 330 + * 331 + * Use nfs_client_init_status to check if it was successful. 332 + */ 333 + bool nfs_client_init_is_complete(const struct nfs_client *clp) 329 334 { 330 335 return clp->cl_cons_state <= NFS_CS_READY; 331 336 } 337 + EXPORT_SYMBOL_GPL(nfs_client_init_is_complete); 338 + 339 + /* 340 + * Return 0 if @clp was successfully initialized, -errno otherwise. 341 + * 342 + * This must be called *after* nfs_client_init_is_complete() returns true, 343 + * otherwise it will pop WARN_ON_ONCE and return -EINVAL 344 + */ 345 + int nfs_client_init_status(const struct nfs_client *clp) 346 + { 347 + /* called without checking nfs_client_init_is_complete */ 348 + if (clp->cl_cons_state > NFS_CS_READY) { 349 + WARN_ON_ONCE(1); 350 + return -EINVAL; 351 + } 352 + return clp->cl_cons_state; 353 + } 354 + EXPORT_SYMBOL_GPL(nfs_client_init_status); 332 355 333 356 int nfs_wait_client_init_complete(const struct nfs_client *clp) 334 357 {
+6 -1
fs/nfs/filelayout/filelayoutdev.c
··· 266 266 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); 267 267 struct nfs4_pnfs_ds *ret = ds; 268 268 struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); 269 + int status; 269 270 270 271 if (ds == NULL) { 271 272 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", ··· 278 277 if (ds->ds_clp) 279 278 goto out_test_devid; 280 279 281 - nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 280 + status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 282 281 dataserver_retrans, 4, 283 282 s->nfs_client->cl_minorversion); 283 + if (status) { 284 + ret = NULL; 285 + goto out; 286 + } 284 287 285 288 out_test_devid: 286 289 if (ret->ds_clp == NULL ||
+2 -1
fs/nfs/flexfilelayout/flexfilelayoutdev.c
··· 384 384 struct inode *ino = lseg->pls_layout->plh_inode; 385 385 struct nfs_server *s = NFS_SERVER(ino); 386 386 unsigned int max_payload; 387 + int status; 387 388 388 389 if (!ff_layout_mirror_valid(lseg, mirror, true)) { 389 390 pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", ··· 405 404 /* FIXME: For now we assume the server sent only one version of NFS 406 405 * to use for the DS. 407 406 */ 408 - nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 407 + status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 409 408 dataserver_retrans, 410 409 mirror->mirror_ds->ds_versions[0].version, 411 410 mirror->mirror_ds->ds_versions[0].minor_version);
+2
fs/nfs/internal.h
··· 186 186 struct nfs_fh *, 187 187 struct nfs_fattr *, 188 188 rpc_authflavor_t); 189 + extern bool nfs_client_init_is_complete(const struct nfs_client *clp); 190 + extern int nfs_client_init_status(const struct nfs_client *clp); 189 191 extern int nfs_wait_client_init_complete(const struct nfs_client *clp); 190 192 extern void nfs_mark_client_ready(struct nfs_client *clp, int state); 191 193 extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
+1 -1
fs/nfs/pnfs.h
··· 367 367 struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, 368 368 gfp_t gfp_flags); 369 369 void nfs4_pnfs_v3_ds_connect_unload(void); 370 - void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, 370 + int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, 371 371 struct nfs4_deviceid_node *devid, unsigned int timeo, 372 372 unsigned int retrans, u32 version, u32 minor_version); 373 373 struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
+13 -2
fs/nfs/pnfs_nfs.c
··· 745 745 /* 746 746 * Create an rpc connection to the nfs4_pnfs_ds data server. 747 747 * Currently only supports IPv4 and IPv6 addresses. 748 - * If connection fails, make devid unavailable. 748 + * If connection fails, make devid unavailable and return a -errno. 749 749 */ 750 - void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, 750 + int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, 751 751 struct nfs4_deviceid_node *devid, unsigned int timeo, 752 752 unsigned int retrans, u32 version, u32 minor_version) 753 753 { ··· 772 772 } else { 773 773 nfs4_wait_ds_connect(ds); 774 774 } 775 + 776 + /* 777 + * At this point the ds->ds_clp should be ready, but it might have 778 + * hit an error. 779 + */ 780 + if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) { 781 + WARN_ON_ONCE(1); 782 + return -EINVAL; 783 + } 784 + 785 + return nfs_client_init_status(ds->ds_clp); 775 786 } 776 787 EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect); 777 788