From: Mr NeilBrown Date: Wed, 18 Mar 2020 02:55:19 +0000 (+1100) Subject: LU-8130 lu_object: use RCU to free lu_object_header X-Git-Tag: 2.13.53~20 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=b25e8a4bc86ee245be19dc05c085a2b0f4fe4a43 LU-8130 lu_object: use RCU to free lu_object_header 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 Change-Id: Ib0e1134ae2ac73532d6f953ff4510076f1d8a78a Reviewed-on: https://review.whamcloud.com/37965 Tested-by: jenkins Tested-by: Maloo Reviewed-by: James Simmons Reviewed-by: Shaun Tancheff Reviewed-by: Oleg Drokin --- diff --git a/Documentation/osd-api.txt b/Documentation/osd-api.txt index c4e9907..59eea26 100644 --- a/Documentation/osd-api.txt +++ b/Documentation/osd-api.txt @@ -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. diff --git a/lustre/include/lu_object.h b/lustre/include/lu_object.h index 80f6f44..65180b2 100644 --- a/lustre/include/lu_object.h +++ b/lustre/include/lu_object.h @@ -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; diff --git a/lustre/llite/vvp_object.c b/lustre/llite/vvp_object.c index 51e1bba..43e2a61 100644 --- a/lustre/llite/vvp_object.c +++ b/lustre/llite/vvp_object.c @@ -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 = { diff --git a/lustre/lod/lod_object.c b/lustre/lod/lod_object.c index c218c5e..d19f91d 100644 --- a/lustre/lod/lod_object.c +++ b/lustre/lod/lod_object.c @@ -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); } diff --git a/lustre/lov/lovsub_object.c b/lustre/lov/lovsub_object.c index d219356..0dec8de 100644 --- a/lustre/lov/lovsub_object.c +++ b/lustre/lov/lovsub_object.c @@ -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; } diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index 2f6b5ec..1313f59 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -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); } diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index d02399d..01dddad 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -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; } diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c index 90c34fd..00ec088 100644 --- a/lustre/mgs/mgs_handler.c +++ b/lustre/mgs/mgs_handler.c @@ -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, diff --git a/lustre/obdclass/local_storage.c b/lustre/obdclass/local_storage.c index bbb8ada..c5d8935 100644 --- a/lustre/obdclass/local_storage.c +++ b/lustre/obdclass/local_storage.c @@ -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 = { diff --git a/lustre/obdecho/echo_client.c b/lustre/obdecho/echo_client.c index e7eece1..9433ec9 100644 --- a/lustre/obdecho/echo_client.c +++ b/lustre/obdecho/echo_client.c @@ -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; } diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index c8a5140..cfcb420 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -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; } diff --git a/lustre/osc/osc_object.c b/lustre/osc/osc_object.c index d12b42e..f092577 100644 --- a/lustre/osc/osc_object.c +++ b/lustre/osc/osc_object.c @@ -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); diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index fdde77b..0f95bc2 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -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); } } diff --git a/lustre/osd-zfs/osd_object.c b/lustre/osd-zfs/osd_object.c index 158ad52..c41a42f 100644 --- a/lustre/osd-zfs/osd_object.c +++ b/lustre/osd-zfs/osd_object.c @@ -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); } } diff --git a/lustre/osp/osp_object.c b/lustre/osp/osp_object.c index 90a1905..b144611 100644 --- a/lustre/osp/osp_object.c +++ b/lustre/osp/osp_object.c @@ -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); } /**