Merge tag 'perf-core-for-mingo-20160901' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / fs / nfs / flexfilelayout / flexfilelayoutdev.c
index add0e5a..f7a3f6b 100644 (file)
@@ -17,8 +17,8 @@
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
 
-static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO;
-static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS;
+static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS;
+static unsigned int dataserver_retrans;
 
 void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds)
 {
@@ -228,7 +228,8 @@ ff_ds_error_match(const struct nfs4_ff_layout_ds_err *e1,
                return e1->opnum < e2->opnum ? -1 : 1;
        if (e1->status != e2->status)
                return e1->status < e2->status ? -1 : 1;
-       ret = memcmp(&e1->stateid, &e2->stateid, sizeof(e1->stateid));
+       ret = memcmp(e1->stateid.data, e2->stateid.data,
+                       sizeof(e1->stateid.data));
        if (ret != 0)
                return ret;
        ret = memcmp(&e1->deviceid, &e2->deviceid, sizeof(e1->deviceid));
@@ -302,40 +303,26 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
        return 0;
 }
 
-/* currently we only support AUTH_NONE and AUTH_SYS */
-static rpc_authflavor_t
-nfs4_ff_layout_choose_authflavor(struct nfs4_ff_layout_mirror *mirror)
+static struct rpc_cred *
+ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode)
 {
-       if (mirror->uid == (u32)-1)
-               return RPC_AUTH_NULL;
-       return RPC_AUTH_UNIX;
-}
+       struct rpc_cred *cred, __rcu **pcred;
 
-/* fetch cred for NFSv3 DS */
-static int ff_layout_update_mirror_cred(struct nfs4_ff_layout_mirror *mirror,
-                                     struct nfs4_pnfs_ds *ds)
-{
-       if (ds->ds_clp && !mirror->cred &&
-           mirror->mirror_ds->ds_versions[0].version == 3) {
-               struct rpc_auth *auth = ds->ds_clp->cl_rpcclient->cl_auth;
-               struct rpc_cred *cred;
-               struct auth_cred acred = {
-                       .uid = make_kuid(&init_user_ns, mirror->uid),
-                       .gid = make_kgid(&init_user_ns, mirror->gid),
-               };
-
-               /* AUTH_NULL ignores acred */
-               cred = auth->au_ops->lookup_cred(auth, &acred, 0);
-               if (IS_ERR(cred)) {
-                       dprintk("%s: lookup_cred failed with %ld\n",
-                               __func__, PTR_ERR(cred));
-                       return PTR_ERR(cred);
-               } else {
-                       if (cmpxchg(&mirror->cred, NULL, cred))
-                               put_rpccred(cred);
-               }
-       }
-       return 0;
+       if (iomode == IOMODE_READ)
+               pcred = &mirror->ro_cred;
+       else
+               pcred = &mirror->rw_cred;
+
+       rcu_read_lock();
+       do {
+               cred = rcu_dereference(*pcred);
+               if (!cred)
+                       break;
+
+               cred = get_rpccred_rcu(cred);
+       } while(!cred);
+       rcu_read_unlock();
+       return cred;
 }
 
 struct nfs_fh *
@@ -356,7 +343,23 @@ out:
        return fh;
 }
 
-/* Upon return, either ds is connected, or ds is NULL */
+/**
+ * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
+ * @lseg: the layout segment we're operating on
+ * @ds_idx: index of the DS to use
+ * @fail_return: return layout on connect failure?
+ *
+ * Try to prepare a DS connection to accept an RPC call. This involves
+ * selecting a mirror to use and connecting the client to it if it's not
+ * already connected.
+ *
+ * Since we only need a single functioning mirror to satisfy a read, we don't
+ * want to return the layout if there is one. For writes though, any down
+ * mirror should result in a LAYOUTRETURN. @fail_return is how we distinguish
+ * between the two cases.
+ *
+ * Returns a pointer to a connected DS object on success or NULL on failure.
+ */
 struct nfs4_pnfs_ds *
 nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
                          bool fail_return)
@@ -367,7 +370,6 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
        struct inode *ino = lseg->pls_layout->plh_inode;
        struct nfs_server *s = NFS_SERVER(ino);
        unsigned int max_payload;
