Whamcloud - gitweb
LU-8130 lu_object: use RCU to free lu_object_header 65/37965/2
authorMr NeilBrown <neilb@suse.de>
Wed, 18 Mar 2020 02:55:19 +0000 (13:55 +1100)
committerOleg Drokin <green@whamcloud.com>
Tue, 31 Mar 2020 06:59:58 +0000 (06:59 +0000)
Any struct containing an lu_object_header is now freed using
call_rcu() or rcu_kfree() when freed by loo_object_free.

This will allow RCU protocols to protect lookups once we
switch the lu_object cache to rhashtable in a future patch.

Signed-off-by: Mr NeilBrown <neilb@suse.de>
Change-Id: Ib0e1134ae2ac73532d6f953ff4510076f1d8a78a
Reviewed-on: https://review.whamcloud.com/37965
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Shaun Tancheff <shaun.tancheff@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
15 files changed:
Documentation/osd-api.txt
lustre/include/lu_object.h
lustre/llite/vvp_object.c
lustre/lod/lod_object.c
lustre/lov/lovsub_object.c
lustre/mdd/mdd_object.c
lustre/mdt/mdt_handler.c
lustre/mgs/mgs_handler.c
lustre/obdclass/local_storage.c
lustre/obdecho/echo_client.c
lustre/ofd/ofd_dev.c
lustre/osc/osc_object.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-zfs/osd_object.c
lustre/osp/osp_object.c

index c4e9907..59eea26 100644 (file)
@@ -514,6 +514,8 @@ loo_object_delete
        during potentially stack consuming resource release.
 loo_object_free
        is called to actually release memory allocated by ->ldo->object_alloc()
+       If the object contains a struct lu_object_header, then it must be
+       freed by call_rcu() or rcu_kfree().
 loo_object_release
        is called when object last it’s last user and moves onto LRU list of
        unused objects. implementation of this method is optional to OSD.
index 80f6f44..65180b2 100644 (file)
@@ -224,12 +224,13 @@ struct lu_object_operations {
          */
         void (*loo_object_delete)(const struct lu_env *env,
                                   struct lu_object *o);
-        /**
-         * Dual to lu_device_operations::ldo_object_alloc(). Called when
-         * object is removed from memory.
-         */
-        void (*loo_object_free)(const struct lu_env *env,
-                                struct lu_object *o);
+       /**
+        * Dual to lu_device_operations::ldo_object_alloc(). Called when
+        * object is removed from memory.  Must use call_rcu or kfree_rcu
+        * if the object contains an lu_object_header.
+        */
+       void (*loo_object_free)(const struct lu_env *env,
+                               struct lu_object *o);
         /**
          * Called when last active reference to the object is released (and
          * object returns to the cache). This method is optional.
@@ -535,6 +536,10 @@ struct lu_object_header {
         * A list of references to this object, for debugging.
         */
        struct lu_ref           loh_reference;
+       /*
+        * Handle used for kfree_rcu() or similar.
+        */
+       struct rcu_head         loh_rcu;
 };
 
 struct fld;
index 51e1bba..43e2a61 100644 (file)
@@ -266,13 +266,22 @@ static int vvp_object_init(const struct lu_env *env, struct lu_object *obj,
        return result;
 }
 
+static void vvp_object_free_rcu(struct rcu_head *head)
+{
+       struct vvp_object *vob = container_of(head, struct vvp_object,
+                                             vob_header.coh_lu.loh_rcu);
+
+       kmem_cache_free(vvp_object_kmem, vob);
+}
+
 static void vvp_object_free(const struct lu_env *env, struct lu_object *obj)
 {
        struct vvp_object *vob = lu2vvp(obj);
 
        lu_object_fini(obj);
        lu_object_header_fini(obj->lo_header);
-       OBD_SLAB_FREE_PTR(vob, vvp_object_kmem);
+       OBD_FREE_PRE(vob, sizeof(*vob), "slab-freed");
+       call_rcu(&vob->vob_header.coh_lu.loh_rcu, vvp_object_free_rcu);
 }
 
 static const struct lu_object_operations vvp_lu_obj_ops = {
index c218c5e..d19f91d 100644 (file)
@@ -8463,6 +8463,7 @@ static void lod_object_free(const struct lu_env *env, struct lu_object *o)
        /* release all underlying object pinned */
        lod_striping_free(env, lo);
        lu_object_fini(o);
+       /* lo doesn't contain a lu_object_header, so we don't need call_rcu */
        OBD_SLAB_FREE_PTR(lo, lod_object_kmem);
 }
 
