NFS: Ensure that rpc_run_task() errors are propagated back to the caller
Trond Myklebust [Mon, 14 Apr 2008 18:54:53 +0000 (14:54 -0400)]
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

fs/nfs/direct.c
fs/nfs/read.c
fs/nfs/write.c

index abf8e02..4757a2b 100644 (file)
@@ -347,8 +347,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
                NFS_PROTO(inode)->read_setup(data, &msg);
 
                task = rpc_run_task(&task_setup_data);
-               if (!IS_ERR(task))
-                       rpc_put_task(task);
+               if (IS_ERR(task))
+                       break;
+               rpc_put_task(task);
 
                dprintk("NFS: %5u initiated direct read call "
                        "(req %s/%Ld, %zu bytes @ offset %Lu)\n",
@@ -763,8 +764,9 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
                NFS_PROTO(inode)->write_setup(data, &msg);
 
                task = rpc_run_task(&task_setup_data);
-               if (!IS_ERR(task))
-                       rpc_put_task(task);
+               if (IS_ERR(task))
+                       break;
+               rpc_put_task(task);
 
                dprintk("NFS: %5u initiated direct write call "
                        "(req %s/%Ld, %zu bytes @ offset %Lu)\n",
index 6f9208a..16f57e0 100644 (file)
@@ -153,7 +153,7 @@ static void nfs_readpage_release(struct nfs_page *req)
 /*
  * Set up the NFS read request struct
  */
-static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
+static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
                const struct rpc_call_ops *call_ops,
                unsigned int count, unsigned int offset)
 {
@@ -202,8 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
                        (unsigned long long)data->args.offset);
 
        task = rpc_run_task(&task_setup_data);
-       if (!IS_ERR(task))
-               rpc_put_task(task);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       rpc_put_task(task);
+       return 0;
 }
 
 static void
@@ -240,6 +242,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
        size_t rsize = NFS_SERVER(inode)->rsize, nbytes;
        unsigned int offset;
        int requests = 0;
+       int ret = 0;
        LIST_HEAD(list);
 
        nfs_list_remove_request(req);
@@ -261,6 +264,8 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
        offset = 0;
        nbytes = count;
        do {
+               int ret2;
+
                data = list_entry(list.next, struct nfs_read_data, pages);
                list_del_init(&data->pages);
 
@@ -268,13 +273,15 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
 
                if (nbytes < rsize)
                        rsize = nbytes;
-               nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
+               ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
                                  rsize, offset);
+               if (ret == 0)
+                       ret = ret2;
                offset += rsize;
                nbytes -= rsize;
        } while (nbytes != 0);
 
-       return 0;
+       return ret;
 
 out_bad:
        while (!list_empty(&list)) {
@@ -292,6 +299,7 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_read_data    *data;
+       int ret = -ENOMEM;
 
        data = nfs_readdata_alloc(npages);
        if (!data)
@@ -307,11 +315,10 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned
        }
        req = nfs_list_entry(data->pages.next);
 
-       nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0);
-       return 0;
+       return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0);
 out_bad:
        nfs_async_read_error(head);
-       return -ENOMEM;
+       return ret;
 }
 
 /*
index 31681bb..1ade11d 100644 (file)
@@ -778,7 +778,7 @@ static int flush_task_priority(int how)
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static void nfs_write_rpcsetup(struct nfs_page *req,
+static int nfs_write_rpcsetup(struct nfs_page *req,
                struct nfs_write_data *data,
                const struct rpc_call_ops *call_ops,
                unsigned int count, unsigned int offset,
@@ -841,8 +841,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
                (unsigned long long)data->args.offset);
 
        task = rpc_run_task(&task_setup_data);
-       if (!IS_ERR(task))
-               rpc_put_task(task);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       rpc_put_task(task);
+       return 0;
 }
 
 /* If a nfs_flush_* function fails, it should remove reqs from @head and
@@ -868,6 +870,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
        size_t wsize = NFS_SERVER(inode)->wsize, nbytes;
        unsigned int offset;
        int requests = 0;
+       int ret = 0;
        LIST_HEAD(list);
 
        nfs_list_remove_request(req);
@@ -889,6 +892,8 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
        offset = 0;
        nbytes = count;
        do {
+               int ret2;
+
                data = list_entry(list.next, struct nfs_write_data, pages);
                list_del_init(&data->pages);
 
@@ -896,13 +901,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
 
                if (nbytes < wsize)
                        wsize = nbytes;
-               nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
+               ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
                                   wsize, offset, how);
+               if (ret == 0)
+                       ret = ret2;
                offset += wsize;
                nbytes -= wsize;
        } while (nbytes != 0);
 
-       return 0;
+       return ret;
 
 out_bad:
        while (!list_empty(&list)) {
@@ -943,9 +950,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
        req = nfs_list_entry(data->pages.next);
 
        /* Set up the argument struct */
-       nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how);
-
-       return 0;
+       return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how);
  out_bad:
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);
@@ -1183,7 +1188,7 @@ void nfs_commitdata_release(void *data)
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static void nfs_commit_rpcsetup(struct list_head *head,
+static int nfs_commit_rpcsetup(struct list_head *head,
                struct nfs_write_data *data,
                int how)
 {
@@ -1232,8 +1237,10 @@ static void nfs_commit_rpcsetup(struct list_head *head,
        dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
 
        task = rpc_run_task(&task_setup_data);
-       if (!IS_ERR(task))
-               rpc_put_task(task);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       rpc_put_task(task);
+       return 0;
 }
 
 /*
@@ -1251,9 +1258,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
                goto out_bad;
 
        /* Set up the argument struct */
-       nfs_commit_rpcsetup(head, data, how);
-
-       return 0;
+       return nfs_commit_rpcsetup(head, data, how);
  out_bad:
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);