NFS recover from destination server reboot for copies
authorOlga Kornievskaia <kolga@netapp.com>
Mon, 13 Aug 2018 19:33:01 +0000 (15:33 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Mon, 13 Aug 2018 21:04:23 +0000 (17:04 -0400)
Mark the destination state to indicate a server-side copy is
happening. On detecting a reboot and recovering open state check
if any state is engaged in a server-side copy, if so, find the
copy and mark it and then signal the waiting thread. Upon wakeup,
if copy was marked then propage EAGAIN to the nfsd_copy_file_range
and restart the copy from scratch.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs42proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4file.c
fs/nfs/nfs4state.c
include/linux/nfs_fs.h

index d158526d104442b05f7462e00b448bf71413dc5e..ac5b784a1de05c864958f1a16646fac034b402d5 100644 (file)
@@ -140,6 +140,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
        struct nfs4_copy_state *copy;
        int status = NFS4_OK;
        bool found_pending = false;
+       struct nfs_open_context *ctx = nfs_file_open_context(dst);
 
        spin_lock(&server->nfs_client->cl_lock);
        list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
@@ -163,6 +164,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
        }
        memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
        init_completion(&copy->completion);
+       copy->parent_state = ctx->state;
 
        list_add_tail(&copy->copies, &server->ss_copies);
        spin_unlock(&server->nfs_client->cl_lock);
@@ -172,15 +174,20 @@ static int handle_async_copy(struct nfs42_copy_res *res,
        list_del_init(&copy->copies);
        spin_unlock(&server->nfs_client->cl_lock);
        if (status == -ERESTARTSYS) {
-               nfs42_do_offload_cancel_async(dst, &copy->stateid);
-               kfree(copy);
-               return status;
+               goto out_cancel;
+       } else if (copy->flags) {
+               status = -EAGAIN;
+               goto out_cancel;
        }
 out:
        res->write_res.count = copy->count;
        memcpy(&res->write_res.verifier, &copy->verf, sizeof(copy->verf));
        status = -copy->error;
 
+       kfree(copy);
+       return status;
+out_cancel:
+       nfs42_do_offload_cancel_async(dst, &copy->stateid);
        kfree(copy);
        return status;
 }
@@ -254,6 +261,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
                if (!res->commit_res.verf)
                        return -ENOMEM;
        }
+       set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
+               &dst_lock->open_context->state->flags);
+
        status = nfs4_call_sync(server->client, server, &msg,
                                &args->seq_args, &res->seq_res, 0);
        if (status == -ENOTSUPP)
index e87d414c40d0aa816eac81e1871fcd107f56b18d..542b2fce04476cd9c9509b52ec2bd526776a40ea 100644 (file)
@@ -163,6 +163,9 @@ enum {
        NFS_STATE_RECOVERY_FAILED,      /* OPEN stateid state recovery failed */
        NFS_STATE_MAY_NOTIFY_LOCK,      /* server may CB_NOTIFY_LOCK */
        NFS_STATE_CHANGE_WAIT,          /* A state changing operation is outstanding */
+#ifdef CONFIG_NFS_V4_2
+       NFS_CLNT_DST_SSC_COPY_STATE,    /* dst server open state on client*/
+#endif /* CONFIG_NFS_V4_2 */
 };
 
 struct nfs4_state {
index 6c03d6b570b2d0d9f33ded5c3e2082fc772e9faf..4288a6ecaf756361bf134af1b790cb15fd9c02d6 100644 (file)
@@ -133,10 +133,15 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
                                    struct file *file_out, loff_t pos_out,
                                    size_t count, unsigned int flags)
 {
+       ssize_t ret;
+
        if (file_inode(file_in) == file_inode(file_out))
                return -EINVAL;
-
-       return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+retry:
+       ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+       if (ret == -EAGAIN)
+               goto retry;
+       return ret;
 }
 
 static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
index f1b27e895a94ea75466d6df3885d741540b57c23..b6882e09d0f4b8c15641e1e61cc1c713caf94938 100644 (file)
@@ -1589,6 +1589,22 @@ restart:
                                }
                                clear_bit(NFS_STATE_RECLAIM_NOGRACE,
                                        &state->flags);
+#ifdef CONFIG_NFS_V4_2
+                               if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) {
+                                       struct nfs4_copy_state *copy;
+
+                                       spin_lock(&sp->so_server->nfs_client->cl_lock);
+                                       list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
+                                               if (memcmp(&state->stateid.other, &copy->parent_state->stateid.other, NFS4_STATEID_SIZE))
+                                                       continue;
+                                               copy->flags = 1;
+                                               complete(&copy->completion);
+                                               printk("AGLO: server rebooted waking up the copy\n");
+                                               break;
+                                       }
+                                       spin_unlock(&sp->so_server->nfs_client->cl_lock);
+                               }
+#endif /* CONFIG_NFS_V4_2 */
                                nfs4_put_open_state(state);
                                spin_lock(&sp->so_lock);
                                goto restart;
index 645ad8e342f6d501812cf2cff64fd110e2d5c9a4..a0831e9d19c9df9f26c6d0777e198c32241550b4 100644 (file)
@@ -192,6 +192,8 @@ struct nfs4_copy_state {
        uint64_t                count;
        struct nfs_writeverf    verf;
        int                     error;
+       int                     flags;
+       struct nfs4_state       *parent_state;
 };
 
 /*