mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 14:50:19 +00:00
md: Fix md_seq_ops() regressions
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
This commit is contained in:
parent
53889bcaf5
commit
f9cfe7e7f9
@ -8135,6 +8135,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;
|
||||
@ -8276,20 +8289,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)
|
||||
@ -8300,16 +8303,23 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -8385,6 +8395,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
|
||||
}
|
||||
spin_unlock(&mddev->lock);
|
||||
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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user