Skip to content

Commit 310e9c8

Browse files
committed
Merge branch 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md into for-6.4/block
Pull MD updates from Song: "- md/bitmap: Optimal last page size, by Jon Derrick - Various raid10 fixes, by Yu Kuai and Li Nan - md: add error_handlers for raid0 and linear, by Mariusz Tkaczyk" * 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md: md/raid5: remove unused working_disks variable md/raid10: don't call bio_start_io_acct twice for bio which experienced read error md/raid10: fix memleak of md thread md/raid10: fix memleak for 'conf->bio_split' md/raid10: fix leak of 'r10bio->remaining' for recovery md/raid10: don't BUG_ON() in raise_barrier() md: fix soft lockup in status_resync md: add error_handlers for raid0 and linear md: Use optimal I/O size for last bitmap page md: Fix types in sb writer md: Move sb writer loop to its own function md/raid10: Fix typo in comment (replacment -> replacement) md: make kobj_type structures constant md/raid10: fix null-ptr-deref in raid10_sync_request md/raid10: fix task hung in raid10d
2 parents d2a1d45 + 7bc4361 commit 310e9c8

7 files changed

Lines changed: 184 additions & 131 deletions

File tree

drivers/md/md-bitmap.c

Lines changed: 83 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -209,76 +209,99 @@ static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mdde
209209
return NULL;
210210
}
211211

212-
static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
212+
static unsigned int optimal_io_size(struct block_device *bdev,
213+
unsigned int last_page_size,
214+
unsigned int io_size)
215+
{
216+
if (bdev_io_opt(bdev) > bdev_logical_block_size(bdev))
217+
return roundup(last_page_size, bdev_io_opt(bdev));
218+
return io_size;
219+
}
220+
221+
static unsigned int bitmap_io_size(unsigned int io_size, unsigned int opt_size,
222+
sector_t start, sector_t boundary)
223+
{
224+
if (io_size != opt_size &&
225+
start + opt_size / SECTOR_SIZE <= boundary)
226+
return opt_size;
227+
if (start + io_size / SECTOR_SIZE <= boundary)
228+
return io_size;
229+
230+
/* Overflows boundary */
231+
return 0;
232+
}
233+
234+
static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
235+
struct page *page)
213236
{
214-
struct md_rdev *rdev;
215237
struct block_device *bdev;
216238
struct mddev *mddev = bitmap->mddev;
217239
struct bitmap_storage *store = &bitmap->storage;
240+
sector_t offset = mddev->bitmap_info.offset;
241+
sector_t ps, sboff, doff;
242+
unsigned int size = PAGE_SIZE;
243+
unsigned int opt_size = PAGE_SIZE;
244+
245+
bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
246+
if (page->index == store->file_pages - 1) {
247+
unsigned int last_page_size = store->bytes & (PAGE_SIZE - 1);
248+
249+
if (last_page_size == 0)
250+
last_page_size = PAGE_SIZE;
251+
size = roundup(last_page_size, bdev_logical_block_size(bdev));
252+
opt_size = optimal_io_size(bdev, last_page_size, size);
253+
}
254+
255+
ps = page->index * PAGE_SIZE / SECTOR_SIZE;
256+
sboff = rdev->sb_start + offset;
257+
doff = rdev->data_offset;
258+
259+
/* Just make sure we aren't corrupting data or metadata */
260+
if (mddev->external) {
261+
/* Bitmap could be anywhere. */
262+
if (sboff + ps > doff &&
263+
sboff < (doff + mddev->dev_sectors + PAGE_SIZE / SECTOR_SIZE))
264+
return -EINVAL;
265+
} else if (offset < 0) {
266+
/* DATA BITMAP METADATA */
267+
size = bitmap_io_size(size, opt_size, offset + ps, 0);
268+
if (size == 0)
269+
/* bitmap runs in to metadata */
270+
return -EINVAL;
271+
272+
if (doff + mddev->dev_sectors > sboff)
273+
/* data runs in to bitmap */
274+
return -EINVAL;
275+
} else if (rdev->sb_start < rdev->data_offset) {
276+
/* METADATA BITMAP DATA */
277+
size = bitmap_io_size(size, opt_size, sboff + ps, doff);
278+
if (size == 0)
279+
/* bitmap runs in to data */
280+
return -EINVAL;
281+
} else {
282+
/* DATA METADATA BITMAP - no problems */
283+
}
218284

219-
restart:
220-
rdev = NULL;
221-
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
222-
int size = PAGE_SIZE;
223-
loff_t offset = mddev->bitmap_info.offset;
285+
md_super_write(mddev, rdev, sboff + ps, (int) size, page);
286+
return 0;
287+
}
224288

