Merge tag 'nfsd-4.6-1' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Mar 2016 02:50:32 +0000 (19:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Mar 2016 02:50:32 +0000 (19:50 -0700)
Pull more nfsd updates from Bruce Fields:
 "Apologies for the previous request, which omitted the top 8 commits
  from my for-next branch (including the SCSI layout commits).  Thanks
  to Trond for spotting my error!"

This actually includes the new layout types, so here's that part of
the pull message repeated:

 "Support for a new pnfs layout type from Christoph Hellwig.  The new
  layout type is a variant of the block layout which uses SCSI features
  to offer improved fencing and device identification.

  Note this pull request also includes the client side of SCSI layout,
  with Trond's permission"

* tag 'nfsd-4.6-1' of git://linux-nfs.org/~bfields/linux:
  nfsd: use short read as well as i_size to set eof
  nfsd: better layoutupdate bounds-checking
  nfsd: block and scsi layout drivers need to depend on CONFIG_BLOCK
  nfsd: add SCSI layout support
  nfsd: move some blocklayout code
  nfsd: add a new config option for the block layout driver
  nfs/blocklayout: add SCSI layout support
  nfs4.h: add SCSI layout definitions

1  2 
fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/extent_tree.c
fs/xfs/xfs_export.c

@@@ -446,8 -446,8 +446,8 @@@ static void bl_free_layout_hdr(struct p
        kfree(bl);
  }
  
- static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
-                                                  gfp_t gfp_flags)
+ static struct pnfs_layout_hdr *__bl_alloc_layout_hdr(struct inode *inode,
+               gfp_t gfp_flags, bool is_scsi_layout)
  {
        struct pnfs_block_layout *bl;
  
        bl->bl_ext_ro = RB_ROOT;
        spin_lock_init(&bl->bl_ext_lock);
  
+       bl->bl_scsi_layout = is_scsi_layout;
        return &bl->bl_layout;
  }
  
