nfs41: create NFSv3 DS connection if specified
authorPeng Tao <tao.peng@primarydata.com>
Fri, 30 May 2014 10:15:59 +0000 (18:15 +0800)
committerTom Haynes <loghyr@primarydata.com>
Tue, 3 Feb 2015 19:06:35 +0000 (11:06 -0800)
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
Signed-off-by: Tom Haynes <Thomas.Haynes@primarydata.com>
fs/nfs/nfs4super.c
fs/nfs/pnfs.h
fs/nfs/pnfs_nfs.c

index 6f340f0..48cea3c 100644 (file)
@@ -346,6 +346,9 @@ out:
 
 static void __exit exit_nfs_v4(void)
 {
+       /* Not called in the _init(), conditionally loaded */
+       nfs4_pnfs_v3_ds_connect_unload();
+
        unregister_nfs_version(&nfs_v4);
        nfs4_unregister_sysctl();
        nfs_idmap_quit();
index 70ffec1..c398821 100644 (file)
@@ -323,9 +323,10 @@ void pnfs_generic_write_commit_done(struct rpc_task *task, void *data);
 void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds);
 struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs,
                                      gfp_t gfp_flags);
+void nfs4_pnfs_v3_ds_connect_unload(void);
 void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
                          struct nfs4_deviceid_node *devid, unsigned int timeo,
-                         unsigned int retrans, u32 versoin, u32 minor_version,
+                         unsigned int retrans, u32 version, u32 minor_version,
                          rpc_authflavor_t au_flavor);
 struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
                                                 struct xdr_stream *xdr,
@@ -615,6 +616,10 @@ static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
        return NULL;
 }
 
+static inline void nfs4_pnfs_v3_ds_connect_unload(void)
+{
+}
+
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */
index ad211a4..23c851d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/sunrpc/addr.h>
+#include <linux/module.h>
 
 #include "nfs4session.h"
 #include "internal.h"
@@ -550,7 +551,75 @@ static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
        wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
 }
 
-static int _nfs4_pnfs_ds_connect(struct nfs_server *mds_srv,
+static struct nfs_client *(*get_v3_ds_connect)(
+                       struct nfs_client *mds_clp,
+                       const struct sockaddr *ds_addr,
+                       int ds_addrlen,
+                       int ds_proto,
+                       unsigned int ds_timeo,
+                       unsigned int ds_retrans,
+                       rpc_authflavor_t au_flavor);
+
+static bool load_v3_ds_connect(void)
+{
+       if (!get_v3_ds_connect) {
+               get_v3_ds_connect = symbol_request(nfs3_set_ds_client);
+               WARN_ON_ONCE(!get_v3_ds_connect);
+       }
+
+       return(get_v3_ds_connect != NULL);
+}
+
+void __exit nfs4_pnfs_v3_ds_connect_unload(void)
+{
+       if (get_v3_ds_connect) {
+               symbol_put(nfs3_set_ds_client);
+               get_v3_ds_connect = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(nfs4_pnfs_v3_ds_connect_unload);
+
+static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
+                                struct nfs4_pnfs_ds *ds,
+                                unsigned int timeo,
+                                unsigned int retrans,
+                                rpc_authflavor_t au_flavor)
+{
+       struct nfs_client *clp = ERR_PTR(-EIO);
+       struct nfs4_pnfs_ds_addr *da;
+       int status = 0;
+
+       dprintk("--> %s DS %s au_flavor %d\n", __func__,
+               ds->ds_remotestr, au_flavor);
+
+       if (!load_v3_ds_connect())
+               goto out;
+
+       list_for_each_entry(da, &ds->ds_addrs, da_node) {
+               dprintk("%s: DS %s: trying address %s\n",
+                       __func__, ds->ds_remotestr, da->da_remotestr);
+
+               clp = get_v3_ds_connect(mds_srv->nfs_client,
+                                       (struct sockaddr *)&da->da_addr,
+                                       da->da_addrlen, IPPROTO_TCP,
+                                       timeo, retrans, au_flavor);
+               if (!IS_ERR(clp))
+                       break;
+       }
+
+       if (IS_ERR(clp)) {
+               status = PTR_ERR(clp);
+               goto out;
+       }
+
+       smp_wmb();
+       ds->ds_clp = clp;
+       dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
+out:
+       return status;
+}
+
+static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                                 struct nfs4_pnfs_ds *ds,
                                 unsigned int timeo,
                                 unsigned int retrans,
@@ -562,7 +631,7 @@ static int _nfs4_pnfs_ds_connect(struct nfs_server *mds_srv,
        int status = 0;
 
        dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
-               mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
+               au_flavor);
 
        list_for_each_entry(da, &ds->ds_addrs, da_node) {
                dprintk("%s: DS %s: trying address %s\n",
@@ -609,8 +678,19 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
        if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
                int err = 0;
 
-               err = _nfs4_pnfs_ds_connect(mds_srv, ds, timeo, retrans,
-                                           minor_version, au_flavor);
+               if (version == 3) {
+                       err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo,
+                                                      retrans, au_flavor);
+               } else if (version == 4) {
+                       err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo,
+                                                      retrans, minor_version,
+                                                      au_flavor);
+               } else {
+                       dprintk("%s: unsupported DS version %d\n", __func__,
+                               version);
+                       err = -EPROTONOSUPPORT;
+               }
+
                if (err)
                        nfs4_mark_deviceid_unavailable(devid);
                nfs4_clear_ds_conn_bit(ds);