nfs4: serialize layoutcommit
Subsystems (2)
PATCH v2 1/1 nfs4: serialize layoutcommit
Current pnfs_layoutcommit_inode can not handle parallel layoutcommit. And as Trond suggested , there is no need for client to optimize for parallel layoutcommit. So add NFS_INO_LAYOUTCOMMITTING flag to mark inflight layoutcommit and serialize lalyoutcommit with it. Also call mark_inode_dirty_sync if pnfs_layoutcommit_inode fails to issue layoutcommit, so that layoutcommit can be retried later. It also fixes the pls_lc_list corruption that Vitaliy found.
Reported-by Vitaliy Gusev <[email protected]>
Signed-off-by Peng Tao <[email protected]>
--- fs/nfs/nfs4proc.c | 6 ++++++ fs/nfs/pnfs.c | 24 +++++++++++++++++++++--- include/linux/nfs_fs.h | 1 + 3 files changed, 28 insertions(+), 3 deletions(-)
fs/nfs/nfs4proc.c +6 -0
@@ -5970,6 +5970,7 @@ static void nfs4_layoutcommit_release(void *calldata) {struct nfs4_layoutcommit_data *data = calldata;struct pnfs_layout_segment *lseg, *tmp; +unsigned long *bitlock = &NFS_I (data->args.inode)->flags;pnfs_cleanup_layoutcommit (data);/* Matched by references in pnfs_set_layoutcommit */
@@ -5979,6 +5980,11 @@ static void nfs4_layoutcommit_release(void *calldata) &lseg->pls_flags))put_lseg (lseg); } + +clear_bit_unlock (NFS_INO_LAYOUTCOMMITTING , bitlock); +smp_mb__after_clear_bit (); +wake_up_bit (bitlock,NFS_INO_LAYOUTCOMMITTING ); +put_rpccred (data->cred);kfree (data); }
fs/nfs/pnfs.c +21 -3
@@ -1446,17 +1446,30 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)/* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ data =kzalloc (sizeof (*data),GFP_NOFS );if (!data) { -mark_inode_dirty_sync (inode); status = -ENOMEM ; goto out; } +if (!test_bit (NFS_INO_LAYOUTCOMMIT , &nfsi->flags)) + goto out_free; +else if (test_and_set_bit (NFS_INO_LAYOUTCOMMITTING , &nfsi->flags)) { +if (!sync) { + status = -EAGAIN ; + goto out_free; + } + status =wait_on_bit_lock (&nfsi->flags,NFS_INO_LAYOUTCOMMITTING , + nfs_wait_bit_killable,TASK_KILLABLE ); +if (status) + goto out_free; + } +INIT_LIST_HEAD (&data->lseg_list);spin_lock (&inode->i_lock);if (!test_and_clear_bit (NFS_INO_LAYOUTCOMMIT , &nfsi->flags)) { +clear_bit (NFS_INO_LAYOUTCOMMITTING , &nfsi->flags);spin_unlock (&inode->i_lock); -kfree (data); - goto out; +wake_up_bit (&nfsi->flags,NFS_INO_LAYOUTCOMMITTING ); + goto out_free; }pnfs_list_write_lseg (inode, &data->lseg_list);
@@ -1478,8 +1491,13 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) status =nfs4_proc_layoutcommit (data, sync); out: +if (status) +mark_inode_dirty_sync (inode);dprintk ("<-- %s status %d\n" , __func__, status);return status; +out_free: +kfree (data); + goto out; }/*
include/linux/nfs_fs.h +1 -0
@@ -230,6 +230,7 @@ struct nfs_inode {#define NFS_INO_COMMIT (7)/* inode is committing unstable writes */ #define NFS_INO_PNFS_COMMIT (8)/* use pnfs code for commit */ #define NFS_INO_LAYOUTCOMMIT (9)/* layoutcommit required */ +#define NFS_INO_LAYOUTCOMMITTING (10)/* layoutcommit inflight */ static inline struct nfs_inode *NFS_I (const struct inode *inode) {
Signature · 1 line
1.7.1.262.g5ef3d