NFS client bugfixes for Linux 4.3
Highlights include: Stable patches: - fix v4.2 SEEK on files over 2 gigs - Fix a layout segment reference leak when pNFS I/O falls back to inband I/O. - Fix recovery of recalled read delegations Bugfixes: - Fix a case where NFSv4 fails to send CLOSE after a server reboot - Fix sunrpc to wait for connections to complete before retrying - Fix sunrpc races between transport connect/disconnect and shutdown - Fix an infinite loop when layoutget fail with BAD_STATEID - nfs/filelayout: Fix NULL reference caused by double freeing of fh_array - Fix a bogus WARN_ON_ONCE() in O_DIRECT when layout commit_through_mds is set - Fix layoutreturn/close ordering issues. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWBWKdAAoJEGcL54qWCgDy2rUP/iIWUQSpUPfKKw7xquQUQe4j ci4nFxpJ/zhKj1u7x3wrkxZAXcEooYo+ZJ7ayzROKcfQL/sUSWGbSLdr3mqrQynv b0SDmnJK9V+CdBQrA+Jp5UGQxcumpMxsAfqVznT0qkf/wDp44DCVgDz5Aj8cRbWU 6xPfMgVLEnXiId9IgKqg3sJ2NmvMZXuI9sHM6hp6OzRmQDjTcx+LgRz7tnQHgaEk zGz8R6eDm3OA0wfApqZwJ6JY793HsDdy30W9L0Yi2PVGXfzwoEB8AqgLVwSDIY1B 5hG5zn3tg9PSz9vhJ7M2h4AgFHdB3w3XGdJUafwqZEeqEIagw1iFCWlMyo/lE2dG G7oob9Jiiwxjc3RDWn2wGaafymrrWZwl2nYzC4O3UvJ3hVJ0mEl1iJagK1m8LzfN fmnP7tTyPuoOXkzDogZ0YI3FrngO6430PoR2hUPkS1yce/a+IV0HQEmXbSDSwN80 1d9zyC9TnPj6rFjZeaGxGK17BpkC0oIQCPq4OSJB4396wzAwMqoJjJVVWWeAK4UC PxzoXqAAaBFguSsDbuBMcXgiuUw/7DIZ/pdzsWSiCFgocgF5ZdJdieCNtGk0nbLM 37R7HCauF93JDrkpUMKPnLXScb2IbEh31pFtKzptJYKwMxEiScXXiP3NE9hfX65i 2zLkl2aBvd154RvVKNbp =GdeV -----END PGP SIGNATURE----- Merge tag 'nfs-for-4.3-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: "Highlights include: Stable patches: - fix v4.2 SEEK on files over 2 gigs - Fix a layout segment reference leak when pNFS I/O falls back to inband I/O. - Fix recovery of recalled read delegations Bugfixes: - Fix a case where NFSv4 fails to send CLOSE after a server reboot - Fix sunrpc to wait for connections to complete before retrying - Fix sunrpc races between transport connect/disconnect and shutdown - Fix an infinite loop when layoutget fail with BAD_STATEID - nfs/filelayout: Fix NULL reference caused by double freeing of fh_array - Fix a bogus WARN_ON_ONCE() in O_DIRECT when layout commit_through_mds is set - Fix layoutreturn/close ordering issues" * tag 'nfs-for-4.3-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS41: make close wait for layoutreturn NFS: Skip checking ds_cinfo.buckets when lseg's commit_through_mds is set NFSv4.x/pnfs: Don't try to recover stateids twice in layoutget NFSv4: Recovery of recalled read delegations is broken NFS: Fix an infinite loop when layoutget fail with BAD_STATEID NFS: Do cleanup before resetting pageio read/write to mds SUNRPC: xs_sock_mark_closed() does not need to trigger socket autoclose SUNRPC: Lock the transport layer on shutdown nfs/filelayout: Fix NULL reference caused by double freeing of fh_array SUNRPC: Ensure that we wait for connections to complete before retrying SUNRPC: drop null test before destroy functions nfs: fix v4.2 SEEK on files over 2 gigs SUNRPC: Fix races between socket connection and destroy code nfs: fix pg_test page count calculation Failing to send a CLOSE if file is opened WRONLY and server reboots on a 4.x mount
This commit is contained in:
commit
101688f534
|
@ -113,7 +113,8 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
|
|||
return status;
|
||||
}
|
||||
|
||||
static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
|
||||
static int nfs_delegation_claim_opens(struct inode *inode,
|
||||
const nfs4_stateid *stateid, fmode_t type)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_open_context *ctx;
|
||||
|
@ -140,7 +141,7 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s
|
|||
/* Block nfs4_proc_unlck */
|
||||
mutex_lock(&sp->so_delegreturn_mutex);
|
||||
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
|
||||
err = nfs4_open_delegation_recall(ctx, state, stateid);
|
||||
err = nfs4_open_delegation_recall(ctx, state, stateid, type);
|
||||
if (!err)
|
||||
err = nfs_delegation_claim_locks(ctx, state, stateid);
|
||||
if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
|
||||
|
@ -411,7 +412,8 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
|
|||
do {
|
||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||
break;
|
||||
err = nfs_delegation_claim_opens(inode, &delegation->stateid);
|
||||
err = nfs_delegation_claim_opens(inode, &delegation->stateid,
|
||||
delegation->type);
|
||||
if (!issync || err != -EAGAIN)
|
||||
break;
|
||||
/*
|
||||
|
|
|
@ -54,7 +54,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
|
|||
|
||||
/* NFSv4 delegation-related procedures */
|
||||
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
|
||||
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
|
||||
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
|
||||
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
|
||||
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
|
||||
|
||||
|
|
|
@ -166,8 +166,11 @@ nfs_direct_select_verf(struct nfs_direct_req *dreq,
|
|||
struct nfs_writeverf *verfp = &dreq->verf;
|
||||
|
||||
#ifdef CONFIG_NFS_V4_1
|
||||
if (ds_clp) {
|
||||
/* pNFS is in use, use the DS verf */
|
||||
/*
|
||||
* pNFS is in use, use the DS verf except commit_through_mds is set
|
||||
* for layout segment where nbuckets is zero.
|
||||
*/
|
||||
if (ds_clp && dreq->ds_cinfo.nbuckets > 0) {
|
||||
if (commit_idx >= 0 && commit_idx < dreq->ds_cinfo.nbuckets)
|
||||
verfp = &dreq->ds_cinfo.buckets[commit_idx].direct_verf;
|
||||
else
|
||||
|
|
|
@ -629,23 +629,18 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
|
|||
goto out;
|
||||
}
|
||||
|
||||
static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
|
||||
static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fl->num_fh; i++) {
|
||||
if (!fl->fh_array[i])
|
||||
break;
|
||||
kfree(fl->fh_array[i]);
|
||||
if (fl->fh_array) {
|
||||
for (i = 0; i < fl->num_fh; i++) {
|
||||
if (!fl->fh_array[i])
|
||||
break;
|
||||
kfree(fl->fh_array[i]);
|
||||
}
|
||||
kfree(fl->fh_array);
|
||||
}
|
||||
kfree(fl->fh_array);
|
||||
fl->fh_array = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
|
||||
{
|
||||
filelayout_free_fh_array(fl);
|
||||
kfree(fl);
|
||||
}
|
||||
|
||||
|
@ -716,21 +711,21 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
|
|||
/* Do we want to use a mempool here? */
|
||||
fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
|
||||
if (!fl->fh_array[i])
|
||||
goto out_err_free;
|
||||
goto out_err;
|
||||
|
||||
p = xdr_inline_decode(&stream, 4);
|
||||
if (unlikely(!p))
|
||||
goto out_err_free;
|
||||
goto out_err;
|
||||
fl->fh_array[i]->size = be32_to_cpup(p++);
|
||||
if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
|
||||
printk(KERN_ERR "NFS: Too big fh %d received %d\n",
|
||||
i, fl->fh_array[i]->size);
|
||||
goto out_err_free;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
|
||||
if (unlikely(!p))
|
||||
goto out_err_free;
|
||||
goto out_err;
|
||||
memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
|
||||
dprintk("DEBUG: %s: fh len %d\n", __func__,
|
||||
fl->fh_array[i]->size);
|
||||
|
@ -739,8 +734,6 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
|
|||
__free_page(scratch);
|
||||
return 0;
|
||||
|
||||
out_err_free:
|
||||
filelayout_free_fh_array(fl);
|
||||
out_err:
|
||||
__free_page(scratch);
|
||||
return -EIO;
|
||||
|
|
|
@ -175,10 +175,12 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
|
|||
{
|
||||
struct nfs_server *server = NFS_SERVER(file_inode(filep));
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
loff_t err;
|
||||
|
||||
do {
|
||||
err = _nfs42_proc_llseek(filep, offset, whence);
|
||||
if (err >= 0)
|
||||
break;
|
||||
if (err == -ENOTSUPP)
|
||||
return -EOPNOTSUPP;
|
||||
err = nfs4_handle_exception(server, err, &exception);
|
||||
|
|
|
@ -1127,6 +1127,21 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
|
||||
fmode_t fmode)
|
||||
{
|
||||
switch(fmode & (FMODE_READ|FMODE_WRITE)) {
|
||||
case FMODE_READ|FMODE_WRITE:
|
||||
return state->n_rdwr != 0;
|
||||
case FMODE_WRITE:
|
||||
return state->n_wronly != 0;
|
||||
case FMODE_READ:
|
||||
return state->n_rdonly != 0;
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -1571,17 +1586,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
|
|||
return opendata;
|
||||
}
|
||||
|
||||
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res)
|
||||
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
|
||||
fmode_t fmode)
|
||||
{
|
||||
struct nfs4_state *newstate;
|
||||
int ret;
|
||||
|
||||
if ((opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
|
||||
opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEG_CUR_FH) &&
|
||||
(opendata->o_arg.u.delegation_type & fmode) != fmode)
|
||||
/* This mode can't have been delegated, so we must have
|
||||
* a valid open_stateid to cover it - not need to reclaim.
|
||||
*/
|
||||
if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
|
||||
return 0;
|
||||
opendata->o_arg.open_flags = 0;
|
||||
opendata->o_arg.fmode = fmode;
|
||||
|
@ -1597,14 +1608,14 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
|
|||
newstate = nfs4_opendata_to_nfs4_state(opendata);
|
||||
if (IS_ERR(newstate))
|
||||
return PTR_ERR(newstate);
|
||||
if (newstate != opendata->state)
|
||||
ret = -ESTALE;
|
||||
nfs4_close_state(newstate, fmode);
|
||||
*res = newstate;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
|
||||
{
|
||||
struct nfs4_state *newstate;
|
||||
int ret;
|
||||
|
||||
/* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
|
||||
|
@ -1615,27 +1626,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|||
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||
clear_bit(NFS_OPEN_STATE, &state->flags);
|
||||
smp_rmb();
|
||||
if (state->n_rdwr != 0) {
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (newstate != state)
|
||||
return -ESTALE;
|
||||
}
|
||||
if (state->n_wronly != 0) {
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (newstate != state)
|
||||
return -ESTALE;
|
||||
}
|
||||
if (state->n_rdonly != 0) {
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (newstate != state)
|
||||
return -ESTALE;
|
||||
}
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = nfs4_open_recover_helper(opendata, FMODE_READ);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/*
|
||||
* We may have performed cached opens for all three recoveries.
|
||||
* Check if we need to update the current stateid.
|
||||
|
@ -1759,18 +1758,32 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
|
|||
return err;
|
||||
}
|
||||
|
||||
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
|
||||
int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
|
||||
struct nfs4_state *state, const nfs4_stateid *stateid,
|
||||
fmode_t type)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||
struct nfs4_opendata *opendata;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
opendata = nfs4_open_recoverdata_alloc(ctx, state,
|
||||
NFS4_OPEN_CLAIM_DELEG_CUR_FH);
|
||||
if (IS_ERR(opendata))
|
||||
return PTR_ERR(opendata);
|
||||
nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
|
||||
err = nfs4_open_recover(opendata, state);
|
||||
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||
switch (type & (FMODE_READ|FMODE_WRITE)) {
|
||||
case FMODE_READ|FMODE_WRITE:
|
||||
case FMODE_WRITE:
|
||||
err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
|
||||
if (err)
|
||||
break;
|
||||
err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
|
||||
if (err)
|
||||
break;
|
||||
case FMODE_READ:
|
||||
err = nfs4_open_recover_helper(opendata, FMODE_READ);
|
||||
}
|
||||
nfs4_opendata_put(opendata);
|
||||
return nfs4_handle_delegation_recall_error(server, state, stateid, err);
|
||||
}
|
||||
|
@ -2645,6 +2658,15 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool
|
||||
nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
|
||||
{
|
||||
if (inode == NULL || !nfs_have_layout(inode))
|
||||
return false;
|
||||
|
||||
return pnfs_wait_on_layoutreturn(inode, task);
|
||||
}
|
||||
|
||||
struct nfs4_closedata {
|
||||
struct inode *inode;
|
||||
struct nfs4_state *state;
|
||||
|
@ -2763,6 +2785,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||
goto out_no_action;
|
||||
}
|
||||
|
||||
if (nfs4_wait_on_layoutreturn(inode, task)) {
|
||||
nfs_release_seqid(calldata->arg.seqid);
|
||||
goto out_wait;
|
||||
}
|
||||
|
||||
if (calldata->arg.fmode == 0)
|
||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
|
||||
if (calldata->roc)
|
||||
|
@ -5308,6 +5335,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
|
|||
|
||||
d_data = (struct nfs4_delegreturndata *)data;
|
||||
|
||||
if (nfs4_wait_on_layoutreturn(d_data->inode, task))
|
||||
return;
|
||||
|
||||
if (d_data->roc)
|
||||
pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier);
|
||||
|
||||
|
@ -7800,39 +7830,46 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
|
|||
dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n",
|
||||
__func__, delay);
|
||||
rpc_delay(task, delay);
|
||||
task->tk_status = 0;
|
||||
rpc_restart_call_prepare(task);
|
||||
goto out; /* Do not call nfs4_async_handle_error() */
|
||||
/* Do not call nfs4_async_handle_error() */
|
||||
goto out_restart;
|
||||
}
|
||||
break;
|
||||
case -NFS4ERR_EXPIRED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
spin_lock(&inode->i_lock);
|
||||
lo = NFS_I(inode)->layout;
|
||||
if (!lo || list_empty(&lo->plh_segs)) {
|
||||
if (nfs4_stateid_match(&lgp->args.stateid,
|
||||
&lgp->args.ctx->state->stateid)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
/* If the open stateid was bad, then recover it. */
|
||||
state = lgp->args.ctx->state;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
lo = NFS_I(inode)->layout;
|
||||
if (lo && nfs4_stateid_match(&lgp->args.stateid,
|
||||
&lo->plh_stateid)) {
|
||||
LIST_HEAD(head);
|
||||
|
||||
/*
|
||||
* Mark the bad layout state as invalid, then retry
|
||||
* with the current stateid.
|
||||
*/
|
||||
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
|
||||
pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
|
||||
spin_unlock(&inode->i_lock);
|
||||
pnfs_free_lseg_list(&head);
|
||||
|
||||
task->tk_status = 0;
|
||||
rpc_restart_call_prepare(task);
|
||||
}
|
||||
} else
|
||||
spin_unlock(&inode->i_lock);
|
||||
goto out_restart;
|
||||
}
|
||||
if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
|
||||
rpc_restart_call_prepare(task);
|
||||
goto out_restart;
|
||||
out:
|
||||
dprintk("<-- %s\n", __func__);
|
||||
return;
|
||||
out_restart:
|
||||
task->tk_status = 0;
|
||||
rpc_restart_call_prepare(task);
|
||||
return;
|
||||
out_overflow:
|
||||
task->tk_status = -EOVERFLOW;
|
||||
goto out;
|
||||
|
|
|
@ -1481,7 +1481,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
|
|||
spin_unlock(&state->state_lock);
|
||||
}
|
||||
nfs4_put_open_state(state);
|
||||
clear_bit(NFS4CLNT_RECLAIM_NOGRACE,
|
||||
clear_bit(NFS_STATE_RECLAIM_NOGRACE,
|
||||
&state->flags);
|
||||
spin_lock(&sp->so_lock);
|
||||
goto restart;
|
||||
|
|
|
@ -508,7 +508,7 @@ size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
|
|||
* for it without upsetting the slab allocator.
|
||||
*/
|
||||
if (((mirror->pg_count + req->wb_bytes) >> PAGE_SHIFT) *
|
||||
sizeof(struct page) > PAGE_SIZE)
|
||||
sizeof(struct page *) > PAGE_SIZE)
|
||||
return 0;
|
||||
|
||||
return min(mirror->pg_bsize - mirror->pg_count, (size_t)req->wb_bytes);
|
||||
|
|
|
@ -1104,20 +1104,15 @@ bool pnfs_roc(struct inode *ino)
|
|||
mark_lseg_invalid(lseg, &tmp_list);
|
||||
found = true;
|
||||
}
|
||||
/* pnfs_prepare_layoutreturn() grabs lo ref and it will be put
|
||||
* in pnfs_roc_release(). We don't really send a layoutreturn but
|
||||
* still want others to view us like we are sending one!
|
||||
*
|
||||
* If pnfs_prepare_layoutreturn() fails, it means someone else is doing
|
||||
* LAYOUTRETURN, so we proceed like there are no layouts to return.
|
||||
*
|
||||
* ROC in three conditions:
|
||||
/* ROC in two conditions:
|
||||
* 1. there are ROC lsegs
|
||||
* 2. we don't send layoutreturn
|
||||
* 3. no others are sending layoutreturn
|
||||
*/
|
||||
if (found && !layoutreturn && pnfs_prepare_layoutreturn(lo))
|
||||
if (found && !layoutreturn) {
|
||||
/* lo ref dropped in pnfs_roc_release() */
|
||||
pnfs_get_layout_hdr(lo);
|
||||
roc = true;
|
||||
}
|
||||
|
||||
out_noroc:
|
||||
spin_unlock(&ino->i_lock);
|
||||
|
@ -1172,6 +1167,26 @@ void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier)
|
|||
spin_unlock(&ino->i_lock);
|
||||
}
|
||||
|
||||
bool pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(ino);
|
||||
struct pnfs_layout_hdr *lo;
|
||||
bool sleep = false;
|
||||
|
||||
/* we might not have grabbed lo reference. so need to check under
|
||||
* i_lock */
|
||||
spin_lock(&ino->i_lock);
|
||||
lo = nfsi->layout;
|
||||
if (lo && test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
|
||||
sleep = true;
|
||||
spin_unlock(&ino->i_lock);
|
||||
|
||||
if (sleep)
|
||||
rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
|
||||
|
||||
return sleep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two layout segments for sorting into layout cache.
|
||||
* We want to preferentially return RW over RO layouts, so ensure those
|
||||
|
|
|
@ -270,6 +270,7 @@ bool pnfs_roc(struct inode *ino);
|
|||
void pnfs_roc_release(struct inode *ino);
|
||||
void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
|
||||
void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier);
|
||||
bool pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task);
|
||||
void pnfs_set_layoutcommit(struct inode *, struct pnfs_layout_segment *, loff_t);
|
||||
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
|
||||
int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
|
||||
|
@ -639,6 +640,12 @@ pnfs_roc_get_barrier(struct inode *ino, u32 *barrier)
|
|||
{
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void set_pnfs_layoutdriver(struct nfs_server *s,
|
||||
const struct nfs_fh *mntfh, u32 id)
|
||||
{
|
||||
|
|
|
@ -72,6 +72,9 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
|
|||
{
|
||||
struct nfs_pgio_mirror *mirror;
|
||||
|
||||
if (pgio->pg_ops && pgio->pg_ops->pg_cleanup)
|
||||
pgio->pg_ops->pg_cleanup(pgio);
|
||||
|
||||
pgio->pg_ops = &nfs_pgio_rw_ops;
|
||||
|
||||
/* read path should never have more than one mirror */
|
||||
|
|
|
@ -1351,6 +1351,9 @@ void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
|
|||
{
|
||||
struct nfs_pgio_mirror *mirror;
|
||||
|
||||
if (pgio->pg_ops && pgio->pg_ops->pg_cleanup)
|
||||
pgio->pg_ops->pg_cleanup(pgio);
|
||||
|
||||
pgio->pg_ops = &nfs_pgio_rw_ops;
|
||||
|
||||
nfs_pageio_stop_mirroring(pgio);
|
||||
|
|
|
@ -42,6 +42,7 @@ struct sock_xprt {
|
|||
/*
|
||||
* Connection of transports
|
||||
*/
|
||||
unsigned long sock_state;
|
||||
struct delayed_work connect_worker;
|
||||
struct sockaddr_storage srcaddr;
|
||||
unsigned short srcport;
|
||||
|
@ -76,6 +77,8 @@ struct sock_xprt {
|
|||
*/
|
||||
#define TCP_RPC_REPLY (1UL << 6)
|
||||
|
||||
#define XPRT_SOCK_CONNECTING 1U
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
|
||||
|
|
|
@ -1092,14 +1092,10 @@ void
|
|||
rpc_destroy_mempool(void)
|
||||
{
|
||||
rpciod_stop();
|
||||
if (rpc_buffer_mempool)
|
||||
mempool_destroy(rpc_buffer_mempool);
|
||||
if (rpc_task_mempool)
|
||||
mempool_destroy(rpc_task_mempool);
|
||||
if (rpc_task_slabp)
|
||||
kmem_cache_destroy(rpc_task_slabp);
|
||||
if (rpc_buffer_slabp)
|
||||
kmem_cache_destroy(rpc_buffer_slabp);
|
||||
mempool_destroy(rpc_buffer_mempool);
|
||||
mempool_destroy(rpc_task_mempool);
|
||||
kmem_cache_destroy(rpc_task_slabp);
|
||||
kmem_cache_destroy(rpc_buffer_slabp);
|
||||
rpc_destroy_wait_queue(&delay_queue);
|
||||
}
|
||||
|
||||
|
|
|
@ -614,6 +614,7 @@ static void xprt_autoclose(struct work_struct *work)
|
|||
clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||||
xprt->ops->close(xprt);
|
||||
xprt_release_write(xprt, NULL);
|
||||
wake_up_bit(&xprt->state, XPRT_LOCKED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -723,6 +724,7 @@ void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
|
|||
xprt->ops->release_xprt(xprt, NULL);
|
||||
out:
|
||||
spin_unlock_bh(&xprt->transport_lock);
|
||||
wake_up_bit(&xprt->state, XPRT_LOCKED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1394,6 +1396,10 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
|
|||
static void xprt_destroy(struct rpc_xprt *xprt)
|
||||
{
|
||||
dprintk("RPC: destroying transport %p\n", xprt);
|
||||
|
||||
/* Exclude transport connect/disconnect handlers */
|
||||
wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE);
|
||||
|
||||
del_timer_sync(&xprt->timer);
|
||||
|
||||
rpc_xprt_debugfs_unregister(xprt);
|
||||
|
|
|
@ -777,7 +777,6 @@ static void xs_sock_mark_closed(struct rpc_xprt *xprt)
|
|||
xs_sock_reset_connection_flags(xprt);
|
||||
/* Mark transport as closed and wake up all pending tasks */
|
||||
xprt_disconnect_done(xprt);
|
||||
xprt_force_disconnect(xprt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -881,8 +880,11 @@ static void xs_xprt_free(struct rpc_xprt *xprt)
|
|||
*/
|
||||
static void xs_destroy(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sock_xprt *transport = container_of(xprt,
|
||||
struct sock_xprt, xprt);
|
||||
dprintk("RPC: xs_destroy xprt %p\n", xprt);
|
||||
|
||||
cancel_delayed_work_sync(&transport->connect_worker);
|
||||
xs_close(xprt);
|
||||
xs_xprt_free(xprt);
|
||||
module_put(THIS_MODULE);
|
||||
|
@ -1435,6 +1437,7 @@ static void xs_tcp_data_ready(struct sock *sk)
|
|||
static void xs_tcp_state_change(struct sock *sk)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
struct sock_xprt *transport;
|
||||
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
if (!(xprt = xprt_from_sock(sk)))
|
||||
|
@ -1446,13 +1449,12 @@ static void xs_tcp_state_change(struct sock *sk)
|
|||
sock_flag(sk, SOCK_ZAPPED),
|
||||
sk->sk_shutdown);
|
||||
|
||||
transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
trace_rpc_socket_state_change(xprt, sk->sk_socket);
|
||||
switch (sk->sk_state) {
|
||||
case TCP_ESTABLISHED:
|
||||
spin_lock(&xprt->transport_lock);
|
||||
if (!xprt_test_and_set_connected(xprt)) {
|
||||
struct sock_xprt *transport = container_of(xprt,
|
||||
struct sock_xprt, xprt);
|
||||
|
||||
/* Reset TCP record info */
|
||||
transport->tcp_offset = 0;
|
||||
|
@ -1461,6 +1463,8 @@ static void xs_tcp_state_change(struct sock *sk)
|
|||
transport->tcp_flags =
|
||||
TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID;
|
||||
xprt->connect_cookie++;
|
||||
clear_bit(XPRT_SOCK_CONNECTING, &transport->sock_state);
|
||||
xprt_clear_connecting(xprt);
|
||||
|
||||
xprt_wake_pending_tasks(xprt, -EAGAIN);
|
||||
}
|
||||
|
@ -1496,6 +1500,9 @@ static void xs_tcp_state_change(struct sock *sk)
|
|||
smp_mb__after_atomic();
|
||||
break;
|
||||
case TCP_CLOSE:
|
||||
if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
|
||||
&transport->sock_state))
|
||||
xprt_clear_connecting(xprt);
|
||||
xs_sock_mark_closed(xprt);
|
||||
}
|
||||
out:
|
||||
|
@ -2179,6 +2186,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
|||
/* Tell the socket layer to start connecting... */
|
||||
xprt->stat.connect_count++;
|
||||
xprt->stat.connect_start = jiffies;
|
||||
set_bit(XPRT_SOCK_CONNECTING, &transport->sock_state);
|
||||
ret = kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
|
@ -2240,7 +2248,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
|||
case -EINPROGRESS:
|
||||
case -EALREADY:
|
||||
xprt_unlock_connect(xprt, transport);
|
||||
xprt_clear_connecting(xprt);
|
||||
return;
|
||||
case -EINVAL:
|
||||
/* Happens, for instance, if the user specified a link
|
||||
|
|
Loading…
Reference in New Issue