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:
parent
6b8d84e2f1
commit
e4648aa4f9
@ -140,6 +140,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
|||||||
struct nfs4_copy_state *copy;
|
struct nfs4_copy_state *copy;
|
||||||
int status = NFS4_OK;
|
int status = NFS4_OK;
|
||||||
bool found_pending = false;
|
bool found_pending = false;
|
||||||
|
struct nfs_open_context *ctx = nfs_file_open_context(dst);
|
||||||
|
|
||||||
spin_lock(&server->nfs_client->cl_lock);
|
spin_lock(&server->nfs_client->cl_lock);
|
||||||
list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
|
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(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
||||||
init_completion(©->completion);
|
init_completion(©->completion);
|
||||||
|
copy->parent_state = ctx->state;
|
||||||
|
|
||||||
list_add_tail(©->copies, &server->ss_copies);
|
list_add_tail(©->copies, &server->ss_copies);
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&server->nfs_client->cl_lock);
|
||||||
@ -172,15 +174,20 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
|||||||
list_del_init(©->copies);
|
list_del_init(©->copies);
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&server->nfs_client->cl_lock);
|
||||||
if (status == -ERESTARTSYS) {
|
if (status == -ERESTARTSYS) {
|
||||||
nfs42_do_offload_cancel_async(dst, ©->stateid);
|
goto out_cancel;
|
||||||
kfree(copy);
|
} else if (copy->flags) {
|
||||||
return status;
|
status = -EAGAIN;
|
||||||
|
goto out_cancel;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
res->write_res.count = copy->count;
|
res->write_res.count = copy->count;
|
||||||
memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
|
memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
|
||||||
status = -copy->error;
|
status = -copy->error;
|
||||||
|
|
||||||
|
kfree(copy);
|
||||||
|
return status;
|
||||||
|
out_cancel:
|
||||||
|
nfs42_do_offload_cancel_async(dst, ©->stateid);
|
||||||
kfree(copy);
|
kfree(copy);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -254,6 +261,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||||||
if (!res->commit_res.verf)
|
if (!res->commit_res.verf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
||||||
|
&dst_lock->open_context->state->flags);
|
||||||
|
|
||||||
status = nfs4_call_sync(server->client, server, &msg,
|
status = nfs4_call_sync(server->client, server, &msg,
|
||||||
&args->seq_args, &res->seq_res, 0);
|
&args->seq_args, &res->seq_res, 0);
|
||||||
if (status == -ENOTSUPP)
|
if (status == -ENOTSUPP)
|
||||||
|
@ -163,6 +163,9 @@ enum {
|
|||||||
NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
|
NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
|
||||||
NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */
|
NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */
|
||||||
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
|
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 {
|
struct nfs4_state {
|
||||||
|
@ -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,
|
struct file *file_out, loff_t pos_out,
|
||||||
size_t count, unsigned int flags)
|
size_t count, unsigned int flags)
|
||||||
{
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
if (file_inode(file_in) == file_inode(file_out))
|
if (file_inode(file_in) == file_inode(file_out))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
retry:
|
||||||
return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
|
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)
|
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
|
||||||
|
@ -1589,6 +1589,22 @@ restart:
|
|||||||
}
|
}
|
||||||
clear_bit(NFS_STATE_RECLAIM_NOGRACE,
|
clear_bit(NFS_STATE_RECLAIM_NOGRACE,
|
||||||
&state->flags);
|
&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, ©->parent_state->stateid.other, NFS4_STATEID_SIZE))
|
||||||
|
continue;
|
||||||
|
copy->flags = 1;
|
||||||
|
complete(©->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);
|
nfs4_put_open_state(state);
|
||||||
spin_lock(&sp->so_lock);
|
spin_lock(&sp->so_lock);
|
||||||
goto restart;
|
goto restart;
|
||||||
|
@ -192,6 +192,8 @@ struct nfs4_copy_state {
|
|||||||
uint64_t count;
|
uint64_t count;
|
||||||
struct nfs_writeverf verf;
|
struct nfs_writeverf verf;
|
||||||
int error;
|
int error;
|
||||||
|
int flags;
|
||||||
|
struct nfs4_state *parent_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user