Merge tag 'nfs-for-4.9-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Nov 2016 17:15:30 +0000 (09:15 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Nov 2016 17:15:30 +0000 (09:15 -0800)
Pull NFS client bugfixes from Anna Schumaker:
 "Most of these fix regressions in 4.9, and none are going to stable
  this time around.

  Bugfixes:
   - Trim extra slashes in v4 nfs_paths to fix tools that use this
   - Fix a -Wmaybe-uninitialized warnings
   - Fix suspicious RCU usages
   - Fix Oops when mounting multiple servers at once
   - Suppress a false-positive pNFS error
   - Fix a DMAR failure in NFS over RDMA"

* tag 'nfs-for-4.9-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  xprtrdma: Fix DMAR failure in frwr_op_map() after reconnect
  fs/nfs: Fix used uninitialized warn in nfs4_slot_seqid_in_use()
  NFS: Don't print a pNFS error if we aren't using pNFS
  NFS: Ignore connections that have cl_rpcclient uninitialized
  SUNRPC: Fix suspicious RCU usage
  NFSv4.1: work around -Wmaybe-uninitialized warning
  NFS: Trim extra slash in v4 nfs_path

fs/nfs/client.c
fs/nfs/namespace.c
fs/nfs/nfs4session.c
fs/nfs/pnfs.c
net/sunrpc/clnt.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/xprt_rdma.h

index 7555ba889d1fce916cc96b8f23c03ad4d6037366..ebecfb8fba067cd4316e1c59e12c472c97d930a6 100644 (file)
@@ -314,7 +314,8 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
                /* Match the full socket address */
                if (!rpc_cmp_addr_port(sap, clap))
                        /* Match all xprt_switch full socket addresses */
-                       if (!rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
+                       if (IS_ERR(clp->cl_rpcclient) ||
+                            !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
                                                           sap))
                                continue;
 
index c8162c660c440bb28eb7e31fbd33ce1b4c3b1438..5551e8ef67fd0b64faa92688a8fa38b05bbb0c78 100644 (file)
@@ -98,7 +98,7 @@ rename_retry:
                return end;
        }
        namelen = strlen(base);
