1, fix an issue that client may send LAYOUTRETURN before LAYOUTCOMMIT 2, update layout stateid when layoutcommit receiving NFS4ERR_OLD_STATEID --- fs/nfs/nfs4proc.c | 19 ++++++++++++++++++- fs/nfs/pnfs.c | 15 ++++++++++++--- fs/nfs/pnfs.h | 6 ++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7d2b67e06cc3..448a13f2537b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -10081,7 +10081,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) case -NFS4ERR_OLD_STATEID: if (nfs4_layout_refresh_old_stateid(&lrp->args.stateid, &lrp->args.range, - lrp->args.inode)) + lrp->args.inode, + false)) goto out_restart; fallthrough; default: @@ -10255,6 +10256,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) { struct nfs4_layoutcommit_data *data = calldata; struct nfs_server *server = NFS_SERVER(data->args.inode); + struct pnfs_layout_range dst_range; if (!nfs41_sequence_done(task, &data->res.seq_res)) return; @@ -10268,6 +10270,14 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) break; case 0: break; + case -NFS4ERR_OLD_STATEID: + if (data->inode) { + nfs4_layout_refresh_old_stateid(&data->args.stateid, + &dst_range, + data->args.inode, + true); + } + fallthrough; default: if (nfs4_async_handle_error(task, server, NULL, NULL) == -EAGAIN) { rpc_restart_call_prepare(task); @@ -10279,10 +10289,17 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) static void nfs4_layoutcommit_release(void *calldata) { struct nfs4_layoutcommit_data *data = calldata; + struct inode *inode = data->args.inode; pnfs_cleanup_layoutcommit(data); nfs_post_op_update_inode_force_wcc(data->args.inode, data->res.fattr); + struct pnfs_layout_hdr *lo; + spin_lock(&inode->i_lock); + lo = NFS_I(inode)->layout; + spin_unlock(&inode->i_lock); + pnfs_put_layout_hdr(lo); + put_cred(data->cred); nfs_iput_and_deactive(data->inode); kfree(data); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a3135b5af7ee..defc0a84e6c7 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -409,7 +409,8 @@ pnfs_clear_lseg_state(struct pnfs_layout_segment *lseg, */ bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst, struct pnfs_layout_range *dst_range, - struct inode *inode) + struct inode *inode, + bool force_update) { struct pnfs_layout_hdr *lo; struct pnfs_layout_range range = { @@ -433,7 +434,7 @@ bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst, } /* Try to update the seqid to the most recent */ err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0); - if (err != -EBUSY) { + if (force_update || err != -EBUSY) { dst->seqid = lo->plh_stateid.seqid; *dst_range = range; ret = true; @@ -1306,6 +1307,9 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo, /* Serialise LAYOUTGET/LAYOUTRETURN */ if (atomic_read(&lo->plh_outstanding) != 0 && lo->plh_return_seq == 0) return false; + /* Serialise LAYOUTCOMMIT/LAYOUTRETURN */ + if (pnfs_layoutcommit_outstanding(lo->plh_inode)) + return false; if (test_and_set_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) return false; set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); @@ -1686,7 +1690,8 @@ int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp, return 0; case -NFS4ERR_OLD_STATEID: if (!nfs4_layout_refresh_old_stateid(&arg->stateid, - &arg->range, arg->inode)) + &arg->range, arg->inode, + false)) break; *ret = -NFS4ERR_NOMATCHING_LAYOUT; return -EAGAIN; @@ -3397,6 +3402,10 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) } } + /* the ref will be free on nfs4_layoutcommit_release, and trigger + * LAYOUTRETURN + */ + pnfs_get_layout_hdr(nfsi->layout); status = nfs4_proc_layoutcommit(data, sync); out: diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 91ff877185c8..c6788f1423a3 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -287,7 +287,8 @@ int pnfs_layout_destroy_byclid(struct nfs_client *clp, enum pnfs_layout_destroy_mode mode); bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst, struct pnfs_layout_range *dst_range, - struct inode *inode); + struct inode *inode, + bool force_update); void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo); void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, @@ -891,7 +892,8 @@ static inline void nfs4_pnfs_v3_ds_connect_unload(void) static inline bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst, struct pnfs_layout_range *dst_range, - struct inode *inode) + struct inode *inode, + bool force_update) { return false; } -- 2.51.0.87.g1fa68948c3.dirty