Commit e4648aa4 authored by Olga Kornievskaia's avatar Olga Kornievskaia Committed by Anna Schumaker
Browse files

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: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 6b8d84e2
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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 {
+7 −2
Original line number Diff line number Diff line
@@ -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)
+16 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -192,6 +192,8 @@ struct nfs4_copy_state {
	uint64_t		count;
	struct nfs_writeverf	verf;
	int			error;
	int			flags;
	struct nfs4_state	*parent_state;
};

/*