OSDN Git Service

pNFS: Add infrastructure for cleaning up per-layout commit structures
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 20 Mar 2020 20:04:06 +0000 (16:04 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 27 Mar 2020 20:34:34 +0000 (16:34 -0400)
Ensure that both the file and flexfiles layout types clean up when
freeing the layout segments.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/internal.h
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/pnfs_nfs.c
include/linux/nfs_xdr.h

index b051d5d..ffc5e2a 100644 (file)
@@ -750,11 +750,16 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg)
        /* This assumes a single RW lseg */
        if (lseg->pls_range.iomode == IOMODE_RW) {
                struct nfs4_filelayout *flo;
+               struct inode *inode;
 
                flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
+               inode = flo->generic_hdr.plh_inode;
+               spin_lock(&inode->i_lock);
                flo->commit_info.nbuckets = 0;
                kfree(flo->commit_info.buckets);
                flo->commit_info.buckets = NULL;
+               pnfs_generic_ds_cinfo_release_lseg(&flo->commit_info, lseg);
+               spin_unlock(&inode->i_lock);
        }
        _filelayout_free_lseg(fl);
 }
@@ -1163,6 +1168,16 @@ filelayout_get_ds_info(struct inode *inode)
                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 = {
        .id                     = LAYOUT_NFSV4_1_FILES,
        .name                   = "LAYOUT_NFSV4_1_FILES",
@@ -1176,6 +1191,7 @@ static struct pnfs_layoutdriver_type filelayout_type = {
        .pg_read_ops            = &filelayout_pg_read_ops,
        .pg_write_ops           = &filelayout_pg_write_ops,
        .get_ds_info            = &filelayout_get_ds_info,
+       .release_ds_info        = filelayout_release_ds_info,
        .mark_request_commit    = filelayout_mark_request_commit,
        .clear_request_commit   = pnfs_generic_clear_request_commit,
        .scan_commit_lists      = pnfs_generic_scan_commit_lists,
index c9e79c8..8e1393d 100644 (file)
@@ -580,6 +580,7 @@ ff_layout_free_lseg(struct pnfs_layout_segment *lseg)
                        kfree(ffl->commit_info.buckets);
                        ffl->commit_info.buckets = NULL;
                }
+               pnfs_generic_ds_cinfo_release_lseg(&ffl->commit_info, lseg);
                spin_unlock(&inode->i_lock);
        }
        _ff_layout_free_lseg(fls);
@@ -2004,6 +2005,15 @@ ff_layout_get_ds_info(struct inode *inode)
 }
 
 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
 ff_layout_free_deviceid_node(struct nfs4_deviceid_node *d)
 {
        nfs4_ff_layout_free_deviceid(container_of(d, struct nfs4_ff_layout_ds,
@@ -2503,6 +2513,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = {
        .pg_read_ops            = &ff_layout_pg_read_ops,
        .pg_write_ops           = &ff_layout_pg_write_ops,
        .get_ds_info            = ff_layout_get_ds_info,
+       .release_ds_info        = ff_layout_release_ds_info,
        .free_deviceid_node     = ff_layout_free_deviceid_node,
        .mark_request_commit    = pnfs_layout_mark_request_commit,
        .clear_request_commit   = pnfs_generic_clear_request_commit,
index 4a1adad..683146a 100644 (file)
@@ -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,
                        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,
                                array->nbuckets);
+       rcu_read_unlock();
 }
 #else
 static inline
index 6b25117..eba18f1 100644 (file)
@@ -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_lc_list);
+       INIT_LIST_HEAD(&lseg->pls_commits);
        refcount_set(&lseg->pls_refcount, 1);
        set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
        lseg->pls_layout = lo;
index 2ec97b4..6c48bd7 100644 (file)
@@ -66,6 +66,7 @@ struct nfs4_pnfs_ds {
 struct pnfs_layout_segment {
        struct list_head pls_list;
        struct list_head pls_lc_list;
+       struct list_head pls_commits;
        struct pnfs_layout_range pls_range;
        refcount_t pls_refcount;
        u32 pls_seq;
@@ -370,6 +371,9 @@ void nfs4_deviceid_purge_client(const struct nfs_client *);
 /* pnfs_nfs.c */
 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_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,
                                       struct nfs_commit_info *cinfo);
index f895a28..edad251 100644 (file)
@@ -118,6 +118,67 @@ pnfs_free_commit_array(struct pnfs_commit_array *p)
 }
 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
  * @bucket->committing.
@@ -177,14 +238,21 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, int max)
        max -= cnt;
        if (!max)
                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,
                                array->nbuckets, max);
+               rcu_read_lock();
+               pnfs_put_commit_array(array, cinfo->inode);
                rv += cnt;
                max -= cnt;
                if (!max)
                        break;
        }
+       rcu_read_unlock();
        return rv;
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_scan_commit_lists);
@@ -230,13 +298,20 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
                                                   fl_cinfo->nbuckets,
                                                   cinfo);
        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,
                                                           array->buckets,
                                                           array->nbuckets,
                                                           cinfo);
+               rcu_read_lock();
+               pnfs_put_commit_array(array, cinfo->inode);
                fl_cinfo->nwritten -= nwritten;
        }
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
 
@@ -330,9 +405,16 @@ pnfs_alloc_ds_commits_list(struct list_head *list,
        struct pnfs_commit_array *array;
        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,
                                array->nbuckets, cinfo);
+               rcu_read_lock();
+               pnfs_put_commit_array(array, cinfo->inode);
+       }
        return ret;
 }
 
index 9946787..33be2ee 100644 (file)
@@ -1275,6 +1275,7 @@ struct pnfs_commit_array {
        struct list_head lseg_list;
        struct pnfs_layout_segment *lseg;
        struct rcu_head rcu;
+       refcount_t refcount;
        unsigned int nbuckets;
        struct pnfs_commit_bucket buckets[];
 };