blkdev_wait_scan module to help initrd scripts
Subsystems (2)
PATCH 1/1 blkdev_wait_scan module to help initrd scripts
Why this is needed
------------------
During initrd scripts we load block device modules which asynchronously perform partition scans. These partition checks must have been completed before later parts of the scripts run (in particular, vgscan).
Under load, especially for virtual machines, the partition scans aren't completed in time and consequently vgscan doesn't find the volume group containing root, and the virtual machine fails to boot.
More detail:
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=241793#c15
scsi_wait_scan
--------------
SCSI devices have a similar problem. This is solved by scsi_wait_scan, a sort of virtual module which is loaded into the kernel and synchronously waits for all SCSI buses to be scanned (it is then unloaded right afterwards). This has been in the kernel since late last year.
How it works
------------
I've added a list of block devices which are being scanned for partitions (rescan_bdevs). Function rescan_partitions is modified so that during the scan it puts the block device on this list, and takes it off after the scan is completed.
I added a function rescan_partitions_wait which checks this list, and while it is non-empty, waits for the scan on the first block device on the list to complete (and repeats, if necessary, until the list is empty).
The module (blkdev_scan_wait.ko) just calls rescan_partitions_wait during its init function.
How to test
-----------
Copy the built module into /lib of an initrd image. Modify /init so that it does:
echo Wait for partition scans to complete
insmod /lib/blkdev_wait_scan.ko
rmmod blkdev_wait_scan
mkblkdevs
after block devs are loaded but before vgscan is run.
Boot it under load (eg. as a Xen guest with lots of guests starting at once or something else stressing the disk). Logs will look something like this (my annotations added):
Registering block device major 202
xvda:Loading dm-mod.ko module <-- partition scan starts
<6>device-mapper: ioctl: 4.11.0-ioctl (2006-10-12) initialised: [email protected] Loading dm-mirror.ko module
Loading dm-zero.ko module
Loading dm-snapshot.ko module
Making device-mapper control node
Wait for partition scans to complete
xvda1 xvda2 <---- partition scan completes
Scanning logical volumes <---- vgscan starts
Reading all physical volumes. This may take a while...
Found volume group "VolGroup00" using metadata type lvm2
-----
Rich.
Signature · 4 lines
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903
Quoted 1 line
From
28779cbc8299da869239732cddab56b5fad4dbf4Mon Sep 17 00:00:00 2001
From: Richard Jones <[email protected]>
Date: Thu, 7 Jun 2007 17:05:29 +0100
Subject: [PATCH] Added blkdev_wait_scan version 2.
--- drivers/block/Kconfig | 11 ++++++ drivers/block/Makefile | 1 + drivers/block/blkdev_wait_scan.c | 34 ++++++++++++++++++++ fs/block_dev.c | 1 + fs/partitions/check.c | 63 +++++++++++++++++++++++++++++++++---- include/linux/fs.h | 2 + include/linux/genhd.h | 2 + 7 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 drivers/block/blkdev_wait_scan.c
drivers/block/Kconfig +11 -0
@@ -451,6 +451,17 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config BLKDEV_WAIT_SCAN + tristate "Module to wait for block devices to finish opening" + default m + help + This module waits for all block devices to finish opening. The + particular use is in initrd scripts, to wait for partition table + probing to finish before we start doing vgscan. + + Just modprobe this module after loading block device modules. + + source "drivers/s390/block/Kconfig" endmenu
drivers/block/Makefile +1 -0
@@ -29,3 +29,4 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o +obj-$(CONFIG_BLKDEV_WAIT_SCAN) += blkdev_wait_scan.o
drivers/block/blkdev_wait_scan.c new file +34 -0
@@ -0,0 +1,34 @@ +/* +* blkdev_wait_scan.c +* +* Copyright (C) 2007 Red Hat, Richard W.M. Jones <[email protected]> +* +* This module waits for all block devices to finish opening. The +* particular use is in initrd scripts, to wait for partition table +* probing to finish before we start doing vgscan. +* +* Just modprobe this module after loading block device modules. +* +* This is derived from scsi_wait_scan. +*/ + +#include <linux/module.h> +#include <linux/genhd.h> + +static int __init blkdev_wait_scan_init (void ) +{ +rescan_partitions_wait (); +return 0 ; +} + +/* Allow the module to be unloaded. */ +static void __exit blkdev_wait_scan_exit(void) +{ +} + +MODULE_DESCRIPTION ("Block device wait for probing to finish" ); +MODULE_AUTHOR ("Richard W.M. Jones" ); +MODULE_LICENSE ("GPL" ); + +module_init (blkdev_wait_scan_init); +module_exit (blkdev_wait_scan_exit);
fs/block_dev.c +1 -0
@@ -463,6 +463,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flagsema_init (&bdev->bd_mount_sem,1 );INIT_LIST_HEAD (&bdev->bd_inodes);INIT_LIST_HEAD (&bdev->bd_list); +INIT_LIST_HEAD (&bdev->bd_rescan_list);#ifdef CONFIG_SYSFS INIT_LIST_HEAD (&bdev->bd_holder_list);#endif
fs/partitions/check.c +56 -7
89 lines not on this page · raw message
include/linux/fs.h +2 -0
@@ -477,6 +477,8 @@ struct block_device {int bd_invalidated;struct gendisk * bd_disk;struct list_head bd_list; +/* on this list if we are doing a partition scan: */ +struct list_head bd_rescan_list;struct backing_dev_info *bd_inode_backing_dev_info;/* * Private data. You must have bd_claim'ed the block_device
include/linux/genhd.h +2 -0
@@ -418,6 +418,8 @@ extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);extern void delete_partition (struct gendisk *,int );extern void printk_all_partitions (void ); +extern void rescan_partitions_wait (void ); +extern struct gendisk *alloc_disk_node (int minors,int node_id);extern struct gendisk *alloc_disk (int minors);extern struct kobject *get_disk (struct gendisk *disk);
Signature · 1 line
1.5.0.6