]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
NFS: Fix up NFS I/O subrequest creation
authorTrond Myklebust <trondmy@gmail.com>
Sun, 7 Apr 2019 17:59:06 +0000 (13:59 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Thu, 25 Apr 2019 18:18:14 +0000 (14:18 -0400)
We require all NFS I/O subrequests to duplicate the lock context as well
as the open context.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/pagelist.c

index e9f39fa5964b0773cd5da3e39363710ca510d6f5..66a5c5d4a77778fcdc4106eb98d34648fdda280a 100644 (file)
@@ -295,25 +295,13 @@ nfs_page_group_destroy(struct kref *kref)
                nfs_release_request(head);
 }
 
-/**
- * nfs_create_request - Create an NFS read/write request.
- * @ctx: open context to use
- * @page: page to write
- * @last: last nfs request created for this page group or NULL if head
- * @offset: starting offset within the page for the write
- * @count: number of bytes to read/write
- *
- * The page must be locked by the caller. This makes sure we never
- * create two different requests for the same page.
- * User should ensure it is safe to sleep in this function.
- */
-struct nfs_page *
-nfs_create_request(struct nfs_open_context *ctx, struct page *page,
-                  struct nfs_page *last, unsigned int offset,
-                  unsigned int count)
+static struct nfs_page *
+__nfs_create_request(struct nfs_lock_context *l_ctx, struct page *page,
+                  struct nfs_page *last, unsigned int pgbase,
+                  unsigned int offset, unsigned int count)
 {
        struct nfs_page         *req;
-       struct nfs_lock_context *l_ctx;
+       struct nfs_open_context *ctx = l_ctx->open_context;
 
        if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))
                return ERR_PTR(-EBADF);
@@ -322,13 +310,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
        if (req == NULL)
                return ERR_PTR(-ENOMEM);
 
-       /* get lock context early so we can deal with alloc failures */
-       l_ctx = nfs_get_lock_context(ctx);
-       if (IS_ERR(l_ctx)) {
-               nfs_page_free(req);
-               return ERR_CAST(l_ctx);
-       }
        req->wb_lock_context = l_ctx;
+       refcount_inc(&l_ctx->count);
        atomic_inc(&l_ctx->io_count);
 
        /* Initialize the request struct. Initially, we assume a
@@ -340,7 +323,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
                get_page(page);
        }
        req->wb_offset  = offset;
-       req->wb_pgbase  = offset;
+       req->wb_pgbase  = pgbase;
        req->wb_bytes   = count;
        req->wb_context = get_nfs_open_context(ctx);
        kref_init(&req->wb_kref);
@@ -348,6 +331,49 @@ nfs_create_request(struct nfs_open_context *ctx, struct page *page,
        return req;
 }
 
+/**
+ * nfs_create_request - Create an NFS read/write request.
+ * @ctx: open context to use
+ * @page: page to write
+ * @last: last nfs request created for this page group or NULL if head
+ * @offset: starting offset within the page for the write
+ * @count: number of bytes to read/write
+ *
+ * The page must be locked by the caller. This makes sure we never
+ * create two different requests for the same page.
+ * User should ensure it is safe to sleep in this function.
+ */
+struct nfs_page *
+nfs_create_request(struct nfs_open_context *ctx, struct page *page,
+                  struct nfs_page *last, unsigned int offset,
+                  unsigned int count)
+{
+       struct nfs_lock_context *l_ctx = nfs_get_lock_context(ctx);
+       struct nfs_page *ret;
+
+       if (IS_ERR(l_ctx))
+               return ERR_CAST(l_ctx);
+       ret = __nfs_create_request(l_ctx, page, last, offset, offset, count);
+       nfs_put_lock_context(l_ctx);
+       return ret;
+}
+
+static struct nfs_page *
+nfs_create_subreq(struct nfs_page *req, struct nfs_page *last,
+                 unsigned int pgbase, unsigned int offset,
+                 unsigned int count)
+{
+       struct nfs_page *ret;
+
+       ret = __nfs_create_request(req->wb_lock_context, req->wb_page, last,
+                       pgbase, offset, count);
+       if (!IS_ERR(ret)) {
+               nfs_lock_request(ret);
+               ret->wb_index = req->wb_index;
+       }
+       return ret;
+}
+
 /**
  * nfs_unlock_request - Unlock request and wake up sleepers.
  * @req: pointer to request
@@ -1049,14 +1075,10 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                pgbase += subreq->wb_bytes;
 
                if (bytes_left) {
-                       subreq = nfs_create_request(req->wb_context,
-                                       req->wb_page,
-                                       subreq, pgbase, bytes_left);
+                       subreq = nfs_create_subreq(req, subreq, pgbase,
+                                       offset, bytes_left);
                        if (IS_ERR(subreq))
                                goto err_ptr;
-                       nfs_lock_request(subreq);
-                       subreq->wb_offset  = offset;
-                       subreq->wb_index = req->wb_index;
                }
        } while (bytes_left > 0);
 
@@ -1158,19 +1180,14 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                             lastreq = lastreq->wb_this_page)
                                ;
 
-                       dupreq = nfs_create_request(req->wb_context,
-                                       req->wb_page, lastreq, pgbase, bytes);
+                       dupreq = nfs_create_subreq(req, lastreq,
+                                       pgbase, offset, bytes);
 
+                       nfs_page_group_unlock(req);
                        if (IS_ERR(dupreq)) {
-                               nfs_page_group_unlock(req);
                                desc->pg_error = PTR_ERR(dupreq);
                                goto out_failed;
                        }
-
-                       nfs_lock_request(dupreq);
-                       nfs_page_group_unlock(req);
-                       dupreq->wb_offset = offset;
-                       dupreq->wb_index = req->wb_index;
                } else
                        dupreq = req;