--- ./block/genhd.c.orig 2006-11-05 16:51:18.000000000 -0600 +++ ./block/genhd.c 2006-11-05 19:41:46.000000000 -0600 @@ -13,9 +13,14 @@ #include #include #include +#include +#include #include #include +DECLARE_WAIT_QUEUE_HEAD(disk_wait_h); +EXPORT_SYMBOL(disk_wait_h); + struct subsystem block_subsys; static DEFINE_MUTEX(block_subsys_lock); @@ -51,6 +56,49 @@ void blkdev_show(struct seq_file *f, off #endif /* CONFIG_PROC_FS */ +/* + * Returns an array of all the block device names and partitions. + */ + +char **get_blkdevs(void) +{ + int i = 0; + int n = 0; + int len = 0; + struct list_head *p; + char **names = NULL; + struct gendisk *sgp; + char buf[BDEVNAME_SIZE]; + + down_read(&block_subsys.rwsem); + + list_for_each(p, &block_subsys.kset.list) { + len ++; + } + + names = kmalloc(sizeof(char *) * len + 1, GFP_KERNEL); + + list_for_each(p, &block_subsys.kset.list) { + sgp = list_entry(p, struct gendisk, kobj.entry); + names[i] = kmalloc(strlen(disk_name(sgp, 0, buf)), GFP_KERNEL); + strcpy(names[i], disk_name(sgp, 0, buf)); + + for (n = 0; n < sgp->minors - 1; n++) { + struct hd_struct *hd = sgp->part[n]; + if (hd && hd->nr_sects) { + names[i] = kmalloc(strlen(disk_name(sgp, n+1, buf)), GFP_KERNEL); + strcpy(names[i], disk_name(sgp, n+1, buf)); + i ++; + } + } + } + names[i] = NULL; + up_read(&block_subsys.rwsem); + return names; +} + +EXPORT_SYMBOL(get_blkdevs); + int register_blkdev(unsigned int major, const char *name) { struct blk_major_name **n, *p; @@ -185,6 +233,11 @@ void add_disk(struct gendisk *disk) disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); + + /* Wake up queue in init/main.c. */ + printk("Waking up queue on %s\n", + disk->disk_name); + wake_up_interruptible(&disk_wait_h); } EXPORT_SYMBOL(add_disk); --- ./drivers/usb/storage/usb.c.orig 2006-11-05 16:51:18.000000000 -0600 +++ ./drivers/usb/storage/usb.c 2006-11-05 19:43:47.000000000 -0600 @@ -1019,6 +1019,8 @@ static int storage_probe(struct usb_inte atomic_inc(&total_threads); wake_up_process(th); + wait_for_completion(&threads_gone); + return 0; /* We come here if there are any problems */ --- ./include/linux/genhd.h.orig 2006-11-05 16:51:18.000000000 -0600 +++ ./include/linux/genhd.h 2006-11-05 19:43:47.000000000 -0600 @@ -60,6 +60,10 @@ struct partition { #include #include #include +#include + +/* Wait queue to wait on disks coming online. */ +extern wait_queue_head_t disk_wait_h; struct partition { unsigned char boot_ind; /* 0x80 - active */ @@ -229,6 +233,7 @@ extern struct gendisk *get_gendisk(dev_t extern void set_device_ro(struct block_device *bdev, int flag); extern void set_disk_ro(struct gendisk *disk, int flag); +extern char **get_blkdevs(void); /* drivers/char/random.c */ extern void add_disk_randomness(struct gendisk *disk); --- ./init/do_mounts.c.orig 2006-11-05 16:51:18.000000000 -0600 +++ ./init/do_mounts.c 2006-11-05 19:51:12.000000000 -0600 @@ -13,6 +13,8 @@ #include #include +#include + #include "do_mounts.h" extern int get_filesystem_list(char * buf); @@ -363,8 +365,35 @@ void __init change_floppy(char *fmt, ... } #endif +/* + * match_root_name - Returns 1 if the root_device_name appears amongst + * the list of block devices, 0 otherwise. + */ + +static int __init match_root_name(void) { + char **names = NULL; + int i = 0; + int match = 0; + + names = get_blkdevs(); + while (names[i] != NULL) { + if (match == 0 && strncmp(names[i], + root_device_name, + strlen(root_device_name)) == 0) { + match = 1; + printk("Block device %s matches %s root_device_name, continuing\n", + names[i], root_device_name); + } + kfree(names[i]); + i ++; + } + kfree(names); + return match; +} + void __init mount_root(void) { + #ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { if (mount_nfs_root()) @@ -386,6 +415,14 @@ void __init mount_root(void) change_floppy("root floppy"); } #endif + + /* Here, we wait for the root device to show up, or if it's + * already there, we just go on. */ + while (!match_root_name()) { + printk("Waiting for root device to wake us up\n"); + interruptible_sleep_on(&disk_wait_h); + } + create_dev("/dev/root", ROOT_DEV); mount_block_root("/dev/root", root_mountflags); } --- ./init/main.c.orig 2006-11-05 16:51:18.000000000 -0600 +++ ./init/main.c 2006-11-05 19:43:47.000000000 -0600 @@ -52,6 +52,11 @@ #include #include +#include +#include +#include + + #include #include #include