| From foo@baz Sat Nov 10 10:51:03 PST 2018 |
| From: Javier González <javier@cnexlabs.com> |
| Date: Tue, 9 Oct 2018 13:12:07 +0200 |
| Subject: lightnvm: pblk: fix race on sysfs line state |
| |
| From: Javier González <javier@cnexlabs.com> |
| |
| [ Upstream commit 44cdbdc657b23f75736eca3e88b781f009104363 ] |
| |
| pblk exposes a sysfs interface that represents its internal state. Part |
| of this state is the map bitmap for the current open line, which should |
| be protected by the line lock to avoid a race when freeing the line |
| metadata. Currently, it is not. |
| |
| This patch makes sure that the line state is consistent and NULL |
| bitmap pointers are not dereferenced. |
| |
| Signed-off-by: Javier González <javier@cnexlabs.com> |
| Signed-off-by: Matias Bjørling <mb@lightnvm.io> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/lightnvm/pblk-core.c | 5 +++-- |
| drivers/lightnvm/pblk-sysfs.c | 8 +++++++- |
| 2 files changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/lightnvm/pblk-core.c |
| +++ b/drivers/lightnvm/pblk-core.c |
| @@ -1539,13 +1539,14 @@ struct pblk_line *pblk_line_replace_data |
| struct pblk_line *cur, *new = NULL; |
| unsigned int left_seblks; |
| |
| - cur = l_mg->data_line; |
| new = l_mg->data_next; |
| if (!new) |
| goto out; |
| - l_mg->data_line = new; |
| |
| spin_lock(&l_mg->free_lock); |
| + cur = l_mg->data_line; |
| + l_mg->data_line = new; |
| + |
| pblk_line_setup_metadata(new, l_mg, &pblk->lm); |
| spin_unlock(&l_mg->free_lock); |
| |
| --- a/drivers/lightnvm/pblk-sysfs.c |
| +++ b/drivers/lightnvm/pblk-sysfs.c |
| @@ -262,8 +262,14 @@ static ssize_t pblk_sysfs_lines(struct p |
| sec_in_line = l_mg->data_line->sec_in_line; |
| meta_weight = bitmap_weight(&l_mg->meta_bitmap, |
| PBLK_DATA_LINES); |
| - map_weight = bitmap_weight(l_mg->data_line->map_bitmap, |
| + |
| + spin_lock(&l_mg->data_line->lock); |
| + if (l_mg->data_line->map_bitmap) |
| + map_weight = bitmap_weight(l_mg->data_line->map_bitmap, |
| lm->sec_per_line); |
| + else |
| + map_weight = 0; |
| + spin_unlock(&l_mg->data_line->lock); |
| } |
| spin_unlock(&l_mg->free_lock); |
| |