-       if (flags & NFS_PATH_CANONICAL) {
+       if (*end == '/') {
                /* Strip off excess slashes in base string */
                while (namelen > 0 && base[namelen - 1] == '/')
                        namelen--;
index b62973045a3e048016f1af48f761fdb152f3908d..a61350f75c741d734475cfa38903118d673b76aa 100644 (file)
@@ -178,12 +178,14 @@ static int nfs4_slot_get_seqid(struct nfs4_slot_table  *tbl, u32 slotid,
        __must_hold(&tbl->slot_tbl_lock)
 {
        struct nfs4_slot *slot;
+       int ret;
 
        slot = nfs4_lookup_slot(tbl, slotid);
-       if (IS_ERR(slot))
-               return PTR_ERR(slot);
-       *seq_nr = slot->seq_nr;
-       return 0;
+       ret = PTR_ERR_OR_ZERO(slot);
+       if (!ret)
+               *seq_nr = slot->seq_nr;
+
+       return ret;
 }
 
 /*
@@ -196,7 +198,7 @@ static int nfs4_slot_get_seqid(struct nfs4_slot_table  *tbl, u32 slotid,
 static bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl,
                u32 slotid, u32 seq_nr)
 {
-       u32 cur_seq;
+       u32 cur_seq = 0;
        bool ret = false;
 
        spin_lock(&tbl->slot_tbl_lock);
index 56b2d96f9103e42c57e5dd490f2561c8a10c554a..259ef85f435aa7f9e0b0e4d06d3ce24a9e7a3ad3 100644 (file)
@@ -146,6 +146,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
        u32 id;
        int i;
 
+       if (fsinfo->nlayouttypes == 0)
+               goto out_no_driver;
        if (!(server->nfs_client->cl_exchange_flags &
                 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
                printk(KERN_ERR "NFS: %s: cl_exchange_flags 0x%x\n",
index 34dd7b26ee5f16589a46f8c7faa158570ccec9ad..62a482790937b54a5d486bc932289b0fb14da248 100644 (file)
@@ -2753,14 +2753,18 @@ EXPORT_SYMBOL_GPL(rpc_cap_max_reconnect_timeout);
 
 void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
 {
+       rcu_read_lock();
        xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put);
 
 void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
 {
+       rcu_read_lock();
        rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
                                 xprt);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt);
 
@@ -2770,9 +2774,8 @@ bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
        struct rpc_xprt_switch *xps;
        bool ret;
 
-       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
-
        rcu_read_lock();
+       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
        ret = rpc_xprt_switch_has_addr(xps, sap);
        rcu_read_unlock();
        return ret;
index 210949562786665ea1a2990e2e9e6f886e580af6..26b26beef2d4a6dd7ef9d31f09de7fe51504d841 100644 (file)
  * being done.
  *
  * When the underlying transport disconnects, MRs are left in one of
- * three states:
+ * four states:
  *
  * INVALID:    The MR was not in use before the QP entered ERROR state.
- *             (Or, the LOCAL_INV WR has not completed or flushed yet).
- *
- * STALE:      The MR was being registered or unregistered when the QP
- *             entered ERROR state, and the pending WR was flushed.
  *
  * VALID:      The MR was registered before the QP entered ERROR state.
  *
- * When frwr_op_map encounters STALE and VALID MRs, they are recovered
- * with ib_dereg_mr and then are re-initialized. Beause MR recovery
+ * FLUSHED_FR: The MR was being registered when the QP entered ERROR
+ *             state, and the pending WR was flushed.
+ *
+ * FLUSHED_LI: The MR was being invalidated when the QP entered ERROR
+ *             state, and the pending WR was flushed.
+ *
+ * When frwr_op_map encounters FLUSHED and VALID MRs, they are recovered
+ * with ib_dereg_mr and then are re-initialized. Because MR recovery
  * allocates fresh resources, it is deferred to a workqueue, and the
  * recovered MRs are placed back on the rb_mws list when recovery is
  * complete. frwr_op_map allocates another MR for the current RPC while
@@ -177,12 +179,15 @@ __frwr_reset_mr(struct rpcrdma_ia *ia, struct rpcrdma_mw *r)
 static void
 frwr_op_recover_mr(struct rpcrdma_mw *mw)
 {
+       enum rpcrdma_frmr_state state = mw->frmr.fr_state;
        struct rpcrdma_xprt *r_xprt = mw->mw_xprt;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        int rc;
 
        rc = __frwr_reset_mr(ia, mw);
-       ib_dma_unmap_sg(ia->ri_device, mw->mw_sg, mw->mw_nents, mw->mw_dir);
+       if (state != FRMR_FLUSHED_LI)
+               ib_dma_unmap_sg(ia->ri_device,
+                               mw->mw_sg, mw->mw_nents, mw->mw_dir);
        if (rc)
                goto out_release;
 
@@ -262,10 +267,8 @@ frwr_op_maxpages(struct rpcrdma_xprt *r_xprt)
 }
 
 static void
-__frwr_sendcompletion_flush(struct ib_wc *wc, struct rpcrdma_frmr *frmr,
-                           const char *wr)
+__frwr_sendcompletion_flush(struct ib_wc *wc, const char *wr)
 {
-       frmr->fr_state = FRMR_IS_STALE;
        if (wc->status != IB_WC_WR_FLUSH_ERR)
                pr_err("rpcrdma: %s: %s (%u/0x%x)\n",
                       wr, ib_wc_status_msg(wc->status),
@@ -288,7 +291,8 @@ frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
        if (wc->status != IB_WC_SUCCESS) {
                cqe = wc->wr_cqe;
                frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-               __frwr_sendcompletion_flush(wc, frmr, "fastreg");
+               frmr->fr_state = FRMR_FLUSHED_FR;
+               __frwr_sendcompletion_flush(wc, "fastreg");
        }
 }
 
@@ -308,7 +312,8 @@ frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
        if (wc->status != IB_WC_SUCCESS) {
                cqe = wc->wr_cqe;
                frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+               frmr->fr_state = FRMR_FLUSHED_LI;
+               __frwr_sendcompletion_flush(wc, "localinv");
        }
 }
 
@@ -328,8 +333,10 @@ frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
        /* WARNING: Only wr_cqe and status are reliable at this point */
        cqe = wc->wr_cqe;
        frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-       if (wc->status != IB_WC_SUCCESS)
-               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+       if (wc->status != IB_WC_SUCCESS) {
+               frmr->fr_state = FRMR_FLUSHED_LI;
+               __frwr_sendcompletion_flush(wc, "localinv");
+       }
        complete(&frmr->fr_linv_done);
 }
 
index 0d35b761c883d01a044ba5f9c635bb3a7edce741..6e1bba358203694e79cbc9074554b12053fa45c7 100644 (file)
@@ -216,7 +216,8 @@ struct rpcrdma_rep {
 enum rpcrdma_frmr_state {
        FRMR_IS_INVALID,        /* ready to be used */
        FRMR_IS_VALID,          /* in use */
-       FRMR_IS_STALE,          /* failed completion */
+       FRMR_FLUSHED_FR,        /* flushed FASTREG WR */
+       FRMR_FLUSHED_LI,        /* flushed LOCALINV WR */
 };
 
 struct rpcrdma_frmr {