ALSA: core: Remove child proc file elements recursively
This patch changes the way to manage the resource release of proc files: namely, let snd_info_free_entry() freeing the whole children. This makes it us possible to drop the snd_device_*() management. Then snd_card_proc_new() becomes merely a wrapper to snd_info_create_card_entry(). Together with this change, now you need to call snd_info_free_entry() for a proc entry created via snd_card_proc_new(), while it was freed via snd_device_free() beforehand. Acked-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
					parent
					
						
							
								886364f679
							
						
					
				
			
			
				commit
				
					
						c560a6797e
					
				
			
		
					 3 changed files with 21 additions and 69 deletions
				
			
		|  | @ -24,6 +24,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/poll.h> | #include <linux/poll.h> | ||||||
| #include <linux/seq_file.h> | #include <linux/seq_file.h> | ||||||
|  | #include <sound/core.h> | ||||||
| 
 | 
 | ||||||
| /* buffer for information */ | /* buffer for information */ | ||||||
| struct snd_info_buffer { | struct snd_info_buffer { | ||||||
|  | @ -146,8 +147,12 @@ void snd_info_card_id_change(struct snd_card *card); | ||||||
| int snd_info_register(struct snd_info_entry *entry); | int snd_info_register(struct snd_info_entry *entry); | ||||||
| 
 | 
 | ||||||
| /* for card drivers */ | /* for card drivers */ | ||||||
| int snd_card_proc_new(struct snd_card *card, const char *name, | static inline int snd_card_proc_new(struct snd_card *card, const char *name, | ||||||
| 		      struct snd_info_entry **entryp); | 				    struct snd_info_entry **entryp) | ||||||
|  | { | ||||||
|  | 	*entryp = snd_info_create_card_entry(card, name, card->proc_root); | ||||||
|  | 	return *entryp ? 0 : -ENOMEM; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| static inline void snd_info_set_text_ops(struct snd_info_entry *entry,  | static inline void snd_info_set_text_ops(struct snd_info_entry *entry,  | ||||||
| 	void *private_data, | 	void *private_data, | ||||||
|  |  | ||||||
|  | @ -760,92 +760,39 @@ EXPORT_SYMBOL(snd_info_create_card_entry); | ||||||
| 
 | 
 | ||||||
| static void snd_info_disconnect(struct snd_info_entry *entry) | static void snd_info_disconnect(struct snd_info_entry *entry) | ||||||
| { | { | ||||||
| 	struct list_head *p, *n; | 	struct snd_info_entry *p, *n; | ||||||
| 
 | 
 | ||||||
| 	list_for_each_safe(p, n, &entry->children) { | 	if (!entry->p) | ||||||
| 		snd_info_disconnect(list_entry(p, struct snd_info_entry, list)); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (! entry->p) |  | ||||||
| 		return; | 		return; | ||||||
|  | 	list_for_each_entry_safe(p, n, &entry->children, list) | ||||||
|  | 		snd_info_disconnect(p); | ||||||
| 	list_del_init(&entry->list); | 	list_del_init(&entry->list); | ||||||
| 	proc_remove(entry->p); | 	proc_remove(entry->p); | ||||||
| 	entry->p = NULL; | 	entry->p = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_info_dev_free_entry(struct snd_device *device) |  | ||||||
| { |  | ||||||
| 	struct snd_info_entry *entry = device->device_data; |  | ||||||
| 	snd_info_free_entry(entry); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_info_dev_register_entry(struct snd_device *device) |  | ||||||
| { |  | ||||||
| 	struct snd_info_entry *entry = device->device_data; |  | ||||||
| 	return snd_info_register(entry); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * snd_card_proc_new - create an info entry for the given card |  | ||||||
|  * @card: the card instance |  | ||||||
|  * @name: the file name |  | ||||||
|  * @entryp: the pointer to store the new info entry |  | ||||||
|  * |  | ||||||
|  * Creates a new info entry and assigns it to the given card. |  | ||||||
|  * Unlike snd_info_create_card_entry(), this function registers the |  | ||||||
|  * info entry as an ALSA device component, so that it can be |  | ||||||
|  * unregistered/released without explicit call. |  | ||||||
|  * Also, you don't have to register this entry via snd_info_register(), |  | ||||||
|  * since this will be registered by snd_card_register() automatically. |  | ||||||
|  * |  | ||||||
|  * The parent is assumed as card->proc_root. |  | ||||||
|  * |  | ||||||
|  * For releasing this entry, use snd_device_free() instead of |  | ||||||
|  * snd_info_free_entry().  |  | ||||||
|  * |  | ||||||
|  * Return: Zero if successful, or a negative error code on failure. |  | ||||||
|  */ |  | ||||||
| int snd_card_proc_new(struct snd_card *card, const char *name, |  | ||||||
| 		      struct snd_info_entry **entryp) |  | ||||||
| { |  | ||||||
| 	static struct snd_device_ops ops = { |  | ||||||
| 		.dev_free = snd_info_dev_free_entry, |  | ||||||
| 		.dev_register =	snd_info_dev_register_entry, |  | ||||||
| 		/* disconnect is done via snd_info_card_disconnect() */ |  | ||||||
| 	}; |  | ||||||
| 	struct snd_info_entry *entry; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	entry = snd_info_create_card_entry(card, name, card->proc_root); |  | ||||||
| 	if (! entry) |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 	if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) { |  | ||||||
| 		snd_info_free_entry(entry); |  | ||||||
| 		return err; |  | ||||||
| 	} |  | ||||||
| 	if (entryp) |  | ||||||
| 		*entryp = entry; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| EXPORT_SYMBOL(snd_card_proc_new); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * snd_info_free_entry - release the info entry |  * snd_info_free_entry - release the info entry | ||||||
|  * @entry: the info entry |  * @entry: the info entry | ||||||
|  * |  * | ||||||
|  * Releases the info entry.  Don't call this after registered. |  * Releases the info entry. | ||||||
|  */ |  */ | ||||||
| void snd_info_free_entry(struct snd_info_entry * entry) | void snd_info_free_entry(struct snd_info_entry * entry) | ||||||
| { | { | ||||||
| 	if (entry == NULL) | 	struct snd_info_entry *p, *n; | ||||||
|  | 
 | ||||||
|  | 	if (!entry) | ||||||
| 		return; | 		return; | ||||||
| 	if (entry->p) { | 	if (entry->p) { | ||||||
| 		mutex_lock(&info_mutex); | 		mutex_lock(&info_mutex); | ||||||
| 		snd_info_disconnect(entry); | 		snd_info_disconnect(entry); | ||||||
| 		mutex_unlock(&info_mutex); | 		mutex_unlock(&info_mutex); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	/* free all children at first */ | ||||||
|  | 	list_for_each_entry_safe(p, n, &entry->children, list) | ||||||
|  | 		snd_info_free_entry(p); | ||||||
|  | 
 | ||||||
| 	kfree(entry->name); | 	kfree(entry->name); | ||||||
| 	if (entry->private_free) | 	if (entry->private_free) | ||||||
| 		entry->private_free(entry); | 		entry->private_free(entry); | ||||||
|  |  | ||||||
|  | @ -592,7 +592,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) | ||||||
| static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) | static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) | ||||||
| { | { | ||||||
| 	if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { | 	if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { | ||||||
| 		snd_device_free(per_pin->codec->card, per_pin->proc_entry); | 		snd_info_free_entry(per_pin->proc_entry); | ||||||
| 		per_pin->proc_entry = NULL; | 		per_pin->proc_entry = NULL; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Takashi Iwai
				Takashi Iwai