+ static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+ {
+       return __bl_alloc_layout_hdr(inode, gfp_flags, false);
+ }
+ static struct pnfs_layout_hdr *sl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+ {
+       return __bl_alloc_layout_hdr(inode, gfp_flags, true);
+ }
  static void bl_free_lseg(struct pnfs_layout_segment *lseg)
  {
        dprintk("%s enter\n", __func__);
@@@ -743,7 -756,7 +756,7 @@@ bl_set_layoutdriver(struct nfs_server *
  
  static bool
  is_aligned_req(struct nfs_pageio_descriptor *pgio,
 -              struct nfs_page *req, unsigned int alignment)
 +              struct nfs_page *req, unsigned int alignment, bool is_write)
  {
        /*
         * Always accept buffered writes, higher layers take care of the
        if (IS_ALIGNED(req->wb_bytes, alignment))
                return true;
  
 -      if (req_offset(req) + req->wb_bytes == i_size_read(pgio->pg_inode)) {
 +      if (is_write &&
 +          (req_offset(req) + req->wb_bytes == i_size_read(pgio->pg_inode))) {
                /*
                 * If the write goes up to the inode size, just write
                 * the full page.  Data past the inode size is
  static void
  bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
  {
 -      if (!is_aligned_req(pgio, req, SECTOR_SIZE)) {
 +      if (!is_aligned_req(pgio, req, SECTOR_SIZE, false)) {
                nfs_pageio_reset_read_mds(pgio);
                return;
        }
@@@ -792,7 -804,7 +805,7 @@@ static size_
  bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
                struct nfs_page *req)
  {
 -      if (!is_aligned_req(pgio, req, SECTOR_SIZE))
 +      if (!is_aligned_req(pgio, req, SECTOR_SIZE, false))
                return 0;
        return pnfs_generic_pg_test(pgio, prev, req);
  }
@@@ -825,7 -837,7 +838,7 @@@ bl_pg_init_write(struct nfs_pageio_desc
  {
        u64 wb_size;
  
 -      if (!is_aligned_req(pgio, req, PAGE_SIZE)) {
 +      if (!is_aligned_req(pgio, req, PAGE_SIZE, true)) {
                nfs_pageio_reset_write_mds(pgio);
                return;
        }
@@@ -847,7 -859,7 +860,7 @@@ static size_
  bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
                 struct nfs_page *req)
  {
 -      if (!is_aligned_req(pgio, req, PAGE_SIZE))
 +      if (!is_aligned_req(pgio, req, PAGE_SIZE, true))
                return 0;
        return pnfs_generic_pg_test(pgio, prev, req);
  }
@@@ -889,22 -901,53 +902,53 @@@ static struct pnfs_layoutdriver_type bl
        .sync                           = pnfs_generic_sync,
  };
  
+ static struct pnfs_layoutdriver_type scsilayout_type = {
+       .id                             = LAYOUT_SCSI,
+       .name                           = "LAYOUT_SCSI",
+       .owner                          = THIS_MODULE,
+       .flags                          = PNFS_LAYOUTRET_ON_SETATTR |
+                                         PNFS_READ_WHOLE_PAGE,
+       .read_pagelist                  = bl_read_pagelist,
+       .write_pagelist                 = bl_write_pagelist,
+       .alloc_layout_hdr               = sl_alloc_layout_hdr,
+       .free_layout_hdr                = bl_free_layout_hdr,
+       .alloc_lseg                     = bl_alloc_lseg,
+       .free_lseg                      = bl_free_lseg,
+       .return_range                   = bl_return_range,
+       .prepare_layoutcommit           = bl_prepare_layoutcommit,
+       .cleanup_layoutcommit           = bl_cleanup_layoutcommit,
+       .set_layoutdriver               = bl_set_layoutdriver,
+       .alloc_deviceid_node            = bl_alloc_deviceid_node,
+       .free_deviceid_node             = bl_free_deviceid_node,
+       .pg_read_ops                    = &bl_pg_read_ops,
+       .pg_write_ops                   = &bl_pg_write_ops,
+       .sync                           = pnfs_generic_sync,
+ };
  static int __init nfs4blocklayout_init(void)
  {
        int ret;
  
        dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
  
-       ret = pnfs_register_layoutdriver(&blocklayout_type);
+       ret = bl_init_pipefs();
        if (ret)
                goto out;
-       ret = bl_init_pipefs();
+       ret = pnfs_register_layoutdriver(&blocklayout_type);
        if (ret)
-               goto out_unregister;
+               goto out_cleanup_pipe;
+       ret = pnfs_register_layoutdriver(&scsilayout_type);
+       if (ret)
+               goto out_unregister_block;
        return 0;
  
- out_unregister:
+ out_unregister_block:
        pnfs_unregister_layoutdriver(&blocklayout_type);
+ out_cleanup_pipe:
+       bl_cleanup_pipefs();
  out:
        return ret;
  }
@@@ -914,8 -957,9 +958,9 @@@ static void __exit nfs4blocklayout_exit
        dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
               __func__);
  
-       bl_cleanup_pipefs();
+       pnfs_unregister_layoutdriver(&scsilayout_type);
        pnfs_unregister_layoutdriver(&blocklayout_type);
+       bl_cleanup_pipefs();
  }
  
  MODULE_ALIAS("nfs-layouttype4-3");
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2014 Christoph Hellwig.
+  * Copyright (c) 2014-2016 Christoph Hellwig.
   */
  
  #include <linux/vmalloc.h>
@@@ -462,10 -462,12 +462,12 @@@ out
        return err;
  }
  
- static size_t ext_tree_layoutupdate_size(size_t count)
+ static size_t ext_tree_layoutupdate_size(struct pnfs_block_layout *bl, size_t count)
  {
-       return sizeof(__be32) /* number of entries */ +
-               PNFS_BLOCK_EXTENT_SIZE * count;
+       if (bl->bl_scsi_layout)
+               return sizeof(__be32) + PNFS_SCSI_RANGE_SIZE * count;
+       else
+               return sizeof(__be32) + PNFS_BLOCK_EXTENT_SIZE * count;
  }
  
  static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
  
                for (i = 0; i < nr_pages; i++)
                        put_page(arg->layoutupdate_pages[i]);
 +              vfree(arg->start_p);
                kfree(arg->layoutupdate_pages);
        } else {
                put_page(arg->layoutupdate_page);
        }
  }
  
