Commit 68f74479 authored by Trond Myklebust's avatar Trond Myklebust

pNFS: Do not free layout segments that are marked for return

We may want to process and transmit layout stat information for the
layout segments that are being returned, so we should defer freeing
them until after the layoutreturn has completed.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 7b410d9c
......@@ -8572,21 +8572,12 @@ static void nfs4_layoutreturn_release(void *calldata)
{
struct nfs4_layoutreturn *lrp = calldata;
struct pnfs_layout_hdr *lo = lrp->args.layout;
LIST_HEAD(freeme);
dprintk("--> %s\n", __func__);
spin_lock(&lo->plh_inode->i_lock);
if (lrp->res.lrs_present) {
pnfs_mark_matching_lsegs_invalid(lo, &freeme,
&lrp->args.range,
be32_to_cpu(lrp->args.stateid.seqid));
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
} else
pnfs_mark_layout_stateid_invalid(lo, &freeme);
pnfs_clear_layoutreturn_waitbit(lo);
spin_unlock(&lo->plh_inode->i_lock);
pnfs_layoutreturn_free_lsegs(lo, &lrp->args.range,
be32_to_cpu(lrp->args.stateid.seqid),
lrp->res.lrs_present ? &lrp->res.stateid : NULL);
nfs4_sequence_free_slot(&lrp->res.seq_res);
pnfs_free_lseg_list(&freeme);
pnfs_put_layout_hdr(lrp->args.layout);
nfs_iput_and_deactive(lrp->inode);
kfree(calldata);
......
......@@ -54,6 +54,10 @@ static DEFINE_SPINLOCK(pnfs_spinlock);
static LIST_HEAD(pnfs_modules_tbl);
static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo);
static void pnfs_free_returned_lsegs(struct pnfs_layout_hdr *lo,
struct list_head *free_me,
const struct pnfs_layout_range *range,
u32 seq);
/* Return the registered pnfs layout driver module matching given id */
static struct pnfs_layoutdriver_type *
......@@ -326,6 +330,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
pnfs_clear_layoutreturn_info(lo);
pnfs_free_returned_lsegs(lo, lseg_list, &range, 0);
return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range, 0);
}
......@@ -405,9 +410,10 @@ pnfs_init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg,
static void pnfs_free_lseg(struct pnfs_layout_segment *lseg)
{
struct inode *ino = lseg->pls_layout->plh_inode;
NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
if (lseg != NULL) {
struct inode *inode = lseg->pls_layout->plh_inode;
NFS_SERVER(inode)->pnfs_curr_ld->free_lseg(lseg);
}
}
static void
......@@ -430,6 +436,18 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
}
static bool
pnfs_cache_lseg_for_layoutreturn(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg)
{
if (test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags) &&
pnfs_layout_is_valid(lo)) {
list_move_tail(&lseg->pls_list, &lo->plh_return_segs);
return true;
}
return false;
}
void
pnfs_put_lseg(struct pnfs_layout_segment *lseg)
{
......@@ -453,6 +471,8 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
}
pnfs_get_layout_hdr(lo);
pnfs_layout_remove_lseg(lo, lseg);
if (pnfs_cache_lseg_for_layoutreturn(lo, lseg))
lseg = NULL;
spin_unlock(&inode->i_lock);
pnfs_free_lseg(lseg);
pnfs_put_layout_hdr(lo);
......@@ -493,10 +513,12 @@ pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg)
struct pnfs_layout_hdr *lo = lseg->pls_layout;
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
return;
pnfs_get_layout_hdr(lo);
pnfs_layout_remove_lseg(lo, lseg);
if (!pnfs_cache_lseg_for_layoutreturn(lo, lseg)) {
pnfs_get_layout_hdr(lo);
pnfs_free_lseg_async(lseg);
}
}
}
EXPORT_SYMBOL_GPL(pnfs_put_lseg_locked);
......@@ -619,6 +641,20 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
return remaining;
}
static void
pnfs_free_returned_lsegs(struct pnfs_layout_hdr *lo,
struct list_head *free_me,
const struct pnfs_layout_range *range,
u32 seq)
{
struct pnfs_layout_segment *lseg, *next;
list_for_each_entry_safe(lseg, next, &lo->plh_return_segs, pls_list) {
if (pnfs_match_lseg_recall(lseg, range, seq))
list_move_tail(&lseg->pls_list, free_me);
}
}
/* note free_me must contain lsegs from a single layout_hdr */
void
pnfs_free_lseg_list(struct list_head *free_me)
......@@ -915,7 +951,7 @@ static void pnfs_clear_layoutcommit(struct inode *inode,
}
}
void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
static void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
{
clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags);
clear_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags);
......@@ -924,6 +960,27 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
}
void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
const struct pnfs_layout_range *range,
u32 seq,
const nfs4_stateid *stateid)
{
struct inode *inode = lo->plh_inode;
LIST_HEAD(freeme);
spin_lock(&inode->i_lock);
if (stateid) {
pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq);
pnfs_free_returned_lsegs(lo, &freeme, range, seq);
pnfs_set_layout_stateid(lo, stateid, true);
} else
pnfs_mark_layout_stateid_invalid(lo, &freeme);
pnfs_clear_layoutreturn_waitbit(lo);
spin_unlock(&inode->i_lock);
pnfs_free_lseg_list(&freeme);
}
static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
nfs4_stateid *stateid,
......@@ -1349,6 +1406,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_return_segs);
INIT_LIST_HEAD(&lo->plh_bulk_destroy);
lo->plh_inode = ino;
lo->plh_lc_cred = get_rpccred(ctx->cred);
......@@ -1920,7 +1978,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
.offset = 0,
.length = NFS4_MAX_UINT64,
};
LIST_HEAD(free_me);
bool return_now = false;
spin_lock(&inode->i_lock);
......@@ -1932,7 +1989,7 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
* for how it works.
*/
if (!pnfs_mark_matching_lsegs_return(lo, &free_me, &range, 0)) {
if (!pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0)) {
nfs4_stateid stateid;
enum pnfs_iomode iomode;
......@@ -1944,7 +2001,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
spin_unlock(&inode->i_lock);
nfs_commit_inode(inode, 0);
}
pnfs_free_lseg_list(&free_me);
}
EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return);
......
......@@ -191,6 +191,7 @@ struct pnfs_layout_hdr {
struct list_head plh_layouts; /* other client layouts */
struct list_head plh_bulk_destroy;
struct list_head plh_segs; /* layout segments list */
struct list_head plh_return_segs; /* invalid layout segments */
unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */
unsigned long plh_retry_timestamp;
unsigned long plh_flags;
......@@ -293,7 +294,10 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
enum pnfs_iomode iomode,
bool strict_iomode,
gfp_t gfp_flags);
void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo);
void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
const struct pnfs_layout_range *range,
u32 seq,
const nfs4_stateid *stateid);
void pnfs_generic_layout_insert_lseg(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg,
......
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