diff options
author | Christian Gromm <christian.gromm@microchip.com> | 2020-01-23 16:38:22 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-01-24 10:08:41 +0100 |
commit | f9e6b51a998da782cfc201dc9309d3a3d8579fef (patch) | |
tree | 237b69ed9111f03a2a046a26f9a199a69e76bf51 /drivers/staging | |
parent | b7935e52dd98696a8c1379f5b67b0c344ee3bc35 (diff) |
staging: next: configfs: fix release link
The functions link_destroy and link_release are both deleting list items.
link_release, however, does not check whether a certain link has already
been deleted from the list by function link_destroy. By fixing this
this patch prevents a kernel crash when removing the configuration
directory of a link that already has been destroyed.
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Link: https://lore.kernel.org/r/1579793906-5054-7-git-send-email-christian.gromm@microchip.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/most/configfs.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/drivers/staging/most/configfs.c b/drivers/staging/most/configfs.c index 034ab96ef69e..9a961222f458 100644 --- a/drivers/staging/most/configfs.c +++ b/drivers/staging/most/configfs.c @@ -128,6 +128,8 @@ static ssize_t mdev_link_create_link_store(struct config_item *item, return ret; list_add_tail(&mdev_link->list, &mdev_link_list); mdev_link->create_link = tmp; + mdev_link->destroy_link = false; + return count; } @@ -143,13 +145,16 @@ static ssize_t mdev_link_destroy_link_store(struct config_item *item, return ret; if (!tmp) return count; - mdev_link->destroy_link = tmp; + ret = most_remove_link(mdev_link->device, mdev_link->channel, mdev_link->comp); if (ret) return ret; if (!list_empty(&mdev_link_list)) list_del(&mdev_link->list); + + mdev_link->destroy_link = tmp; + return count; } @@ -378,13 +383,20 @@ static void mdev_link_release(struct config_item *item) struct mdev_link *mdev_link = to_mdev_link(item); int ret; - if (!list_empty(&mdev_link_list)) { - ret = most_remove_link(mdev_link->device, mdev_link->channel, - mdev_link->comp); - if (ret && (ret != -ENODEV)) - pr_err("Removing link failed.\n"); - list_del(&mdev_link->list); + if (mdev_link->destroy_link) + goto free_item; + + ret = most_remove_link(mdev_link->device, mdev_link->channel, + mdev_link->comp); + if (ret) { + pr_err("Removing link failed.\n"); + goto free_item; } + + if (!list_empty(&mdev_link_list)) + list_del(&mdev_link->list); + +free_item: kfree(to_mdev_link(item)); } |