NFSv4.1: nfs4_fl_prepare_ds - fix bugs when the connect attempt fails
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 26 Sep 2013 18:08:36 +0000 (14:08 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sun, 29 Sep 2013 19:56:35 +0000 (15:56 -0400)
- Fix an Oops when nfs4_ds_connect() returns an error.
- Always check the device status after waiting for a connect to complete.

Reported-by: Andy Adamson <andros@netapp.com>
Reported-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: <stable@vger.kernel.org> # v3.10+
fs/nfs/nfs4filelayoutdev.c

index 95604f6..cd3aef5 100644 (file)
@@ -801,34 +801,34 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
        struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
-
-       if (filelayout_test_devid_unavailable(devid))
-               return NULL;
+       struct nfs4_pnfs_ds *ret = ds;
 
        if (ds == NULL) {
                printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
                        __func__, ds_idx);
                filelayout_mark_devid_invalid(devid);
-               return NULL;
+               goto out;
        }
        if (ds->ds_clp)
-               return ds;
+               goto out_test_devid;
 
        if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
                struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
                int err;
 
                err = nfs4_ds_connect(s, ds);
-               if (err) {
+               if (err)
                        nfs4_mark_deviceid_unavailable(devid);
-                       ds = NULL;
-               }
                nfs4_clear_ds_conn_bit(ds);
        } else {
                /* Either ds is connected, or ds is NULL */
                nfs4_wait_ds_connect(ds);
        }
-       return ds;
+out_test_devid:
+       if (filelayout_test_devid_unavailable(devid))
+               ret = NULL;
+out:
+       return ret;
 }
 
 module_param(dataserver_retrans, uint, 0644);