-       rpc_authflavor_t flavor;
 
        if (!ff_layout_mirror_valid(lseg, mirror)) {
                pr_err_ratelimited("NFS: %s: No data server for offset index %d\n",
@@ -377,15 +379,13 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
 
        devid = &mirror->mirror_ds->id_node;
        if (ff_layout_test_devid_unavailable(devid))
-               goto out;
+               goto out_fail;
 
        ds = mirror->mirror_ds->ds;
        /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
        smp_rmb();
        if (ds->ds_clp)
-               goto out_update_creds;
-
-       flavor = nfs4_ff_layout_choose_authflavor(mirror);
+               goto out;
 
        /* FIXME: For now we assume the server sent only one version of NFS
         * to use for the DS.
@@ -394,7 +394,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
                             dataserver_retrans,
                             mirror->mirror_ds->ds_versions[0].version,
                             mirror->mirror_ds->ds_versions[0].minor_version,
-                            flavor);
+                            RPC_AUTH_UNIX);
 
        /* connect success, check rsize/wsize limit */
        if (ds->ds_clp) {
@@ -405,25 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
                        mirror->mirror_ds->ds_versions[0].rsize = max_payload;
                if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
                        mirror->mirror_ds->ds_versions[0].wsize = max_payload;
-       } else {
-               ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
-                                        mirror, lseg->pls_range.offset,
-                                        lseg->pls_range.length, NFS4ERR_NXIO,
-                                        OP_ILLEGAL, GFP_NOIO);
-               if (!fail_return) {
-                       if (ff_layout_has_available_ds(lseg))
-                               set_bit(NFS_LAYOUT_RETURN_REQUESTED,
-                                       &lseg->pls_layout->plh_flags);
-                       else
-                               pnfs_error_mark_layout_for_return(ino, lseg);
-               } else
-                       pnfs_error_mark_layout_for_return(ino, lseg);
-               ds = NULL;
                goto out;
        }
-out_update_creds:
-       if (ff_layout_update_mirror_cred(mirror, ds))
-               ds = NULL;
+       ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
+                                mirror, lseg->pls_range.offset,
+                                lseg->pls_range.length, NFS4ERR_NXIO,
+                                OP_ILLEGAL, GFP_NOIO);
+out_fail:
+       if (fail_return || !ff_layout_has_available_ds(lseg))
+               pnfs_error_mark_layout_for_return(ino, lseg);
+       ds = NULL;
 out:
        return ds;
 }
@@ -433,16 +424,15 @@ ff_layout_get_ds_cred(struct pnfs_layout_segment *lseg, u32 ds_idx,
                      struct rpc_cred *mdscred)
 {
        struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, ds_idx);
-       struct rpc_cred *cred = ERR_PTR(-EINVAL);
-
-       if (!nfs4_ff_layout_prepare_ds(lseg, ds_idx, true))
-               goto out;
+       struct rpc_cred *cred;
 
-       if (mirror && mirror->cred)
-               cred = mirror->cred;
-       else
-               cred = mdscred;
-out:
+       if (mirror) {
+               cred = ff_layout_get_mirror_cred(mirror, lseg->pls_range.iomode);
+               if (!cred)
+                       cred = get_rpccred(mdscred);
+       } else {
+               cred = get_rpccred(mdscred);
+       }
        return cred;
 }
 
@@ -562,6 +552,18 @@ bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg)
        return ff_rw_layout_has_available_ds(lseg);
 }
 
+bool ff_layout_avoid_mds_available_ds(struct pnfs_layout_segment *lseg)
+{
+       return ff_layout_no_fallback_to_mds(lseg) ||
+              ff_layout_has_available_ds(lseg);
+}
+
+bool ff_layout_avoid_read_on_rw(struct pnfs_layout_segment *lseg)
+{
+       return lseg->pls_range.iomode == IOMODE_RW &&
+              ff_layout_no_read_on_rw(lseg);
+}
+
 module_param(dataserver_retrans, uint, 0644);
 MODULE_PARM_DESC(dataserver_retrans, "The  number of times the NFSv4.1 client "
                        "retries a request before it attempts further "