summaryrefslogtreecommitdiff
path: root/fs/nfs/pnfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r--fs/nfs/pnfs.c218
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);
}
/*