Introduce simple helpers to allocate memory with a refcount. The refcount can be chained to the parent, so that it assures to keep the parent memory until all children are released.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/core.h | 5 ++++ sound/core/init.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+)
diff --git a/include/sound/core.h b/include/sound/core.h index f6e0dd648b80..6fccec08a12f 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -75,6 +75,11 @@ struct snd_device {
#define snd_device(n) list_entry(n, struct snd_device, list)
+/* referenced memory allocation */ +void *snd_refmem_alloc(size_t bytes, void *parent); +void *snd_refmem_get(void *p); +void snd_refmem_put(void *p); + /* main structure for soundcard */
struct snd_card { diff --git a/sound/core/init.c b/sound/core/init.c index baef2688d0cf..7e7c4b8d4e11 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -111,6 +111,64 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int), return mask; /* unchanged */ }
+/* + * referenced memory allocation + */ + +struct snd_refmem { + struct kref kref; + void *parent; + char data[]; +}; + +#define to_refmem(p) container_of(p, struct snd_refmem, data) + +void *snd_refmem_alloc(size_t bytes, void *parent) +{ + struct snd_refmem *ref; + + ref = kzalloc(bytes + sizeof(*ref), GFP_KERNEL); + if (!ref) + return NULL; + kref_init(&ref->kref); + ref->parent = parent; + snd_refmem_get(parent); + return ref->data; +} +EXPORT_SYMBOL_GPL(snd_refmem_alloc); + +void *snd_refmem_get(void *p) +{ + struct snd_refmem *ref; + + if (!p) + return NULL; + ref = to_refmem(p); + kref_get(&ref->kref); + return p; +} +EXPORT_SYMBOL_GPL(snd_refmem_get); + +static void snd_refmem_release(struct kref *kref) +{ + struct snd_refmem *ref = container_of(kref, struct snd_refmem, kref); + void *parent = ref->parent; + + kfree(ref); + snd_refmem_put(parent); +} + +void snd_refmem_put(void *p) +{ + struct snd_refmem *ref; + + if (!p) + return; + ref = to_refmem(p); + kref_put(&ref->kref, snd_refmem_release); +} +EXPORT_SYMBOL_GPL(snd_refmem_put); + /* the default release callback set in snd_device_initialize() below; * this is just NOP for now, as almost all jobs are already done in * dev_free callback of snd_device chain instead.