225-
bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
289+
static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
290+
{
291+
struct md_rdev *rdev;
292+
struct mddev *mddev = bitmap->mddev;
293+
int ret;
226294

227-
if (page->index == store->file_pages-1) {
228-
int last_page_size = store->bytes & (PAGE_SIZE-1);
229-
if (last_page_size == 0)
230-
last_page_size = PAGE_SIZE;
231-
size = roundup(last_page_size,
232-
bdev_logical_block_size(bdev));
233-
}
234-
/* Just make sure we aren't corrupting data or
235-
* metadata
236-
*/
237-
if (mddev->external) {
238-
/* Bitmap could be anywhere. */
239-
if (rdev->sb_start + offset + (page->index
240-
* (PAGE_SIZE/512))
241-
> rdev->data_offset
242-
&&
243-
rdev->sb_start + offset
244-
< (rdev->data_offset + mddev->dev_sectors
245-
+ (PAGE_SIZE/512)))
246-
goto bad_alignment;
247-
} else if (offset < 0) {
248-
/* DATA BITMAP METADATA */
249-
if (offset
250-
+ (long)(page->index * (PAGE_SIZE/512))
251-
+ size/512 > 0)
252-
/* bitmap runs in to metadata */
253-
goto bad_alignment;
254-
if (rdev->data_offset + mddev->dev_sectors
255-
> rdev->sb_start + offset)
256-
/* data runs in to bitmap */
257-
goto bad_alignment;
258-
} else if (rdev->sb_start < rdev->data_offset) {
259-
/* METADATA BITMAP DATA */
260-
if (rdev->sb_start
261-
+ offset
262-
+ page->index*(PAGE_SIZE/512) + size/512
263-
> rdev->data_offset)
264-
/* bitmap runs in to data */
265-
goto bad_alignment;
266-
} else {
267-
/* DATA METADATA BITMAP - no problems */
295+
do {
296+
rdev = NULL;
297+
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
298+
ret = __write_sb_page(rdev, bitmap, page);
299+
if (ret)
300+
return ret;
268301
}
269-
md_super_write(mddev, rdev,
270-
rdev->sb_start + offset
271-
+ page->index * (PAGE_SIZE/512),
272-
size,
273-
page);
274-
}
302+
} while (wait && md_super_wait(mddev) < 0);
275303

276-
if (wait && md_super_wait(mddev) < 0)
277-
goto restart;
278304
return 0;
279-
280-
bad_alignment:
281-
return -EINVAL;
282305
}
283306

284307
static void md_bitmap_file_kick(struct bitmap *bitmap);

drivers/md/md-linear.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
223223
bio_sector < start_sector))
224224
goto out_of_bounds;
225225

226-
if (unlikely(is_mddev_broken(tmp_dev->rdev, "linear"))) {
226+
if (unlikely(is_rdev_broken(tmp_dev->rdev))) {
227+
md_error(mddev, tmp_dev->rdev);
227228
bio_io_error(bio);
228229
return true;
229230
}
@@ -270,6 +271,16 @@ static void linear_status (struct seq_file *seq, struct mddev *mddev)
270271
seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2);
271272
}
272273

274+
static void linear_error(struct mddev *mddev, struct md_rdev *rdev)
275+
{
276+
if (!test_and_set_bit(MD_BROKEN, &mddev->flags)) {
277+
char *md_name = mdname(mddev);
278+
279+
pr_crit("md/linear%s: Disk failure on %pg detected, failing array.\n",
280+
md_name, rdev->bdev);
281+
}
282+
}
283+
273284
static void linear_quiesce(struct mddev *mddev, int state)
274285
{
275286
}
@@ -286,6 +297,7 @@ static struct md_personality linear_personality =
286297
.hot_add_disk = linear_add,
287298
.size = linear_size,
288299
.quiesce = linear_quiesce,
300+
.error_handler = linear_error,
289301
};
290302

291303
static int __init linear_init (void)

drivers/md/md.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
static LIST_HEAD(pers_list);
7979
static DEFINE_SPINLOCK(pers_lock);
8080

81-
static struct kobj_type md_ktype;
81+
static const struct kobj_type md_ktype;
8282

