summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Kuai <yukuai3@huawei.com>2024-01-09 21:39:57 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-02-27 04:10:53 -0800
commit8fab939c5d62e9c64bc89ea514f2e7ed886cb671 (patch)
treee237a52c392c50ae243161339b9bb584053fb4b2
parent4b79bee3e3c0b66b18fbb6187d68927366c8f3b5 (diff)
downloadlinux-8fab939c5d62e9c64bc89ea514f2e7ed886cb671.tar.gz
linux-8fab939c5d62e9c64bc89ea514f2e7ed886cb671.tar.bz2
linux-8fab939c5d62e9c64bc89ea514f2e7ed886cb671.zip
md: Fix md_seq_ops() regressions
commit f9cfe7e7f96a9414a17d596e288693c4f2325d49 upstream. Commit cf1b6d4441ff ("md: simplify md_seq_ops") introduce following regressions: 1) If list all_mddevs is emptly, personalities and unused devices won't be showed to user anymore. 2) If seq_file buffer overflowed from md_seq_show(), then md_seq_start() will be called again, hence personalities will be showed to user again. 3) If seq_file buffer overflowed from md_seq_stop(), seq_read_iter() doesn't handle this, hence unused devices won't be showed to user. Fix above problems by printing personalities and unused devices in md_seq_show(). Fixes: cf1b6d4441ff ("md: simplify md_seq_ops") Cc: stable@vger.kernel.org # v6.7+ Signed-off-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/r/20240109133957.2975272-1-yukuai1@huaweicloud.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/md/md.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 240e12cfd17f..a8ac4afc51d9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -8121,6 +8121,19 @@ static void status_unused(struct seq_file *seq)
seq_printf(seq, "\n");
}
+static void status_personalities(struct seq_file *seq)
+{
+ struct md_personality *pers;
+
+ seq_puts(seq, "Personalities : ");
+ spin_lock(&pers_lock);
+ list_for_each_entry(pers, &pers_list, list)
+ seq_printf(seq, "[%s] ", pers->name);
+
+ spin_unlock(&pers_lock);
+ seq_puts(seq, "\n");
+}
+
static int status_resync(struct seq_file *seq, struct mddev *mddev)
{
sector_t max_sectors, resync, res;
@@ -8262,20 +8275,10 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
static void *md_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(&all_mddevs_lock)
{
- struct md_personality *pers;
-
- seq_puts(seq, "Personalities : ");
- spin_lock(&pers_lock);
- list_for_each_entry(pers, &pers_list, list)
- seq_printf(seq, "[%s] ", pers->name);
-
- spin_unlock(&pers_lock);
- seq_puts(seq, "\n");
seq->poll_event = atomic_read(&md_event_count);
-
spin_lock(&all_mddevs_lock);
- return seq_list_start(&all_mddevs, *pos);
+ return seq_list_start_head(&all_mddevs, *pos);
}
static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -8286,7 +8289,6 @@ static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void md_seq_stop(struct seq_file *seq, void *v)
__releases(&all_mddevs_lock)
{
- status_unused(seq);
spin_unlock(&all_mddevs_lock);
}
@@ -8319,10 +8321,18 @@ static void md_bitmap_status(struct seq_file *seq, struct mddev *mddev)
static int md_seq_show(struct seq_file *seq, void *v)
{
- struct mddev *mddev = list_entry(v, struct mddev, all_mddevs);
+ struct mddev *mddev;
sector_t sectors;
struct md_rdev *rdev;
+ if (v == &all_mddevs) {
+ status_personalities(seq);
+ if (list_empty(&all_mddevs))
+ status_unused(seq);
+ return 0;
+ }
+
+ mddev = list_entry(v, struct mddev, all_mddevs);
if (!mddev_get(mddev))
return 0;
@@ -8403,6 +8413,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
spin_unlock(&mddev->lock);
mutex_unlock(&mddev->bitmap_info.mutex);
spin_lock(&all_mddevs_lock);
+
+ if (mddev == list_last_entry(&all_mddevs, struct mddev, all_mddevs))
+ status_unused(seq);
+
if (atomic_dec_and_test(&mddev->active))
__mddev_put(mddev);