NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn
Note that clearing NFS_INO_LAYOUTCOMMIT is tricky, since it requires you to also clear the NFS_LSEG_LAYOUTCOMMIT bits from the layout segments. The only two sites that need to do this are the ones that call pnfs_return_layout() without first doing a layout commit. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Acked-by: Benny Halevy <bhalevy@tonian.com> Cc: stable@vger.kernel.org
This commit is contained in:
Родитель
a073dbff35
Коммит
2495680434
|
@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo)
|
|||
{
|
||||
if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
|
||||
return;
|
||||
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
|
||||
pnfs_return_layout(inode);
|
||||
}
|
||||
|
||||
|
|
|
@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range,
|
|||
lo_seg_intersecting(lseg_range, recall_range);
|
||||
}
|
||||
|
||||
static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg,
|
||||
struct list_head *tmp_list)
|
||||
{
|
||||
if (!atomic_dec_and_test(&lseg->pls_refcount))
|
||||
return false;
|
||||
pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
|
||||
list_add(&lseg->pls_list, tmp_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns 1 if lseg is removed from list, 0 otherwise */
|
||||
static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
|
||||
struct list_head *tmp_list)
|
||||
|
@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
|
|||
*/
|
||||
dprintk("%s: lseg %p ref %d\n", __func__, lseg,
|
||||
atomic_read(&lseg->pls_refcount));
|
||||
if (atomic_dec_and_test(&lseg->pls_refcount)) {
|
||||
pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
|
||||
list_add(&lseg->pls_list, tmp_list);
|
||||
if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
|
|||
return lseg;
|
||||
}
|
||||
|
||||
static void pnfs_clear_layoutcommit(struct inode *inode,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct pnfs_layout_segment *lseg, *tmp;
|
||||
|
||||
if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
|
||||
return;
|
||||
list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) {
|
||||
if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
|
||||
continue;
|
||||
pnfs_lseg_dec_and_remove_zero(lseg, head);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
|
||||
* when the layout segment list is empty.
|
||||
|
@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino)
|
|||
/* Reference matched in nfs4_layoutreturn_release */
|
||||
pnfs_get_layout_hdr(lo);
|
||||
empty = list_empty(&lo->plh_segs);
|
||||
pnfs_clear_layoutcommit(ino, &tmp_list);
|
||||
pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
|
||||
/* Don't send a LAYOUTRETURN if list was initially empty */
|
||||
if (empty) {
|
||||
|
@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino)
|
|||
spin_unlock(&ino->i_lock);
|
||||
pnfs_free_lseg_list(&tmp_list);
|
||||
|
||||
WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
|
||||
|
||||
lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
|
||||
if (unlikely(lrp == NULL)) {
|
||||
status = -ENOMEM;
|
||||
|
@ -1458,7 +1479,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
|
|||
dprintk("pnfs write error = %d\n", hdr->pnfs_error);
|
||||
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
|
||||
PNFS_LAYOUTRET_ON_ERROR) {
|
||||
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
|
||||
pnfs_return_layout(hdr->inode);
|
||||
}
|
||||
if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
|
||||
|
@ -1613,7 +1633,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
|
|||
dprintk("pnfs read error = %d\n", hdr->pnfs_error);
|
||||
if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
|
||||
PNFS_LAYOUTRET_ON_ERROR) {
|
||||
clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
|
||||
pnfs_return_layout(hdr->inode);
|
||||
}
|
||||
if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
|
||||
|
|
Загрузка…
Ссылка в новой задаче