Commit a9bae566 authored by Peng Tao's avatar Peng Tao Committed by Trond Myklebust

pnfs: let layoutcommit handle a list of lseg

There can be multiple lseg per file, so layoutcommit should be
able to handle it.

[Needed in v3.0]
CC: Stable Tree <stable@kernel.org>
Signed-off-by: default avatarPeng Tao <peng_tao@emc.com>
Signed-off-by: default avatarBoaz Harrosh <bharrosh@panasas.com>
Signed-off-by: default avatarJim Rees <rees@umich.edu>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 9fa40758
...@@ -5912,9 +5912,15 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) ...@@ -5912,9 +5912,15 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
static void nfs4_layoutcommit_release(void *calldata) static void nfs4_layoutcommit_release(void *calldata)
{ {
struct nfs4_layoutcommit_data *data = calldata; struct nfs4_layoutcommit_data *data = calldata;
struct pnfs_layout_segment *lseg, *tmp;
/* Matched by references in pnfs_set_layoutcommit */ /* Matched by references in pnfs_set_layoutcommit */
put_lseg(data->lseg); list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
list_del_init(&lseg->pls_lc_list);
if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
&lseg->pls_flags))
put_lseg(lseg);
}
put_rpccred(data->cred); put_rpccred(data->cred);
kfree(data); kfree(data);
} }
......
...@@ -225,6 +225,7 @@ static void ...@@ -225,6 +225,7 @@ static void
init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg) init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
{ {
INIT_LIST_HEAD(&lseg->pls_list); INIT_LIST_HEAD(&lseg->pls_list);
INIT_LIST_HEAD(&lseg->pls_lc_list);
atomic_set(&lseg->pls_refcount, 1); atomic_set(&lseg->pls_refcount, 1);
smp_mb(); smp_mb();
set_bit(NFS_LSEG_VALID, &lseg->pls_flags); set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
...@@ -1356,16 +1357,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) ...@@ -1356,16 +1357,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
/* /*
* Currently there is only one (whole file) write lseg. * There can be multiple RW segments.
*/ */
static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode) static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
{ {
struct pnfs_layout_segment *lseg, *rv = NULL; struct pnfs_layout_segment *lseg;
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
if (lseg->pls_range.iomode == IOMODE_RW) if (lseg->pls_range.iomode == IOMODE_RW &&
rv = lseg; test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
return rv; list_add(&lseg->pls_lc_list, listp);
}
} }
void void
...@@ -1377,12 +1379,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) ...@@ -1377,12 +1379,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
spin_lock(&nfsi->vfs_inode.i_lock); spin_lock(&nfsi->vfs_inode.i_lock);
if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
/* references matched in nfs4_layoutcommit_release */
get_lseg(wdata->lseg);
mark_as_dirty = true; mark_as_dirty = true;
dprintk("%s: Set layoutcommit for inode %lu ", dprintk("%s: Set layoutcommit for inode %lu ",
__func__, wdata->inode->i_ino); __func__, wdata->inode->i_ino);
} }
if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
/* references matched in nfs4_layoutcommit_release */
get_lseg(wdata->lseg);
}
if (end_pos > nfsi->layout->plh_lwb) if (end_pos > nfsi->layout->plh_lwb)
nfsi->layout->plh_lwb = end_pos; nfsi->layout->plh_lwb = end_pos;
spin_unlock(&nfsi->vfs_inode.i_lock); spin_unlock(&nfsi->vfs_inode.i_lock);
...@@ -1409,7 +1413,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -1409,7 +1413,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
{ {
struct nfs4_layoutcommit_data *data; struct nfs4_layoutcommit_data *data;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct pnfs_layout_segment *lseg;
loff_t end_pos; loff_t end_pos;
int status = 0; int status = 0;
...@@ -1426,17 +1429,15 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -1426,17 +1429,15 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
goto out; goto out;
} }
INIT_LIST_HEAD(&data->lseg_list);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
kfree(data); kfree(data);
goto out; goto out;
} }
/*
* Currently only one (whole file) write lseg which is referenced pnfs_list_write_lseg(inode, &data->lseg_list);
* in pnfs_set_layoutcommit and will be found.
*/
lseg = pnfs_list_write_lseg(inode);
end_pos = nfsi->layout->plh_lwb; end_pos = nfsi->layout->plh_lwb;
nfsi->layout->plh_lwb = 0; nfsi->layout->plh_lwb = 0;
...@@ -1446,7 +1447,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -1446,7 +1447,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
data->args.inode = inode; data->args.inode = inode;
data->lseg = lseg;
data->cred = get_rpccred(nfsi->layout->plh_lc_cred); data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
nfs_fattr_init(&data->fattr); nfs_fattr_init(&data->fattr);
data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
......
...@@ -36,10 +36,12 @@ ...@@ -36,10 +36,12 @@
enum { enum {
NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */
NFS_LSEG_ROC, /* roc bit received from server */ NFS_LSEG_ROC, /* roc bit received from server */
NFS_LSEG_LAYOUTCOMMIT, /* layoutcommit bit set for layoutcommit */
}; };
struct pnfs_layout_segment { struct pnfs_layout_segment {
struct list_head pls_list; struct list_head pls_list;
struct list_head pls_lc_list;
struct pnfs_layout_range pls_range; struct pnfs_layout_range pls_range;
atomic_t pls_refcount; atomic_t pls_refcount;
unsigned long pls_flags; unsigned long pls_flags;
......
...@@ -262,7 +262,7 @@ struct nfs4_layoutcommit_res { ...@@ -262,7 +262,7 @@ struct nfs4_layoutcommit_res {
struct nfs4_layoutcommit_data { struct nfs4_layoutcommit_data {
struct rpc_task task; struct rpc_task task;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct pnfs_layout_segment *lseg; struct list_head lseg_list;
struct rpc_cred *cred; struct rpc_cred *cred;
struct nfs4_layoutcommit_args args; struct nfs4_layoutcommit_args args;
struct nfs4_layoutcommit_res res; struct nfs4_layoutcommit_res res;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment