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:
during potentially stack consuming resource release.
loo_object_free
is called to actually release memory allocated by ->ldo->object_alloc()
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.
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.
*/
void (*loo_object_delete)(const struct lu_env *env,
struct lu_object *o);
*/
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.
/**
* Called when last active reference to the object is released (and
* object returns to the cache). This method is optional.
* A list of references to this object, for debugging.
*/
struct lu_ref loh_reference;
* 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;
+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);
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 = {
}
static const struct lu_object_operations vvp_lu_obj_ops = {
/* release all underlying object pinned */
lod_striping_free(env, lo);
lu_object_fini(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);
}
OBD_SLAB_FREE_PTR(lo, lod_object_kmem);
}
+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);
static void lovsub_object_free(const struct lu_env *env, struct lu_object *obj)
{
struct lovsub_object *los = lu2lovsub(obj);
lu_object_fini(obj);
lu_object_header_fini(&los->lso_header.coh_lu);
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);
+ /* mdd doesn't contain an lu_object_header, so don't need call_rcu */
OBD_SLAB_FREE_PTR(mdd, mdd_object_kmem);
}
OBD_SLAB_FREE_PTR(mdd, mdd_object_kmem);
}
+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)
{
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);
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);
dt_object_fini(&obj->mgo_obj);
lu_object_header_fini(h);
dt_object_fini(&obj->mgo_obj);
lu_object_header_fini(h);
+ 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,
}
static int mgs_object_print(const struct lu_env *env, void *cookie,
dt_object_fini(&obj->ls_obj);
lu_object_header_fini(h);
dt_object_fini(&obj->ls_obj);
lu_object_header_fini(h);
+ OBD_FREE_PRE(obj, sizeof(*obj), "kfreed");
+ kfree_rcu(obj, ls_header.loh_rcu);
}
static struct lu_object_operations ls_lu_obj_ops = {
}
static struct lu_object_operations ls_lu_obj_ops = {
OBD_FREE_PTR(eco->eo_oinfo);
}
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));
static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
{
struct echo_object *eco = cl2echo_obj(lu2cl(obj));
lu_object_fini(obj);
lu_object_header_fini(obj->lo_header);
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);
+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.
*
/**
* Implementation of lu_object_operations::loo_object_free.
*
lu_object_fini(o);
lu_object_header_fini(h);
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);
LASSERT(atomic_read(&osc->oo_nr_ios) == 0);
lu_object_fini(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);
OBD_SLAB_FREE_PTR(osc, osc_object_kmem);
}
EXPORT_SYMBOL(osc_object_free);
dt_object_fini(&obj->oo_dt);
if (obj->oo_hl_head != NULL)
ldiskfs_htree_lock_head_free(obj->oo_hl_head);
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(obj);
if (unlikely(h)) {
lu_object_header_fini(h);
+ OBD_FREE_PRE(h, sizeof(*h), "kfreed");
+ kfree_rcu(h, loh_rcu);
LASSERT(osd_invariant(obj));
dt_object_fini(&obj->oo_dt);
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_SLAB_FREE_PTR(obj, osd_object_kmem);
if (unlikely(h)) {
lu_object_header_fini(h);
+ OBD_FREE_PRE(h, sizeof(*h), "kfreed");
+ kfree_rcu(h, loh_rcu);
+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.
*
/**
* Implement OSP layer lu_object_operations::loo_object_free() interface.
*
OBD_FREE(oxe, oxe->oxe_buflen);
}
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);