NFS: Don't accept more reads/writes if the open context recovery failed
Trond Myklebust [Mon, 18 Mar 2013 23:45:14 +0000 (19:45 -0400)]
If the state recovery failed, we want to ensure that the application
doesn't try to use the same file descriptor for more reads or writes.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

fs/nfs/nfs4filelayout.c
fs/nfs/nfs4state.c
fs/nfs/pagelist.c
fs/nfs/read.c
fs/nfs/write.c
include/linux/nfs_fs.h

index 1ee5737..4ba32e2 100644 (file)
@@ -305,6 +305,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
 {
        struct nfs_read_data *rdata = data;
 
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) {
+               rpc_exit(task, -EIO);
+               return;
+       }
        if (filelayout_reset_to_mds(rdata->header->lseg)) {
                dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
                filelayout_reset_read(rdata);
@@ -407,6 +411,10 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
 {
        struct nfs_write_data *wdata = data;
 
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) {
+               rpc_exit(task, -EIO);
+               return;
+       }
        if (filelayout_reset_to_mds(wdata->header->lseg)) {
                dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
                filelayout_reset_write(wdata);
index fec1c5b..8db102c 100644 (file)
@@ -1328,9 +1328,25 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
                nfs4_schedule_state_manager(clp);
 }
 
+static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
+{
+       struct inode *inode = state->inode;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_open_context *ctx;
+
+       spin_lock(&inode->i_lock);
+       list_for_each_entry(ctx, &nfsi->open_files, list) {
+               if (ctx->state != state)
+                       continue;
+               set_bit(NFS_CONTEXT_BAD, &ctx->flags);
+       }
+       spin_unlock(&inode->i_lock);
+}
+
 static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
 {
        set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
+       nfs4_state_mark_open_context_bad(state);
 }
 
 
index e56e846..7f09330 100644 (file)
@@ -104,6 +104,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
        struct nfs_page         *req;
        struct nfs_lock_context *l_ctx;
 
+       if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))
+               return ERR_PTR(-EBADF);
        /* try to allocate the request struct */
        req = nfs_page_alloc();
        if (req == NULL)
index a5e5d98..70a26c6 100644 (file)
@@ -514,6 +514,8 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_read_data *data = calldata;
        NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               rpc_exit(task, -EIO);
 }
 
 static const struct rpc_call_ops nfs_read_common_ops = {
index c483cc5..a2c7c28 100644 (file)
@@ -1251,6 +1251,8 @@ void nfs_write_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_write_data *data = calldata;
        NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               rpc_exit(task, -EIO);
 }
 
 void nfs_commit_prepare(struct rpc_task *task, void *calldata)
index 1cc2568..f6b1956 100644 (file)
@@ -77,6 +77,7 @@ struct nfs_open_context {
        unsigned long flags;
 #define NFS_CONTEXT_ERROR_WRITE                (0)
 #define NFS_CONTEXT_RESEND_WRITES      (1)
+#define NFS_CONTEXT_BAD                        (2)
        int error;
 
        struct list_head list;