Merge tag 'nfs-for-4.9-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[cascardo/linux.git] / fs / nfs / pnfs.c
index 2c93a85..56b2d96 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/module.h>
+#include <linux/sort.h>
 #include "internal.h"
 #include "pnfs.h"
 #include "iostat.h"
@@ -98,36 +99,80 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)
        nfss->pnfs_curr_ld = NULL;
 }
 
+/*
+ * When the server sends a list of layout types, we choose one in the order
+ * given in the list below.
+ *
+ * FIXME: should this list be configurable in some fashion? module param?
+ *       mount option? something else?
+ */
+static const u32 ld_prefs[] = {
+       LAYOUT_SCSI,
+       LAYOUT_BLOCK_VOLUME,
+       LAYOUT_OSD2_OBJECTS,
+       LAYOUT_FLEX_FILES,
+       LAYOUT_NFSV4_1_FILES,
+       0
+};
+
+static int
+ld_cmp(const void *e1, const void *e2)
+{
+       u32 ld1 = *((u32 *)e1);
+       u32 ld2 = *((u32 *)e2);
+       int i;
+
+       for (i = 0; ld_prefs[i] != 0; i++) {
+               if (ld1 == ld_prefs[i])
+                       return -1;
+
+               if (ld2 == ld_prefs[i])
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Try to set the server's pnfs module to the pnfs layout type specified by id.
  * Currently only one pNFS layout driver per filesystem is supported.
  *
- * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
+ * @ids array of layout types supported by MDS.
  */
 void
 set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
-                     u32 id)
+                     struct nfs_fsinfo *fsinfo)
 {
        struct pnfs_layoutdriver_type *ld_type = NULL;
+       u32 id;
+       int i;
 
-       if (id == 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: id %u cl_exchange_flags 0x%x\n",
-                       __func__, id, server->nfs_client->cl_exchange_flags);
+               printk(KERN_ERR "NFS: %s: cl_exchange_flags 0x%x\n",
+                       __func__, server->nfs_client->cl_exchange_flags);
                goto out_no_driver;
        }
-       ld_type = find_pnfs_driver(id);
-       if (!ld_type) {
-               request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
+
+       sort(fsinfo->layouttype, fsinfo->nlayouttypes,
+               sizeof(*fsinfo->layouttype), ld_cmp, NULL);
+
+       for (i = 0; i < fsinfo->nlayouttypes; i++) {
+               id = fsinfo->layouttype[i];
                ld_type = find_pnfs_driver(id);
                if (!ld_type) {
-                       dprintk("%s: No pNFS module found for %u.\n",
-                               __func__, id);
-                       goto out_no_driver;
+                       request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX,
+                                       id);
+                       ld_type = find_pnfs_driver(id);
                }
+               if (ld_type)
+                       break;
+       }
+
+       if (!ld_type) {
+               dprintk("%s: No pNFS module found!\n", __func__);
+               goto out_no_driver;
        }
+
        server->pnfs_curr_ld = ld_type;
        if (ld_type->set_layoutdriver
            && ld_type->set_layoutdriver(server, mntfh)) {
@@ -2185,10 +2230,8 @@ static void pnfs_ld_handle_read_error(struct nfs_pgio_header *hdr)
  */
 void pnfs_ld_read_done(struct nfs_pgio_header *hdr)
 {
-       if (likely(!hdr->pnfs_error)) {
-               __nfs4_read_done_cb(hdr);
+       if (likely(!hdr->pnfs_error))
                hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
-       }
        trace_nfs4_pnfs_read(hdr, hdr->pnfs_error);
        if (unlikely(hdr->pnfs_error))
                pnfs_ld_handle_read_error(hdr);