diff options
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 218 |
1 files changed, 33 insertions, 185 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3b71623..d00260b 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -417,16 +417,6 @@ 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) @@ -440,8 +430,11 @@ 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 (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) + if (atomic_dec_and_test(&lseg->pls_refcount)) { + pnfs_layout_remove_lseg(lseg->pls_layout, lseg); + list_add(&lseg->pls_list, tmp_list); rv = 1; + } } return rv; } @@ -512,147 +505,37 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) } EXPORT_SYMBOL_GPL(pnfs_destroy_layout); -static bool -pnfs_layout_add_bulk_destroy_list(struct inode *inode, - struct list_head *layout_list) -{ - struct pnfs_layout_hdr *lo; - bool ret = false; - - spin_lock(&inode->i_lock); - lo = NFS_I(inode)->layout; - if (lo != NULL && list_empty(&lo->plh_bulk_destroy)) { - pnfs_get_layout_hdr(lo); - list_add(&lo->plh_bulk_destroy, layout_list); - ret = true; - } - spin_unlock(&inode->i_lock); - return ret; -} - -/* Caller must hold rcu_read_lock and clp->cl_lock */ -static int -pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, - struct nfs_server *server, - struct list_head *layout_list) -{ - struct pnfs_layout_hdr *lo, *next; - struct inode *inode; - - list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { - inode = igrab(lo->plh_inode); - if (inode == NULL) - continue; - list_del_init(&lo->plh_layouts); - if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) - continue; - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - iput(inode); - spin_lock(&clp->cl_lock); - rcu_read_lock(); - return -EAGAIN; - } - return 0; -} - -static int -pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, - bool is_bulk_recall) +/* + * Called by the state manger to remove all layouts established under an + * expired lease. + */ +void +pnfs_destroy_all_layouts(struct nfs_client *clp) { + struct nfs_server *server; struct pnfs_layout_hdr *lo; - struct inode *inode; - struct pnfs_layout_range range = { - .iomode = IOMODE_ANY, - .offset = 0, - .length = NFS4_MAX_UINT64, - }; - LIST_HEAD(lseg_list); - int ret = 0; - - while (!list_empty(layout_list)) { - lo = list_entry(layout_list->next, struct pnfs_layout_hdr, - plh_bulk_destroy); - dprintk("%s freeing layout for inode %lu\n", __func__, - lo->plh_inode->i_ino); - inode = lo->plh_inode; - spin_lock(&inode->i_lock); - list_del_init(&lo->plh_bulk_destroy); - lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ - if (is_bulk_recall) - set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); - if (pnfs_mark_matching_lsegs_invalid(lo, &lseg_list, &range)) - ret = -EAGAIN; - spin_unlock(&inode->i_lock); - pnfs_free_lseg_list(&lseg_list); - pnfs_put_layout_hdr(lo); - iput(inode); - } - return ret; -} + LIST_HEAD(tmp_list); -int -pnfs_destroy_layouts_byfsid(struct nfs_client *clp, - struct nfs_fsid *fsid, - bool is_recall) -{ - struct nfs_server *server; - LIST_HEAD(layout_list); + nfs4_deviceid_mark_client_invalid(clp); + nfs4_deviceid_purge_client(clp); spin_lock(&clp->cl_lock); rcu_read_lock(); -restart: list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - if (memcmp(&server->fsid, fsid, sizeof(*fsid)) != 0) - continue; - if (pnfs_layout_bulk_destroy_byserver_locked(clp, - server, - &layout_list) != 0) - goto restart; + if (!list_empty(&server->layouts)) + list_splice_init(&server->layouts, &tmp_list); } rcu_read_unlock(); spin_unlock(&clp->cl_lock); - if (list_empty(&layout_list)) - return 0; - return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); -} - -int -pnfs_destroy_layouts_byclid(struct nfs_client *clp, - bool is_recall) -{ - struct nfs_server *server; - LIST_HEAD(layout_list); - - spin_lock(&clp->cl_lock); - rcu_read_lock(); -restart: - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - if (pnfs_layout_bulk_destroy_byserver_locked(clp, - server, - &layout_list) != 0) - goto restart; + while (!list_empty(&tmp_list)) { + lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, + plh_layouts); + dprintk("%s freeing layout for inode %lu\n", __func__, + lo->plh_inode->i_ino); + list_del_init(&lo->plh_layouts); + pnfs_destroy_layout(NFS_I(lo->plh_inode)); } - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - - if (list_empty(&layout_list)) - return 0; - return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); -} - -/* - * Called by the state manger to remove all layouts established under an - * expired lease. - */ -void -pnfs_destroy_all_layouts(struct nfs_client *clp) -{ - nfs4_deviceid_mark_client_invalid(clp); - nfs4_deviceid_purge_client(clp); - - pnfs_destroy_layouts_byclid(clp, false); } /* @@ -784,21 +667,6 @@ 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. @@ -830,7 +698,6 @@ _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) { @@ -843,6 +710,8 @@ _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; @@ -1019,7 +888,7 @@ alloc_init_layout_hdr(struct inode *ino, atomic_set(&lo->plh_refcount, 1); INIT_LIST_HEAD(&lo->plh_layouts); INIT_LIST_HEAD(&lo->plh_segs); - INIT_LIST_HEAD(&lo->plh_bulk_destroy); + INIT_LIST_HEAD(&lo->plh_bulk_recall); lo->plh_inode = ino; lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred); return lo; @@ -1443,15 +1312,13 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq) + const struct nfs_pgio_completion_ops *compl_ops) { struct nfs_pageio_descriptor pgio; LIST_HEAD(failed); /* Resend all requests through the MDS */ nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); - pgio.pg_dreq = dreq; while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); @@ -1480,13 +1347,13 @@ 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)) data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } /* @@ -1601,15 +1468,13 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, - const struct nfs_pgio_completion_ops *compl_ops, - struct nfs_direct_req *dreq) + const struct nfs_pgio_completion_ops *compl_ops) { struct nfs_pageio_descriptor pgio; LIST_HEAD(failed); /* Resend all requests through the MDS */ nfs_pageio_init_read(&pgio, inode, compl_ops); - pgio.pg_dreq = dreq; while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); @@ -1634,13 +1499,13 @@ 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)) data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, &hdr->pages, - hdr->completion_ops, - hdr->dreq); + hdr->completion_ops); } /* @@ -1766,27 +1631,11 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { if (lseg->pls_range.iomode == IOMODE_RW && - test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) list_add(&lseg->pls_lc_list, listp); } } -static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) -{ - struct pnfs_layout_segment *lseg, *tmp; - unsigned long *bitlock = &NFS_I(inode)->flags; - - /* Matched by references in pnfs_set_layoutcommit */ - list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { - list_del_init(&lseg->pls_lc_list); - pnfs_put_lseg(lseg); - } - - clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); - smp_mb__after_clear_bit(); - wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); -} - void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) { pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); @@ -1831,7 +1680,6 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data) if (nfss->pnfs_curr_ld->cleanup_layoutcommit) nfss->pnfs_curr_ld->cleanup_layoutcommit(data); - pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list); } /* |