+ static __be32 *encode_block_extent(struct pnfs_block_extent *be, __be32 *p)
+ {
+       p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
+                       NFS4_DEVICEID4_SIZE);
+       p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
+       p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
+       p = xdr_encode_hyper(p, 0LL);
+       *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
+       return p;
+ }
+ static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
+ {
+       p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
+       return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
+ }
  static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
                size_t buffer_size, size_t *count)
  {
                        continue;
  
                (*count)++;
-               if (ext_tree_layoutupdate_size(*count) > buffer_size) {
+               if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
                        /* keep counting.. */
                        ret = -ENOSPC;
                        continue;
                }
  
-               p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
-                               NFS4_DEVICEID4_SIZE);
-               p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
-               p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
-               p = xdr_encode_hyper(p, 0LL);
-               *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
+               if (bl->bl_scsi_layout)
+                       p = encode_scsi_range(be, p);
+               else
+                       p = encode_block_extent(be, p);
                be->be_tag = EXTENT_COMMITTING;
        }
        spin_unlock(&bl->bl_ext_lock);
@@@ -537,7 -552,7 +553,7 @@@ retry
        if (unlikely(ret)) {
                ext_tree_free_commitdata(arg, buffer_size);
  
-               buffer_size = ext_tree_layoutupdate_size(count);
+               buffer_size = ext_tree_layoutupdate_size(bl, count);
                count = 0;
  
                arg->layoutupdate_pages =
        }
  
        *start_p = cpu_to_be32(count);
-       arg->layoutupdate_len = ext_tree_layoutupdate_size(count);
+       arg->layoutupdate_len = ext_tree_layoutupdate_size(bl, count);
  
        if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
                void *p = start_p, *end = p + arg->layoutupdate_len;
 +              struct page *page = NULL;
                int i = 0;
  
 -              for ( ; p < end; p += PAGE_SIZE)
 -                      arg->layoutupdate_pages[i++] = vmalloc_to_page(p);
 +              arg->start_p = start_p;
 +              for ( ; p < end; p += PAGE_SIZE) {
 +                      page = vmalloc_to_page(p);
 +                      arg->layoutupdate_pages[i++] = page;
 +                      get_page(page);
 +              }
        }
  
        dprintk("%s found %zu ranges\n", __func__, count);
diff --combined fs/xfs/xfs_export.c
@@@ -152,7 -152,7 +152,7 @@@ xfs_nfs_get_inode
                return ERR_PTR(error);
        }
  
 -      if (ip->i_d.di_gen != generation) {
 +      if (VFS_I(ip)->i_generation != generation) {
                IRELE(ip);
                return ERR_PTR(-ESTALE);
        }
@@@ -246,7 -246,7 +246,7 @@@ const struct export_operations xfs_expo
        .fh_to_parent           = xfs_fs_fh_to_parent,
        .get_parent             = xfs_fs_get_parent,
        .commit_metadata        = xfs_fs_nfs_commit_metadata,
- #ifdef CONFIG_NFSD_PNFS
+ #ifdef CONFIG_NFSD_BLOCKLAYOUT
        .get_uuid               = xfs_fs_get_uuid,
        .map_blocks             = xfs_fs_map_blocks,
        .commit_blocks          = xfs_fs_commit_blocks,