Merge tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 31 Mar 2017 19:29:03 +0000 (12:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 31 Mar 2017 19:29:03 +0000 (12:29 -0700)
Pull NFS client fixes from Anna Schumaker:
 "Here are a few more bugfixes that came in over the last couple of
  weeks. Most of these fix various hangs and loops that people found,
  but we also had a few error handling fixes.

  Stable Bugfixes:
   - fix infinite loop on BAD_STATEID error

  Other Bugfixes:
   - fix old dentry rehash after move
   - fix pnfs GETDEVINFO hangs
   - fix pnfs fallback to MDS on commit errors
   - fix flexfiles kernel oops"

* tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  nfs: flexfiles: fix kernel OOPS if MDS returns unsupported DS type
  NFSv4.1 fix infinite loop on IO BAD_STATEID error
  PNFS fix fallback to MDS if got error on commit to DS
  NFS filelayout:call GETDEVICEINFO after pnfs_layout_process completes
  NFS store nfs4_deviceid in struct nfs4_filelayout_segment
  NFS cleanup struct nfs4_filelayout_segment
  NFS: Fix old dentry rehash after move

1  2 
fs/nfs/filelayout/filelayout.c

index 44347f4bdc1516f54f030ca9f0d95332ab816116,c9230fecc77ea1d12ff975173d0b0922eca63ea6..acd30baca46166c902aa5dfae1663184cc30e235
@@@ -202,10 -202,10 +202,10 @@@ static int filelayout_async_handle_erro
                        task->tk_status);
                nfs4_mark_deviceid_unavailable(devid);
                pnfs_error_mark_layout_for_return(inode, lseg);
-               pnfs_set_lo_fail(lseg);
                rpc_wake_up(&tbl->slot_tbl_waitq);
                /* fall through */
        default:
+               pnfs_set_lo_fail(lseg);
  reset:
                dprintk("%s Retry through MDS. Error %d\n", __func__,
                        task->tk_status);
@@@ -482,7 -482,7 +482,7 @@@ filelayout_read_pagelist(struct nfs_pgi
        u32 j, idx;
        struct nfs_fh *fh;
  
 -      dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
 +      dprintk("--> %s ino %lu pgbase %u req %zu@%llu\n",
                __func__, hdr->inode->i_ino,
                hdr->args.pgbase, (size_t)hdr->args.count, offset);
  
@@@ -540,7 -540,7 +540,7 @@@ filelayout_write_pagelist(struct nfs_pg
        if (IS_ERR(ds_clnt))
                return PNFS_NOT_ATTEMPTED;
  
 -      dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n",
 +      dprintk("%s ino %lu sync %d req %zu@%llu DS: %s cl_count %d\n",
                __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count,
                offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
  
        return PNFS_ATTEMPTED;
  }
  
+ static int
+ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
+                         struct nfs4_filelayout_segment *fl,
+                         gfp_t gfp_flags)
+ {
+       struct nfs4_deviceid_node *d;
+       struct nfs4_file_layout_dsaddr *dsaddr;
+       int status = -EINVAL;
+       /* find and reference the deviceid */
+       d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
+                       lo->plh_lc_cred, gfp_flags);
+       if (d == NULL)
+               goto out;
+       dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
+       /* Found deviceid is unavailable */
+       if (filelayout_test_devid_unavailable(&dsaddr->id_node))
+               goto out_put;
+       fl->dsaddr = dsaddr;
+       if (fl->first_stripe_index >= dsaddr->stripe_count) {
+               dprintk("%s Bad first_stripe_index %u\n",
+                               __func__, fl->first_stripe_index);
+               goto out_put;
+       }
+       if ((fl->stripe_type == STRIPE_SPARSE &&
+           fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
+           (fl->stripe_type == STRIPE_DENSE &&
+           fl->num_fh != dsaddr->stripe_count)) {
+               dprintk("%s num_fh %u not valid for given packing\n",
+                       __func__, fl->num_fh);
+               goto out_put;
+       }
+       status = 0;
+ out:
+       return status;
+ out_put:
+       nfs4_fl_put_deviceid(dsaddr);
+       goto out;
+ }
  /*
   * filelayout_check_layout()
   *
@@@ -572,11 -616,8 +616,8 @@@ static in
  filelayout_check_layout(struct pnfs_layout_hdr *lo,
                        struct nfs4_filelayout_segment *fl,
                        struct nfs4_layoutget_res *lgr,
-                       struct nfs4_deviceid *id,
                        gfp_t gfp_flags)
  {
-       struct nfs4_deviceid_node *d;
-       struct nfs4_file_layout_dsaddr *dsaddr;
        int status = -EINVAL;
  
        dprintk("--> %s\n", __func__);
                goto out;
        }
  
-       /* find and reference the deviceid */
-       d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), id,
-                       lo->plh_lc_cred, gfp_flags);
-       if (d == NULL)
-               goto out;
-       dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
-       /* Found deviceid is unavailable */
-       if (filelayout_test_devid_unavailable(&dsaddr->id_node))
-               goto out_put;
-       fl->dsaddr = dsaddr;
-       if (fl->first_stripe_index >= dsaddr->stripe_count) {
-               dprintk("%s Bad first_stripe_index %u\n",
-                               __func__, fl->first_stripe_index);
-               goto out_put;
-       }
-       if ((fl->stripe_type == STRIPE_SPARSE &&
-           fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
-           (fl->stripe_type == STRIPE_DENSE &&
-           fl->num_fh != dsaddr->stripe_count)) {
-               dprintk("%s num_fh %u not valid for given packing\n",
-                       __func__, fl->num_fh);
-               goto out_put;
-       }
        status = 0;
  out:
        dprintk("--> %s returns %d\n", __func__, status);
        return status;
- out_put:
-       nfs4_fl_put_deviceid(dsaddr);
-       goto out;
  }
  
  static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
