diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 76169e41d4e5..ed9e7e740d80 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -61,6 +61,10 @@
#include <linux/slab.h>
#include <linux/hashtable.h>
+#if defined(DA_OBJ_EMBEDDED_TYPE) && RV_MON_TYPE != RV_MON_PER_OBJ
+#error "DA_OBJ_EMBEDDED_TYPE is only supported by RV_MON_PER_OBJ monitors"
+#endif
+
/*
* Per-cpu variables require a unique name although static in some
* configurations (e.g. CONFIG_DEBUG_FORCE_WEAK_PER_CPU or alpha modules).
@@ -453,9 +457,24 @@ static inline void da_monitor_destroy(void)
* Functions to define, init and get a per-object monitor.
*/
+#ifdef DA_OBJ_EMBEDDED_TYPE
+/*
+ * Framework-owned target: one instance is embedded in each storage and
+ * allocated/freed with it. monitor_target keeps pointer semantics, but
+ * da_get_target() points into the storage rather than to a borrowed object.
+ * The header derives the typedef: do not define monitor_target by hand.
+ */
+typedef DA_OBJ_EMBEDDED_TYPE * monitor_target;
+#endif
+
struct da_monitor_storage {
da_id_type id;
+#ifdef DA_OBJ_EMBEDDED_TYPE
+ DA_OBJ_EMBEDDED_TYPE target;
+ bool filled;
+#else
monitor_target target;
+#endif
union rv_task_monitor rv;
struct hlist_node node;
struct rcu_head rcu;@@ -466,6 +485,40 @@ struct da_monitor_storage {
#endif
static DEFINE_HASHTABLE(da_monitor_ht, DA_MONITOR_HT_BITS);
+#ifdef DA_OBJ_EMBEDDED_TYPE
+
+#define TARGET_PTR(storage) (&(storage)->target)
+
+static inline bool da_storage_is_empty(struct da_monitor_storage *mon_storage)
+{
+ /* Pairs with smp_store_release in da_storage_set_target(). */
+ return !smp_load_acquire(&mon_storage->filled);
+}
+static inline void da_storage_set_target(struct da_monitor_storage *mon_storage,
+ monitor_target target)
+{
+ if (WARN_ON_ONCE(!target))
+ return;
+
+ memcpy(&mon_storage->target, target, sizeof(mon_storage->target));
+ /* Pairs with smp_load_acquire in da_storage_is_empty(). */
+ smp_store_release(&mon_storage->filled, true);
+}
+#else
+
+#define TARGET_PTR(storage) storage->target
+
+static inline bool da_storage_is_empty(struct da_monitor_storage *mon_storage)
+{
+ return !TARGET_PTR(mon_storage);
+}
+static inline void da_storage_set_target(struct da_monitor_storage *mon_storage,
+ monitor_target target)
+{
+ mon_storage->target = target;
+}
+#endif
+
/*
* da_create_empty_storage - pre-allocate an empty storage
*/@@ -503,7 +556,7 @@ static inline struct da_monitor *da_create_storage(da_id_type id,
if (!mon_storage)
return NULL;
- mon_storage->target = target;
+ da_storage_set_target(mon_storage, target);
return &mon_storage->rv.da_mon;
}
@@ -536,10 +589,20 @@ static struct da_monitor *da_get_monitor(da_id_type id, monitor_target target)
/*
* da_get_target - return the object associated to the monitor
+ *
+ * NULL for an embedded target whose storage was pre-allocated but not filled
+ * yet: a manual-allocation monitor publishes its storage before it has one.
*/
static inline monitor_target da_get_target(struct da_monitor *da_mon)
{
- return container_of(da_mon, struct da_monitor_storage, rv.da_mon)->target;
+ struct da_monitor_storage *mon_storage =
+ container_of(da_mon, struct da_monitor_storage, rv.da_mon);
+
+#ifdef DA_OBJ_EMBEDDED_TYPE
+ if (unlikely(da_storage_is_empty(mon_storage)))
+ return NULL;
+#endif
+ return TARGET_PTR(mon_storage);
}
/*@@ -572,8 +635,11 @@ static inline struct da_monitor *da_fill_empty_storage(da_id_type id,
monitor_target target,
struct da_monitor *da_mon)
{
- if (unlikely(da_mon && !da_get_target(da_mon)))
- container_of(da_mon, struct da_monitor_storage, rv.da_mon)->target = target;
+ struct da_monitor_storage *mon_storage =
+ container_of(da_mon, struct da_monitor_storage, rv.da_mon);
+
+ if (unlikely(da_mon && da_storage_is_empty(mon_storage)))
+ da_storage_set_target(mon_storage, target);
return da_mon;
}
@@ -589,7 +655,11 @@ static inline monitor_target da_get_target_by_id(da_id_type id)
if (unlikely(!mon_storage))
return NULL;
- return mon_storage->target;
+#ifdef DA_OBJ_EMBEDDED_TYPE
+ if (unlikely(da_storage_is_empty(mon_storage)))
+ return NULL;
+#endif
+ return TARGET_PTR(mon_storage);
}
static void da_kfree_cb(struct rcu_head *head)
@@ -635,7 +705,7 @@ da_create_pool_storage(da_id_type id, monitor_target target,
memset(mon_storage, 0, sizeof(*mon_storage));
mon_storage->id = id;
- mon_storage->target = target;
+ da_storage_set_target(mon_storage, target);
hash_add_rcu(da_monitor_ht, &mon_storage->node, id);
return &mon_storage->rv.da_mon;
--
2.25.1