index d219356..0dec8de 100644 (file)
@@ -70,6 +70,14 @@ int lovsub_object_init(const struct lu_env *env, struct lu_object *obj,
 
 }
 
+static void lovsub_object_free_rcu(struct rcu_head *head)
+{
+       struct lovsub_object *los = container_of(head, struct lovsub_object,
+                                                lso_header.coh_lu.loh_rcu);
+
+       kmem_cache_free(lovsub_object_kmem, los);
+}
+
 static void lovsub_object_free(const struct lu_env *env, struct lu_object *obj)
 {
        struct lovsub_object *los = lu2lovsub(obj);
@@ -95,7 +103,8 @@ static void lovsub_object_free(const struct lu_env *env, struct lu_object *obj)
 
        lu_object_fini(obj);
        lu_object_header_fini(&los->lso_header.coh_lu);
-       OBD_SLAB_FREE_PTR(los, lovsub_object_kmem);
+       OBD_FREE_PRE(los, sizeof(*los), "slab-freed");
+       call_rcu(&los->lso_header.coh_lu.loh_rcu, lovsub_object_free_rcu);
        EXIT;
 }
 
index 2f6b5ec..1313f59 100644 (file)
@@ -335,6 +335,7 @@ static void mdd_object_free(const struct lu_env *env, struct lu_object *o)
        }
 
        lu_object_fini(o);
+       /* mdd doesn't contain an lu_object_header, so don't need call_rcu */
        OBD_SLAB_FREE_PTR(mdd, mdd_object_kmem);
 }
 
index d02399d..01dddad 100644 (file)
@@ -5775,22 +5775,31 @@ static int mdt_object_init(const struct lu_env *env, struct lu_object *o,
         RETURN(rc);
 }
 
+static void mdt_object_free_rcu(struct rcu_head *head)
+{
+       struct mdt_object *mo = container_of(head, struct mdt_object,
+                                            mot_header.loh_rcu);
+
+       kmem_cache_free(mdt_object_kmem, mo);
+}
+
 static void mdt_object_free(const struct lu_env *env, struct lu_object *o)
 {
-        struct mdt_object *mo = mdt_obj(o);
-        struct lu_object_header *h;
-        ENTRY;
+       struct mdt_object *mo = mdt_obj(o);
+       struct lu_object_header *h;
+       ENTRY;
 
-        h = o->lo_header;
-        CDEBUG(D_INFO, "object free, fid = "DFID"\n",
-               PFID(lu_object_fid(o)));
+       h = o->lo_header;
+       CDEBUG(D_INFO, "object free, fid = "DFID"\n",
+              PFID(lu_object_fid(o)));
 
        LASSERT(atomic_read(&mo->mot_open_count) == 0);
        LASSERT(atomic_read(&mo->mot_lease_count) == 0);
 
        lu_object_fini(o);
        lu_object_header_fini(h);
-       OBD_SLAB_FREE_PTR(mo, mdt_object_kmem);
+       OBD_FREE_PRE(mo, sizeof(*mo), "slab-freed");
+       call_rcu(&mo->mot_header.loh_rcu, mdt_object_free_rcu);
 
        EXIT;
 }
index 90c34fd..00ec088 100644 (file)
@@ -1487,7 +1487,8 @@ static void mgs_object_free(const struct lu_env *env, struct lu_object *o)
 
        dt_object_fini(&obj->mgo_obj);
        lu_object_header_fini(h);
-       OBD_FREE_PTR(obj);
+       OBD_FREE_PRE(obj, sizeof(*obj), "kfreed");
+       kfree_rcu(obj, mgo_header.loh_rcu);
 }
 
 static int mgs_object_print(const struct lu_env *env, void *cookie,
index bbb8ada..c5d8935 100644 (file)
@@ -65,7 +65,8 @@ static void ls_object_free(const struct lu_env *env, struct lu_object *o)
 
        dt_object_fini(&obj->ls_obj);
        lu_object_header_fini(h);
-       OBD_FREE_PTR(obj);
+       OBD_FREE_PRE(obj, sizeof(*obj), "kfreed");
+       kfree_rcu(obj, ls_header.loh_rcu);
 }
 
 static struct lu_object_operations ls_lu_obj_ops = {
index e7eece1..9433ec9 100644 (file)
@@ -545,6 +545,14 @@ static void echo_object_delete(const struct lu_env *env, struct lu_object *obj)
                OBD_FREE_PTR(eco->eo_oinfo);
 }
 
