NFS recover from destination server reboot for copies

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>
This commit is contained in:
Olga Kornievskaia 2018-08-13 15:33:01 -04:00 committed by Anna Schumaker
parent 6b8d84e2f1
commit e4648aa4f9
5 changed files with 41 additions and 5 deletions

View 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)

View 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 {

View 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)

View 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;

View 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;
};
/*