Commit 121a641e authored by Yu Kuai's avatar Yu Kuai Committed by Wentao Guan
Browse files

md: Fix md_seq_ops() regressions

stable inclusion
from stable-v6.6.80
commit 8fab939c5d62e9c64bc89ea514f2e7ed886cb671
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBXANC

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8fab939c5d62e9c64bc89ea514f2e7ed886cb671



--------------------------------

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: default avatarYu Kuai <yukuai3@huawei.com>
Signed-off-by: default avatarSong Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20240109133957.2975272-1-yukuai1@huaweicloud.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 8fab939c5d62e9c64bc89ea514f2e7ed886cb671)
Signed-off-by: default avatarWentao Guan <guanwentao@uniontech.com>
parent 2716eaf4
Loading
Loading
Loading
Loading
+27 −13
Original line number Diff line number Diff line
@@ -8161,6 +8161,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;
@@ -8302,20 +8315,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)
@@ -8326,7 +8329,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);
}

@@ -8359,10 +8361,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;

@@ -8443,6 +8453,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);