diff options
author | Christian Gromm <christian.gromm@microchip.com> | 2019-11-08 17:21:08 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-11-11 16:41:00 +0100 |
commit | 08283d30744434d8f30d386622372e8f5b03bcf2 (patch) | |
tree | c34f2411b0de27f49975720fd9e066ec08c6ee13 /drivers/staging/most | |
parent | 4845b3c8c8d221441605a1eff8aab7f1622dce93 (diff) | |
download | linux-08283d30744434d8f30d386622372e8f5b03bcf2.tar.gz linux-08283d30744434d8f30d386622372e8f5b03bcf2.tar.bz2 linux-08283d30744434d8f30d386622372e8f5b03bcf2.zip |
staging: most: block module removal while having active configfs items
This patch avoids that core component modules are being unloaded
while the related configfs interface has active items in its directories.
It is needed to prevent the situation where the core module cannot
be unloaded anymore, because the reference count 'used by' indicates that
the module is still being used and the usage count cannot be decreased by
calling rmdir, as the configfs directory has already been removed.
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Link: https://lore.kernel.org/r/1573230068-27658-3-git-send-email-christian.gromm@microchip.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/most')
-rw-r--r-- | drivers/staging/most/cdev/cdev.c | 1 | ||||
-rw-r--r-- | drivers/staging/most/configfs.c | 38 | ||||
-rw-r--r-- | drivers/staging/most/core.h | 1 | ||||
-rw-r--r-- | drivers/staging/most/net/net.c | 1 | ||||
-rw-r--r-- | drivers/staging/most/sound/sound.c | 1 | ||||
-rw-r--r-- | drivers/staging/most/video/video.c | 1 |
6 files changed, 40 insertions, 3 deletions
diff --git a/drivers/staging/most/cdev/cdev.c b/drivers/staging/most/cdev/cdev.c index 724d098aeef0..f880147c82fd 100644 --- a/drivers/staging/most/cdev/cdev.c +++ b/drivers/staging/most/cdev/cdev.c @@ -494,6 +494,7 @@ err_remove_ida: static struct cdev_component comp = { .cc = { + .mod = THIS_MODULE, .name = "cdev", .probe_channel = comp_probe, .disconnect_channel = comp_disconnect_channel, diff --git a/drivers/staging/most/configfs.c b/drivers/staging/most/configfs.c index c292dd306bb8..34a9fb53985c 100644 --- a/drivers/staging/most/configfs.c +++ b/drivers/staging/most/configfs.c @@ -395,6 +395,7 @@ static const struct config_item_type mdev_link_type = { struct most_common { struct config_group group; + struct module *mod; struct configfs_subsystem subsys; }; @@ -407,11 +408,16 @@ static struct config_item *most_common_make_item(struct config_group *group, const char *name) { struct mdev_link *mdev_link; + struct most_common *mc = to_most_common(group->cg_subsys); mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); if (!mdev_link) return ERR_PTR(-ENOMEM); + if (!try_module_get(mc->mod)) { + kfree(mdev_link); + return ERR_PTR(-ENOLCK); + } config_item_init_type_name(&mdev_link->item, name, &mdev_link_type); @@ -436,8 +442,17 @@ static struct configfs_item_operations most_common_item_ops = { .release = most_common_release, }; +static void most_common_disconnect(struct config_group *group, + struct config_item *item) +{ + struct most_common *mc = to_most_common(group->cg_subsys); + + module_put(mc->mod); +} + static struct configfs_group_operations most_common_group_ops = { .make_item = most_common_make_item, + .disconnect_notify = most_common_disconnect, }; static const struct config_item_type most_common_type = { @@ -558,13 +573,14 @@ static const struct config_item_type most_snd_grp_type = { struct most_sound { struct configfs_subsystem subsys; struct list_head soundcard_list; + struct module *mod; }; static struct config_group *most_sound_make_group(struct config_group *group, const char *name) { struct most_snd_grp *most; - struct most_sound *ms = container_of(to_configfs_subsystem(group), + struct most_sound *ms = container_of(group->cg_subsys, struct most_sound, subsys); list_for_each_entry(most, &ms->soundcard_list, list) { @@ -573,17 +589,29 @@ static struct config_group *most_sound_make_group(struct config_group *group, return ERR_PTR(-EPROTO); } } + if (!try_module_get(ms->mod)) + return ERR_PTR(-ENOLCK); most = kzalloc(sizeof(*most), GFP_KERNEL); - if (!most) + if (!most) { + module_put(ms->mod); return ERR_PTR(-ENOMEM); - + } config_group_init_type_name(&most->group, name, &most_snd_grp_type); list_add_tail(&most->list, &ms->soundcard_list); return &most->group; } +static void most_sound_disconnect(struct config_group *group, + struct config_item *item) +{ + struct most_sound *ms = container_of(group->cg_subsys, + struct most_sound, subsys); + module_put(ms->mod); +} + static struct configfs_group_operations most_sound_group_ops = { .make_group = most_sound_make_group, + .disconnect_notify = most_sound_disconnect, }; static const struct config_item_type most_sound_type = { @@ -607,12 +635,16 @@ int most_register_configfs_subsys(struct core_component *c) int ret; if (!strcmp(c->name, "cdev")) { + most_cdev.mod = c->mod; ret = configfs_register_subsystem(&most_cdev.subsys); } else if (!strcmp(c->name, "net")) { + most_net.mod = c->mod; ret = configfs_register_subsystem(&most_net.subsys); } else if (!strcmp(c->name, "video")) { + most_video.mod = c->mod; ret = configfs_register_subsystem(&most_video.subsys); } else if (!strcmp(c->name, "sound")) { + most_sound_subsys.mod = c->mod; ret = configfs_register_subsystem(&most_sound_subsys.subsys); } else { return -ENODEV; diff --git a/drivers/staging/most/core.h b/drivers/staging/most/core.h index 652aaa771029..49859aef98df 100644 --- a/drivers/staging/most/core.h +++ b/drivers/staging/most/core.h @@ -265,6 +265,7 @@ struct most_interface { struct core_component { struct list_head list; const char *name; + struct module *mod; int (*probe_channel)(struct most_interface *iface, int channel_idx, struct most_channel_config *cfg, char *name, char *param); diff --git a/drivers/staging/most/net/net.c b/drivers/staging/most/net/net.c index 26a31854c636..6cab1bb8956e 100644 --- a/drivers/staging/most/net/net.c +++ b/drivers/staging/most/net/net.c @@ -498,6 +498,7 @@ put_nd: } static struct core_component comp = { + .mod = THIS_MODULE, .name = "net", .probe_channel = comp_probe_channel, .disconnect_channel = comp_disconnect_channel, diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c index 79817061fcfa..1359f289ffd5 100644 --- a/drivers/staging/most/sound/sound.c +++ b/drivers/staging/most/sound/sound.c @@ -782,6 +782,7 @@ static int audio_tx_completion(struct most_interface *iface, int channel_id) * Initialization of the struct core_component */ static struct core_component comp = { + .mod = THIS_MODULE, .name = DRIVER_NAME, .probe_channel = audio_probe_channel, .disconnect_channel = audio_disconnect_channel, diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index 250af9fb704d..10c1ef7e3a3e 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -528,6 +528,7 @@ static int comp_disconnect_channel(struct most_interface *iface, } static struct core_component comp = { + .mod = THIS_MODULE, .name = "video", .probe_channel = comp_probe_channel, .disconnect_channel = comp_disconnect_channel, |