8383
struct md_cluster_operations *md_cluster_ops;
8484
EXPORT_SYMBOL(md_cluster_ops);
@@ -3597,7 +3597,7 @@ static const struct sysfs_ops rdev_sysfs_ops = {
35973597
.show = rdev_attr_show,
35983598
.store = rdev_attr_store,
35993599
};
3600-
static struct kobj_type rdev_ktype = {
3600+
static const struct kobj_type rdev_ktype = {
36013601
.release = rdev_free,
36023602
.sysfs_ops = &rdev_sysfs_ops,
36033603
.default_groups = rdev_default_groups,
@@ -5555,7 +5555,7 @@ static const struct sysfs_ops md_sysfs_ops = {
55555555
.show = md_attr_show,
55565556
.store = md_attr_store,
55575557
};
5558-
static struct kobj_type md_ktype = {
5558+
static const struct kobj_type md_ktype = {
55595559
.release = md_kobj_release,
55605560
.sysfs_ops = &md_sysfs_ops,
55615561
.default_groups = md_attr_groups,
@@ -7974,6 +7974,9 @@ void md_error(struct mddev *mddev, struct md_rdev *rdev)
79747974
return;
79757975
mddev->pers->error_handler(mddev, rdev);
79767976

7977+
if (mddev->pers->level == 0 || mddev->pers->level == LEVEL_LINEAR)
7978+
return;
7979+
79777980
if (mddev->degraded && !test_bit(MD_BROKEN, &mddev->flags))
79787981
set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
79797982
sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8029,16 +8032,16 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
80298032
} else if (resync > max_sectors) {
80308033
resync = max_sectors;
80318034
} else {
8032-
resync -= atomic_read(&mddev->recovery_active);
8033-
if (resync < MD_RESYNC_ACTIVE) {
8034-
/*
8035-
* Resync has started, but the subtraction has
8036-
* yielded one of the special values. Force it
8037-
* to active to ensure the status reports an
8038-
* active resync.
8039-
*/
8035+
res = atomic_read(&mddev->recovery_active);
8036+
/*
8037+
* Resync has started, but the subtraction has overflowed or
8038+
* yielded one of the special values. Force it to active to
8039+
* ensure the status reports an active resync.
8040+
*/
8041+
if (resync < res || resync - res < MD_RESYNC_ACTIVE)
80408042
resync = MD_RESYNC_ACTIVE;
8041-
}
8043+
else
8044+
resync -= res;
80428045
}
80438046

80448047
if (resync == MD_RESYNC_NONE) {

drivers/md/md.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -790,15 +790,9 @@ extern void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
790790
struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
791791
struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);
792792

793-
static inline bool is_mddev_broken(struct md_rdev *rdev, const char *md_type)
793+
static inline bool is_rdev_broken(struct md_rdev *rdev)
794794
{
795-
if (!disk_live(rdev->bdev->bd_disk)) {
796-
if (!test_and_set_bit(MD_BROKEN, &rdev->mddev->flags))
797-
pr_warn("md: %s: %s array has a missing/failed member\n",
798-
mdname(rdev->mddev), md_type);
799-
return true;
800-
}
801-
return false;
795+
return !disk_live(rdev->bdev->bd_disk);
802796
}
803797

804798
static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)

drivers/md/raid0.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,9 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
569569
return true;
570570
}
571571

572-
if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) {
572+
if (unlikely(is_rdev_broken(tmp_dev))) {
573573
bio_io_error(bio);
574+
md_error(mddev, tmp_dev);
574575
return true;
575576
}
576577

@@ -592,6 +593,16 @@ static void raid0_status(struct seq_file *seq, struct mddev *mddev)
592593
return;
593594
}
594595

596+
static void raid0_error(struct mddev *mddev, struct md_rdev *rdev)
597+
{
598+
if (!test_and_set_bit(MD_BROKEN, &mddev->flags)) {
599+
char *md_name = mdname(mddev);
600+
601+
pr_crit("md/raid0%s: Disk failure on %pg detected, failing array.\n",
602+
md_name, rdev->bdev);
603+
}
604+
}
605+
595606
static void *raid0_takeover_raid45(struct mddev *mddev)
596607
{
597608
struct md_rdev *rdev;
@@ -767,6 +778,7 @@ static struct md_personality raid0_personality=
767778
.size = raid0_size,
768779
.takeover = raid0_takeover,
769780
.quiesce = raid0_quiesce,
781+
.error_handler = raid0_error,
770782
};
771783

772784
static int __init raid0_init (void)

0 commit comments

Comments
 (0)