pnfs: pnfs_update_layout needs to consider if strict iomode checking is on
authorTom Haynes <thomas.haynes@primarydata.com>
Wed, 25 May 2016 14:31:14 +0000 (07:31 -0700)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Thu, 26 May 2016 12:40:56 +0000 (08:40 -0400)
As flexfiles has FF_FLAGS_NO_READ_IO, there is a need to generically
support enforcing that a IOMODE_RW segment will not allow READ I/O.

Signed-off-by: Tom Haynes <loghyr@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h

index 3e50057..aa59757 100644 (file)
@@ -890,6 +890,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                                           0,
                                           NFS4_MAX_UINT64,
                                           IOMODE_READ,
+                                          false,
                                           GFP_KERNEL);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
@@ -915,6 +916,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
                                           0,
                                           NFS4_MAX_UINT64,
                                           IOMODE_RW,
+                                          false,
                                           GFP_NOFS);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
index a7aeb74..0e8018b 100644 (file)
@@ -820,6 +820,36 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
        return NULL;
 }
 
+static void
+ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,
+                     struct nfs_page *req,
+                     bool strict_iomode)
+{
+retry_strict:
+       pnfs_put_lseg(pgio->pg_lseg);
+       pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                          req->wb_context,
+                                          0,
+                                          NFS4_MAX_UINT64,
+                                          IOMODE_READ,
+                                          strict_iomode,
+                                          GFP_KERNEL);
+       if (IS_ERR(pgio->pg_lseg)) {
+               pgio->pg_error = PTR_ERR(pgio->pg_lseg);
+               pgio->pg_lseg = NULL;
+       }
+
+       /* If we don't have checking, do get a IOMODE_RW
+        * segment, and the server wants to avoid READs
+        * there, then retry!
+        */
+       if (pgio->pg_lseg && !strict_iomode &&
+           ff_layout_avoid_read_on_rw(pgio->pg_lseg)) {
+               strict_iomode = true;
+               goto retry_strict;
+       }
+}
+
 static void
 ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                        struct nfs_page *req)
@@ -830,19 +860,10 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
        int ds_idx;
 
        /* Use full layout for now */
-       if (!pgio->pg_lseg || ff_layout_avoid_read_on_rw(pgio->pg_lseg)) {
-               pnfs_put_lseg(pgio->pg_lseg);
-               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
-                                                  req->wb_context,
-                                                  0,
-                                                  NFS4_MAX_UINT64,
-                                                  IOMODE_READ,
-                                                  GFP_KERNEL);
-               if (IS_ERR(pgio->pg_lseg)) {
-                       pgio->pg_error = PTR_ERR(pgio->pg_lseg);
-                       pgio->pg_lseg = NULL;
-               }
-       }
+       if (!pgio->pg_lseg)
+               ff_layout_pg_get_read(pgio, req, false);
+       else if (ff_layout_avoid_read_on_rw(pgio->pg_lseg))
+               ff_layout_pg_get_read(pgio, req, true);
 
        /* If no lseg, fall back to read through mds */
        if (pgio->pg_lseg == NULL)
@@ -894,6 +915,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
                                                   0,
                                                   NFS4_MAX_UINT64,
                                                   IOMODE_RW,
+                                                  false,
                                                   GFP_NOFS);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
@@ -952,6 +974,7 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
                                                   0,
                                                   NFS4_MAX_UINT64,
                                                   IOMODE_RW,
+                                                  false,
                                                   GFP_NOFS);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
index 79ae304..0c7e0d4 100644 (file)
@@ -1321,23 +1321,28 @@ out_existing:
 
 /*
  * iomode matching rules:
- * iomode      lseg    match
- * -----       -----   -----
- * ANY         READ    true
- * ANY         RW      true
- * RW          READ    false
- * RW          RW      true
- * READ                READ    true
- * READ                RW      true
+ * iomode      lseg    strict match
+ *                      iomode
+ * -----       -----   ------ -----
+ * ANY         READ    N/A    true
+ * ANY         RW      N/A    true
+ * RW          READ    N/A    false
+ * RW          RW      N/A    true
+ * READ                READ    N/A    true
+ * READ                RW      true   false
+ * READ                RW      false  true
  */
 static bool
 pnfs_lseg_range_match(const struct pnfs_layout_range *ls_range,
-                const struct pnfs_layout_range *range)
+                const struct pnfs_layout_range *range,
+                bool strict_iomode)
 {
        struct pnfs_layout_range range1;
 
        if ((range->iomode == IOMODE_RW &&
             ls_range->iomode != IOMODE_RW) ||
+           (range->iomode != ls_range->iomode &&
+            strict_iomode == true) ||
            !pnfs_lseg_range_intersecting(ls_range, range))
                return 0;
 
@@ -1352,7 +1357,8 @@ pnfs_lseg_range_match(const struct pnfs_layout_range *ls_range,
  */
 static struct pnfs_layout_segment *
 pnfs_find_lseg(struct pnfs_layout_hdr *lo,
-               struct pnfs_layout_range *range)
+               struct pnfs_layout_range *range,
+               bool strict_iomode)
 {
        struct pnfs_layout_segment *lseg, *ret = NULL;
 
@@ -1361,7 +1367,8 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo,
        list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
                if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
                    !test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags) &&
-                   pnfs_lseg_range_match(&lseg->pls_range, range)) {
+                   pnfs_lseg_range_match(&lseg->pls_range, range,
+                                         strict_iomode)) {
                        ret = pnfs_get_lseg(lseg);
                        break;
                }
@@ -1478,6 +1485,7 @@ pnfs_update_layout(struct inode *ino,
                   loff_t pos,
                   u64 count,
                   enum pnfs_iomode iomode,
+                  bool strict_iomode,
                   gfp_t gfp_flags)
 {
        struct pnfs_layout_range arg = {
@@ -1539,7 +1547,7 @@ lookup_again:
                goto out_unlock;
        }
 
-       lseg = pnfs_find_lseg(lo, &arg);
+       lseg = pnfs_find_lseg(lo, &arg, strict_iomode);
        if (lseg) {
                trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                PNFS_UPDATE_LAYOUT_FOUND_CACHED);
@@ -1883,6 +1891,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
                                                   req_offset(req),
                                                   rd_size,
                                                   IOMODE_READ,
+                                                  false,
                                                   GFP_KERNEL);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
@@ -1907,6 +1916,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
                                                   req_offset(req),
                                                   wb_size,
                                                   IOMODE_RW,
+                                                  false,
                                                   GFP_NOFS);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
index f9f3331..b21bd0b 100644 (file)
@@ -288,6 +288,7 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
                                               loff_t pos,
                                               u64 count,
                                               enum pnfs_iomode iomode,
+                                              bool strict_iomode,
                                               gfp_t gfp_flags);
 void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo);