Commit a9901899 authored by Trond Myklebust's avatar Trond Myklebust

pNFS: Add infrastructure for cleaning up per-layout commit structures

Ensure that both the file and flexfiles layout types clean up when
freeing the layout segments.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent e3b9f7e6
...@@ -750,11 +750,16 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg) ...@@ -750,11 +750,16 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg)
/* This assumes a single RW lseg */ /* This assumes a single RW lseg */
if (lseg->pls_range.iomode == IOMODE_RW) { if (lseg->pls_range.iomode == IOMODE_RW) {
struct nfs4_filelayout *flo; struct nfs4_filelayout *flo;
struct inode *inode;
flo = FILELAYOUT_FROM_HDR(lseg->pls_layout); flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
inode = flo->generic_hdr.plh_inode;
spin_lock(&inode->i_lock);
flo->commit_info.nbuckets = 0; flo->commit_info.nbuckets = 0;
kfree(flo->commit_info.buckets); kfree(flo->commit_info.buckets);
flo->commit_info.buckets = NULL; flo->commit_info.buckets = NULL;
pnfs_generic_ds_cinfo_release_lseg(&flo->commit_info, lseg);
spin_unlock(&inode->i_lock);
} }
_filelayout_free_lseg(fl); _filelayout_free_lseg(fl);
} }
...@@ -1163,6 +1168,16 @@ filelayout_get_ds_info(struct inode *inode) ...@@ -1163,6 +1168,16 @@ filelayout_get_ds_info(struct inode *inode)
return &FILELAYOUT_FROM_HDR(layout)->commit_info; return &FILELAYOUT_FROM_HDR(layout)->commit_info;
} }
static void
filelayout_release_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
struct inode *inode)
{
spin_lock(&inode->i_lock);
pnfs_generic_ds_cinfo_destroy(fl_cinfo);
spin_unlock(&inode->i_lock);
}
static struct pnfs_layoutdriver_type filelayout_type = { static struct pnfs_layoutdriver_type filelayout_type = {
.id = LAYOUT_NFSV4_1_FILES, .id = LAYOUT_NFSV4_1_FILES,
.name = "LAYOUT_NFSV4_1_FILES", .name = "LAYOUT_NFSV4_1_FILES",
...@@ -1176,6 +1191,7 @@ static struct pnfs_layoutdriver_type filelayout_type = { ...@@ -1176,6 +1191,7 @@ static struct pnfs_layoutdriver_type filelayout_type = {
.pg_read_ops = &filelayout_pg_read_ops, .pg_read_ops = &filelayout_pg_read_ops,
.pg_write_ops = &filelayout_pg_write_ops, .pg_write_ops = &filelayout_pg_write_ops,
.get_ds_info = &filelayout_get_ds_info, .get_ds_info = &filelayout_get_ds_info,
.release_ds_info = filelayout_release_ds_info,
.mark_request_commit = filelayout_mark_request_commit, .mark_request_commit = filelayout_mark_request_commit,
.clear_request_commit = pnfs_generic_clear_request_commit, .clear_request_commit = pnfs_generic_clear_request_commit,
.scan_commit_lists = pnfs_generic_scan_commit_lists, .scan_commit_lists = pnfs_generic_scan_commit_lists,
......
...@@ -580,6 +580,7 @@ ff_layout_free_lseg(struct pnfs_layout_segment *lseg) ...@@ -580,6 +580,7 @@ ff_layout_free_lseg(struct pnfs_layout_segment *lseg)
kfree(ffl->commit_info.buckets); kfree(ffl->commit_info.buckets);
ffl->commit_info.buckets = NULL; ffl->commit_info.buckets = NULL;
} }
pnfs_generic_ds_cinfo_release_lseg(&ffl->commit_info, lseg);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
_ff_layout_free_lseg(fls); _ff_layout_free_lseg(fls);
...@@ -2003,6 +2004,15 @@ ff_layout_get_ds_info(struct inode *inode) ...@@ -2003,6 +2004,15 @@ ff_layout_get_ds_info(struct inode *inode)
return &FF_LAYOUT_FROM_HDR(layout)->commit_info; return &FF_LAYOUT_FROM_HDR(layout)->commit_info;
} }
static void
ff_layout_release_ds_info(struct pnfs_ds_commit_info *fl_cinfo,
struct inode *inode)
{
spin_lock(&inode->i_lock);
pnfs_generic_ds_cinfo_destroy(fl_cinfo);
spin_unlock(&inode->i_lock);
}
static void static void
ff_layout_free_deviceid_node(struct nfs4_deviceid_node *d) ff_layout_free_deviceid_node(struct nfs4_deviceid_node *d)
{ {
...@@ -2503,6 +2513,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = { ...@@ -2503,6 +2513,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = {
.pg_read_ops = &ff_layout_pg_read_ops, .pg_read_ops = &ff_layout_pg_read_ops,
.pg_write_ops = &ff_layout_pg_write_ops, .pg_write_ops = &ff_layout_pg_write_ops,
.get_ds_info = ff_layout_get_ds_info, .get_ds_info = ff_layout_get_ds_info,
.release_ds_info = ff_layout_release_ds_info,
.free_deviceid_node = ff_layout_free_deviceid_node, .free_deviceid_node = ff_layout_free_deviceid_node,
.mark_request_commit = pnfs_layout_mark_request_commit, .mark_request_commit = pnfs_layout_mark_request_commit,
.clear_request_commit = pnfs_generic_clear_request_commit, .clear_request_commit = pnfs_generic_clear_request_commit,
......
...@@ -534,9 +534,11 @@ void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo) ...@@ -534,9 +534,11 @@ void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo)
pnfs_bucket_clear_pnfs_ds_commit_verifiers(cinfo->buckets, pnfs_bucket_clear_pnfs_ds_commit_verifiers(cinfo->buckets,
cinfo->nbuckets); cinfo->nbuckets);
list_for_each_entry(array, &cinfo->commits, cinfo_list) rcu_read_lock();
list_for_each_entry_rcu(array, &cinfo->commits, cinfo_list)
pnfs_bucket_clear_pnfs_ds_commit_verifiers(array->buckets, pnfs_bucket_clear_pnfs_ds_commit_verifiers(array->buckets,
array->nbuckets); array->nbuckets);
rcu_read_unlock();
} }
#else #else
static inline static inline
......
...@@ -506,6 +506,7 @@ pnfs_init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg, ...@@ -506,6 +506,7 @@ pnfs_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); INIT_LIST_HEAD(&lseg->pls_lc_list);
INIT_LIST_HEAD(&lseg->pls_commits);
refcount_set(&lseg->pls_refcount, 1); refcount_set(&lseg->pls_refcount, 1);
set_bit(NFS_LSEG_VALID, &lseg->pls_flags); set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
lseg->pls_layout = lo; lseg->pls_layout = lo;
......
...@@ -66,6 +66,7 @@ struct nfs4_pnfs_ds { ...@@ -66,6 +66,7 @@ struct nfs4_pnfs_ds {
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 list_head pls_lc_list;
struct list_head pls_commits;
struct pnfs_layout_range pls_range; struct pnfs_layout_range pls_range;
refcount_t pls_refcount; refcount_t pls_refcount;
u32 pls_seq; u32 pls_seq;
...@@ -370,6 +371,9 @@ void nfs4_deviceid_purge_client(const struct nfs_client *); ...@@ -370,6 +371,9 @@ void nfs4_deviceid_purge_client(const struct nfs_client *);
/* pnfs_nfs.c */ /* pnfs_nfs.c */
struct pnfs_commit_array *pnfs_alloc_commit_array(size_t n, gfp_t gfp_flags); struct pnfs_commit_array *pnfs_alloc_commit_array(size_t n, gfp_t gfp_flags);
void pnfs_free_commit_array(struct pnfs_commit_array *p); void pnfs_free_commit_array(struct pnfs_commit_array *p);
void pnfs_generic_ds_cinfo_release_lseg(struct pnfs_ds_commit_info *fl_cinfo,
struct pnfs_layout_segment *lseg);
void pnfs_generic_ds_cinfo_destroy(struct pnfs_ds_commit_info *fl_cinfo);
void pnfs_generic_clear_request_commit(struct nfs_page *req, void pnfs_generic_clear_request_commit(struct nfs_page *req,
struct nfs_commit_info *cinfo); struct nfs_commit_info *cinfo);
......
...@@ -118,6 +118,67 @@ pnfs_free_commit_array(struct pnfs_commit_array *p) ...@@ -118,6 +118,67 @@ pnfs_free_commit_array(struct pnfs_commit_array *p)
} }
EXPORT_SYMBOL_GPL(pnfs_free_commit_array); EXPORT_SYMBOL_GPL(pnfs_free_commit_array);
static void
pnfs_release_commit_array_locked(struct pnfs_commit_array *array)
{
list_del_rcu(&array->cinfo_list);
list_del(&array->lseg_list);
pnfs_free_commit_array(array);
}
static void
pnfs_put_commit_array_locked(struct pnfs_commit_array *array)
{
if (refcount_dec_and_test(&array->refcount))
pnfs_release_commit_array_locked(array);
}
static void
pnfs_put_commit_array(struct pnfs_commit_array *array, struct inode *inode)
{
if (refcount_dec_and_lock(&array->refcount, &inode->i_lock)) {
pnfs_release_commit_array_locked(array);
spin_unlock(&inode->i_lock);
}
}
static struct pnfs_commit_array *
pnfs_get_commit_array(struct pnfs_commit_array *array)
{
if (refcount_inc_not_zero(&array->refcount))
return array;
return NULL;
}
static void
pnfs_remove_and_free_commit_array(struct pnfs_commit_array *array)
{
array->lseg = NULL;
list_del_init(&array->lseg_list);
pnfs_put_commit_array_locked(array);
}
void
pnfs_generic_ds_cinfo_release_lseg(struct pnfs_ds_commit_info *fl_cinfo,
struct pnfs_layout_segment *lseg)
{
struct pnfs_commit_array *array, *tmp;
list_for_each_entry_safe(array, tmp, &lseg->pls_commits, lseg_list)
pnfs_remove_and_free_commit_array(array);
}
EXPORT_SYMBOL_GPL(pnfs_generic_ds_cinfo_release_lseg);
void
pnfs_generic_ds_cinfo_destroy(struct pnfs_ds_commit_info *fl_cinfo)
{
struct pnfs_commit_array *array, *tmp;
list_for_each_entry_safe(array, tmp, &fl_cinfo->commits, cinfo_list)
pnfs_remove_and_free_commit_array(array);
}
EXPORT_SYMBOL_GPL(pnfs_generic_ds_cinfo_destroy);
/* /*
* Locks the nfs_page requests for commit and moves them to * Locks the nfs_page requests for commit and moves them to
* @bucket->committing. * @bucket->committing.
...@@ -177,14 +238,21 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max) ...@@ -177,14 +238,21 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max)
max -= cnt; max -= cnt;
if (!max) if (!max)
return rv; return rv;
list_for_each_entry(array, &fl_cinfo->commits, cinfo_list) { rcu_read_lock();
list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
if (!array->lseg || !pnfs_get_commit_array(array))
continue;
rcu_read_unlock();
cnt = pnfs_bucket_scan_array(cinfo, array->buckets, cnt = pnfs_bucket_scan_array(cinfo, array->buckets,
array->nbuckets, max); array->nbuckets, max);
rcu_read_lock();
pnfs_put_commit_array(array, cinfo->inode);
rv += cnt; rv += cnt;
max -= cnt; max -= cnt;
if (!max) if (!max)
break; break;
} }
rcu_read_unlock();
return rv; return rv;
} }
EXPORT_SYMBOL_GPL(pnfs_generic_scan_commit_lists); EXPORT_SYMBOL_GPL(pnfs_generic_scan_commit_lists);
...@@ -230,13 +298,20 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst, ...@@ -230,13 +298,20 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
fl_cinfo->nbuckets, fl_cinfo->nbuckets,
cinfo); cinfo);
fl_cinfo->nwritten -= nwritten; fl_cinfo->nwritten -= nwritten;
list_for_each_entry(array, &fl_cinfo->commits, cinfo_list) { rcu_read_lock();
list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
if (!array->lseg || !pnfs_get_commit_array(array))
continue;
rcu_read_unlock();
nwritten = pnfs_bucket_recover_commit_reqs(dst, nwritten = pnfs_bucket_recover_commit_reqs(dst,
array->buckets, array->buckets,
array->nbuckets, array->nbuckets,
cinfo); cinfo);
rcu_read_lock();
pnfs_put_commit_array(array, cinfo->inode);
fl_cinfo->nwritten -= nwritten; fl_cinfo->nwritten -= nwritten;
} }
rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs); EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
...@@ -330,9 +405,16 @@ pnfs_alloc_ds_commits_list(struct list_head *list, ...@@ -330,9 +405,16 @@ pnfs_alloc_ds_commits_list(struct list_head *list,
struct pnfs_commit_array *array; struct pnfs_commit_array *array;
unsigned int ret = 0; unsigned int ret = 0;
list_for_each_entry(array, &fl_cinfo->commits, cinfo_list) rcu_read_lock();
list_for_each_entry_rcu(array, &fl_cinfo->commits, cinfo_list) {
if (!array->lseg || !pnfs_get_commit_array(array))
continue;
rcu_read_unlock();
ret += pnfs_bucket_alloc_ds_commits(list, array->buckets, ret += pnfs_bucket_alloc_ds_commits(list, array->buckets,
array->nbuckets, cinfo); array->nbuckets, cinfo);
rcu_read_lock();
pnfs_put_commit_array(array, cinfo->inode);
}
return ret; return ret;
} }
......
...@@ -1275,6 +1275,7 @@ struct pnfs_commit_array { ...@@ -1275,6 +1275,7 @@ struct pnfs_commit_array {
struct list_head lseg_list; struct list_head lseg_list;
struct pnfs_layout_segment *lseg; struct pnfs_layout_segment *lseg;
struct rcu_head rcu; struct rcu_head rcu;
refcount_t refcount;
unsigned int nbuckets; unsigned int nbuckets;
struct pnfs_commit_bucket buckets[]; struct pnfs_commit_bucket buckets[];
}; };
......
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