+static void echo_object_free_rcu(struct rcu_head *head)
+{
+       struct echo_object *eco = container_of(head, struct echo_object,
+                                              eo_hdr.coh_lu.loh_rcu);
+
+       kmem_cache_free(echo_object_kmem, eco);
+}
+
 static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
 {
        struct echo_object *eco    = cl2echo_obj(lu2cl(obj));
@@ -554,7 +562,8 @@ static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
        lu_object_fini(obj);
        lu_object_header_fini(obj->lo_header);
 
-       OBD_SLAB_FREE_PTR(eco, echo_object_kmem);
+       OBD_FREE_PRE(eco, sizeof(*eco), "slab-freed");
+       call_rcu(&eco->eo_hdr.coh_lu.loh_rcu, echo_object_free_rcu);
        EXIT;
 }
 
index c8a5140..cfcb420 100644 (file)
@@ -455,6 +455,14 @@ static int ofd_object_init(const struct lu_env *env, struct lu_object *o,
        RETURN(rc);
 }
 
+static void ofd_object_free_rcu(struct rcu_head *head)
+{
+       struct ofd_object *of = container_of(head, struct ofd_object,
+                                            ofo_header.loh_rcu);
+
+       kmem_cache_free(ofd_object_kmem, of);
+}
+
 /**
  * Implementation of lu_object_operations::loo_object_free.
  *
@@ -476,7 +484,8 @@ static void ofd_object_free(const struct lu_env *env, struct lu_object *o)
 
        lu_object_fini(o);
        lu_object_header_fini(h);
-       OBD_SLAB_FREE_PTR(of, ofd_object_kmem);
+       OBD_FREE_PRE(of, sizeof(*of), "slab-freed");
+       call_rcu(&of->ofo_header.loh_rcu, ofd_object_free_rcu);
        EXIT;
 }
 
index d12b42e..f092577 100644 (file)
@@ -118,6 +118,7 @@ void osc_object_free(const struct lu_env *env, struct lu_object *obj)
        LASSERT(atomic_read(&osc->oo_nr_ios) == 0);
 
        lu_object_fini(obj);
+       /* osc doen't contain an lu_object_header, so we don't need call_rcu */
        OBD_SLAB_FREE_PTR(osc, osc_object_kmem);
 }
 EXPORT_SYMBOL(osc_object_free);
index fdde77b..0f95bc2 100644 (file)
@@ -1580,10 +1580,12 @@ static void osd_object_free(const struct lu_env *env, struct lu_object *l)
        dt_object_fini(&obj->oo_dt);
        if (obj->oo_hl_head != NULL)
                ldiskfs_htree_lock_head_free(obj->oo_hl_head);
+       /* obj doesn't contain an lu_object_header, so we don't need call_rcu */
        OBD_FREE_PTR(obj);
        if (unlikely(h)) {
                lu_object_header_fini(h);
-               OBD_FREE_PTR(h);
+               OBD_FREE_PRE(h, sizeof(*h), "kfreed");
+               kfree_rcu(h, loh_rcu);
        }
 }
 
index 158ad52..c41a42f 100644 (file)
@@ -694,10 +694,12 @@ static void osd_object_free(const struct lu_env *env, struct lu_object *l)
        LASSERT(osd_invariant(obj));
 
        dt_object_fini(&obj->oo_dt);
+       /* obj doesn't contain an lu_object_header, so we don't need call_rcu */
        OBD_SLAB_FREE_PTR(obj, osd_object_kmem);
        if (unlikely(h)) {
                lu_object_header_fini(h);
-               OBD_FREE_PTR(h);
+               OBD_FREE_PRE(h, sizeof(*h), "kfreed");
+               kfree_rcu(h, loh_rcu);
        }
 }
 
index 90a1905..b144611 100644 (file)
@@ -2272,6 +2272,14 @@ static int osp_object_init(const struct lu_env *env, struct lu_object *o,
        RETURN(rc);
 }
 
+static void osp_object_free_rcu(struct rcu_head *head)
+{
+       struct osp_object *obj = container_of(head, struct osp_object,
+                                             opo_header.loh_rcu);
+
+       kmem_cache_free(osp_object_kmem, obj);
+}
+
 /**
  * Implement OSP layer lu_object_operations::loo_object_free() interface.
  *
@@ -2302,7 +2310,8 @@ static void osp_object_free(const struct lu_env *env, struct lu_object *o)
 
                OBD_FREE(oxe, oxe->oxe_buflen);
        }
-       OBD_SLAB_FREE_PTR(obj, osp_object_kmem);
+       OBD_FREE_PRE(obj, sizeof(*obj), "slab-freed");
+       call_rcu(&obj->opo_header.loh_rcu, osp_object_free_rcu);
 }
 
 /**