]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blobdiff - fs/nfs/pnfs.c
Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[mirror_ubuntu-eoan-kernel.git] / fs / nfs / pnfs.c
index e550e8836c3759acb041e035078387a869e1f2c8..8e672a2b2d693193e8ca7252d70c73578d739e0f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
+#include <linux/module.h>
 #include "internal.h"
 #include "pnfs.h"
 #include "iostat.h"
@@ -1168,23 +1169,17 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
 /*
  * Called by non rpc-based layout drivers
  */
-int
-pnfs_ld_write_done(struct nfs_write_data *data)
+void pnfs_ld_write_done(struct nfs_write_data *data)
 {
-       int status;
-
-       if (!data->pnfs_error) {
+       if (likely(!data->pnfs_error)) {
                pnfs_set_layoutcommit(data);
                data->mds_ops->rpc_call_done(&data->task, data);
-               data->mds_ops->rpc_release(data);
-               return 0;
+       } else {
+               put_lseg(data->lseg);
+               data->lseg = NULL;
+               dprintk("pnfs write error = %d\n", data->pnfs_error);
        }
-
-       dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
-               data->pnfs_error);
-       status = nfs_initiate_write(data, NFS_CLIENT(data->inode),
-                                   data->mds_ops, NFS_FILE_SYNC);
-       return status ? : -EAGAIN;
+       data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 
@@ -1265,26 +1260,36 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
 
+static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
+{
+       struct nfs_pageio_descriptor pgio;
+
+       put_lseg(data->lseg);
+       data->lseg = NULL;
+       dprintk("pnfs write error = %d\n", data->pnfs_error);
+
+       nfs_pageio_init_read_mds(&pgio, data->inode);
+
+       while (!list_empty(&data->pages)) {
+               struct nfs_page *req = nfs_list_entry(data->pages.next);
+
+               nfs_list_remove_request(req);
+               nfs_pageio_add_request(&pgio, req);
+       }
+       nfs_pageio_complete(&pgio);
+}
+
 /*
  * Called by non rpc-based layout drivers
  */
-int
-pnfs_ld_read_done(struct nfs_read_data *data)
+void pnfs_ld_read_done(struct nfs_read_data *data)
 {
-       int status;
-
-       if (!data->pnfs_error) {
+       if (likely(!data->pnfs_error)) {
                __nfs4_read_done_cb(data);
                data->mds_ops->rpc_call_done(&data->task, data);
-               data->mds_ops->rpc_release(data);
-               return 0;
-       }
-
-       dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
-               data->pnfs_error);
-       status = nfs_initiate_read(data, NFS_CLIENT(data->inode),
-                                  data->mds_ops);
-       return status ? : -EAGAIN;
+       } else
+               pnfs_ld_handle_read_error(data);
+       data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
 
@@ -1381,6 +1386,18 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
        }
 }
 
+void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
+{
+       if (lseg->pls_range.iomode == IOMODE_RW) {
+               dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+       } else {
+               dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+       }
+}
+EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
+
 void
 pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 {
@@ -1443,17 +1460,31 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (!data) {
-               mark_inode_dirty_sync(inode);
                status = -ENOMEM;
                goto out;
        }
 
+       if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+               goto out_free;
+
+       if (test_and_set_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags)) {
+               if (!sync) {
+                       status = -EAGAIN;
+                       goto out_free;
+               }
+               status = wait_on_bit_lock(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING,
+                                       nfs_wait_bit_killable, TASK_KILLABLE);
+               if (status)
+                       goto out_free;
+       }
+
        INIT_LIST_HEAD(&data->lseg_list);
        spin_lock(&inode->i_lock);
        if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
+               clear_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags);
                spin_unlock(&inode->i_lock);
-               kfree(data);
-               goto out;
+               wake_up_bit(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING);
+               goto out_free;
        }
 
        pnfs_list_write_lseg(inode, &data->lseg_list);
@@ -1475,6 +1506,11 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 
        status = nfs4_proc_layoutcommit(data, sync);
 out:
+       if (status)
+               mark_inode_dirty_sync(inode);
        dprintk("<-- %s status %d\n", __func__, status);
        return status;
+out_free:
+       kfree(data);
+       goto out;
 }