@@@ -657,7 -667,6 +667,6 @@@ static in
  filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                         struct nfs4_filelayout_segment *fl,
                         struct nfs4_layoutget_res *lgr,
-                        struct nfs4_deviceid *id,
                         gfp_t gfp_flags)
  {
        struct xdr_stream stream;
        if (unlikely(!p))
                goto out_err;
  
-       memcpy(id, p, sizeof(*id));
+       memcpy(&fl->deviceid, p, sizeof(fl->deviceid));
        p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
-       nfs4_print_deviceid(id);
+       nfs4_print_deviceid(&fl->deviceid);
  
        nfl_util = be32_to_cpup(p++);
        if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
@@@ -831,15 -840,14 +840,14 @@@ filelayout_alloc_lseg(struct pnfs_layou
  {
        struct nfs4_filelayout_segment *fl;
        int rc;
-       struct nfs4_deviceid id;
  
        dprintk("--> %s\n", __func__);
        fl = kzalloc(sizeof(*fl), gfp_flags);
        if (!fl)
                return NULL;
  
-       rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
-       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
+       rc = filelayout_decode_layout(layoutid, fl, lgr, gfp_flags);
+       if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, gfp_flags)) {
                _filelayout_free_lseg(fl);
                return NULL;
        }
@@@ -888,18 -896,51 +896,51 @@@ filelayout_pg_test(struct nfs_pageio_de
        return min(stripe_unit - (unsigned int)stripe_offset, size);
  }
  
+ static struct pnfs_layout_segment *
+ fl_pnfs_update_layout(struct inode *ino,
+                     struct nfs_open_context *ctx,
+                     loff_t pos,
+                     u64 count,
+                     enum pnfs_iomode iomode,
+                     bool strict_iomode,
+                     gfp_t gfp_flags)
+ {
+       struct pnfs_layout_segment *lseg = NULL;
+       struct pnfs_layout_hdr *lo;
+       struct nfs4_filelayout_segment *fl;
+       int status;
+       lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
+                                 gfp_flags);
+       if (!lseg)
+               lseg = ERR_PTR(-ENOMEM);
+       if (IS_ERR(lseg))
+               goto out;
+       lo = NFS_I(ino)->layout;
+       fl = FILELAYOUT_LSEG(lseg);
+       status = filelayout_check_deviceid(lo, fl, gfp_flags);
+       if (status)
+               lseg = ERR_PTR(status);
+ out:
+       if (IS_ERR(lseg))
+               pnfs_put_lseg(lseg);
+       return lseg;
+ }
  static void
  filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                        struct nfs_page *req)
  {
        if (!pgio->pg_lseg) {
-               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
-                                          req->wb_context,
-                                          0,
-                                          NFS4_MAX_UINT64,
-                                          IOMODE_READ,
-                                          false,
-                                          GFP_KERNEL);
+               pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
+                                                     req->wb_context,
+                                                     0,
+                                                     NFS4_MAX_UINT64,
+                                                     IOMODE_READ,
+                                                     false,
+                                                     GFP_KERNEL);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
                        pgio->pg_lseg = NULL;
@@@ -919,13 -960,13 +960,13 @@@ filelayout_pg_init_write(struct nfs_pag
        int status;
  
        if (!pgio->pg_lseg) {
-               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
-                                          req->wb_context,
-                                          0,
-                                          NFS4_MAX_UINT64,
-                                          IOMODE_RW,
-                                          false,
-                                          GFP_NOFS);
+               pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
+                                                     req->wb_context,
+                                                     0,
+                                                     NFS4_MAX_UINT64,
+                                                     IOMODE_RW,
+                                                     false,
+                                                     GFP_NOFS);
                if (IS_ERR(pgio->pg_lseg)) {
                        pgio->pg_error = PTR_ERR(pgio->pg_lseg);
                        pgio->pg_lseg = NULL;