X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fblock%2Fgenhd.c;h=8bbe01d4b487cf5c9a03b474e8ffd2e57bbf1e8f;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=e82caa224d1fa80846b82f2d2d5f001e6e0ef4d2;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index e82caa224..8bbe01d4b 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -14,15 +14,17 @@ #include #include #include +#include #define MAX_PROBE_HASH 255 /* random */ static struct subsystem block_subsys; +static DECLARE_MUTEX(block_subsys_sem); + /* * Can be deleted altogether. Later. * - * Modified under both block_subsys.rwsem and major_names_lock. */ static struct blk_major_name { struct blk_major_name *next; @@ -30,14 +32,13 @@ static struct blk_major_name { char name[16]; } *major_names[MAX_PROBE_HASH]; -static spinlock_t major_names_lock = SPIN_LOCK_UNLOCKED; - /* index in the above - for now: assume no multimajor ranges */ static inline int major_to_index(int major) { return major % MAX_PROBE_HASH; } +#ifdef CONFIG_PROC_FS /* get block device names in somewhat random order */ int get_blkdev_list(char *p) { @@ -46,24 +47,24 @@ int get_blkdev_list(char *p) len = sprintf(p, "\nBlock devices:\n"); - down_read(&block_subsys.rwsem); + down(&block_subsys_sem); for (i = 0; i < ARRAY_SIZE(major_names); i++) { for (n = major_names[i]; n; n = n->next) len += sprintf(p+len, "%3d %s\n", n->major, n->name); } - up_read(&block_subsys.rwsem); + up(&block_subsys_sem); return len; } +#endif int register_blkdev(unsigned int major, const char *name) { struct blk_major_name **n, *p; int index, ret = 0; - unsigned long flags; - down_write(&block_subsys.rwsem); + down(&block_subsys_sem); /* temporary */ if (major == 0) { @@ -93,7 +94,6 @@ int register_blkdev(unsigned int major, const char *name) p->next = NULL; index = major_to_index(major); - spin_lock_irqsave(&major_names_lock, flags); for (n = &major_names[index]; *n; n = &(*n)->next) { if ((*n)->major == major) break; @@ -102,7 +102,6 @@ int register_blkdev(unsigned int major, const char *name) *n = p; else ret = -EBUSY; - spin_unlock_irqrestore(&major_names_lock, flags); if (ret < 0) { printk("register_blkdev: cannot get major %d for %s\n", @@ -110,7 +109,7 @@ int register_blkdev(unsigned int major, const char *name) kfree(p); } out: - up_write(&block_subsys.rwsem); + up(&block_subsys_sem); return ret; } @@ -122,11 +121,9 @@ int unregister_blkdev(unsigned int major, const char *name) struct blk_major_name **n; struct blk_major_name *p = NULL; int index = major_to_index(major); - unsigned long flags; int ret = 0; - down_write(&block_subsys.rwsem); - spin_lock_irqsave(&major_names_lock, flags); + down(&block_subsys_sem); for (n = &major_names[index]; *n; n = &(*n)->next) if ((*n)->major == major) break; @@ -136,8 +133,7 @@ int unregister_blkdev(unsigned int major, const char *name) p = *n; *n = p->next; } - spin_unlock_irqrestore(&major_names_lock, flags); - up_write(&block_subsys.rwsem); + up(&block_subsys_sem); kfree(p); return ret; @@ -231,7 +227,7 @@ static void *part_start(struct seq_file *part, loff_t *pos) struct list_head *p; loff_t l = *pos; - down_read(&block_subsys.rwsem); + down(&block_subsys_sem); list_for_each(p, &block_subsys.kset.list) if (!l--) return list_entry(p, struct gendisk, kobj.entry); @@ -248,7 +244,7 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos) static void part_stop(struct seq_file *part, void *v) { - up_read(&block_subsys.rwsem); + up(&block_subsys_sem); } static int show_partition(struct seq_file *part, void *v) @@ -305,27 +301,21 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data) return NULL; } -int __init device_init(void) +static int __init genhd_device_init(void) { - bdev_map = kobj_map_init(base_probe, &block_subsys); + bdev_map = kobj_map_init(base_probe, &block_subsys_sem); blk_dev_init(); subsystem_register(&block_subsys); return 0; } -subsys_initcall(device_init); +subsys_initcall(genhd_device_init); /* * kobject & sysfs bindings for block devices */ - -struct disk_attribute { - struct attribute attr; - ssize_t (*show)(struct gendisk *, char *); -}; - static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, char *page) { @@ -365,7 +355,9 @@ static ssize_t disk_size_read(struct gendisk * disk, char *page) static ssize_t disk_stats_read(struct gendisk * disk, char *page) { + preempt_disable(); disk_round_stats(disk); + preempt_enable(); return sprintf(page, "%8u %8u %8llu %8u " "%8u %8u %8llu %8u " @@ -436,8 +428,67 @@ static int block_hotplug_filter(struct kset *kset, struct kobject *kobj) return ((ktype == &ktype_block) || (ktype == &ktype_part)); } +static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct kobj_type *ktype = get_ktype(kobj); + struct device *physdev; + struct gendisk *disk; + struct hd_struct *part; + int length = 0; + int i = 0; + + if (ktype == &ktype_block) { + disk = container_of(kobj, struct gendisk, kobj); + add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, + &length, "MINOR=%u", disk->first_minor); + } else if (ktype == &ktype_part) { + disk = container_of(kobj->parent, struct gendisk, kobj); + part = container_of(kobj, struct hd_struct, kobj); + add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, + &length, "MINOR=%u", + disk->first_minor + part->partno); + } else + return 0; + + add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MAJOR=%u", disk->major); + + /* add physical device, backing this device */ + physdev = disk->driverfs_dev; + if (physdev) { + char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); + + add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, + &length, "PHYSDEVPATH=%s", path); + kfree(path); + + if (physdev->bus) + add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVBUS=%s", + physdev->bus->name); + + if (physdev->driver) + add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", + physdev->driver->name); + } + + /* terminate, set to next free slot, shrink available space */ + envp[i] = NULL; + envp = &envp[i]; + num_envp -= i; + buffer = &buffer[length]; + buffer_size -= length; + + return 0; +} + static struct kset_hotplug_ops block_hotplug_ops = { - .filter = block_hotplug_filter, + .filter = block_hotplug_filter, + .hotplug = block_hotplug, }; /* declare block_subsys. */ @@ -460,7 +511,7 @@ static void *diskstats_start(struct seq_file *part, loff_t *pos) loff_t k = *pos; struct list_head *p; - down_read(&block_subsys.rwsem); + down(&block_subsys_sem); list_for_each(p, &block_subsys.kset.list) if (!k--) return list_entry(p, struct gendisk, kobj.entry); @@ -477,7 +528,7 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) static void diskstats_stop(struct seq_file *part, void *v) { - up_read(&block_subsys.rwsem); + up(&block_subsys_sem); } static int diskstats_show(struct seq_file *s, void *v) @@ -494,7 +545,9 @@ static int diskstats_show(struct seq_file *s, void *v) "\n\n"); */ + preempt_disable(); disk_round_stats(gp); + preempt_enable(); seq_printf(s, "%4d %4d %s %u %u %llu %u %u %u %llu %u %u %u %u\n", gp->major, n + gp->first_minor, disk_name(gp, n, buf), disk_stat_read(gp, reads), disk_stat_read(gp, read_merges), @@ -623,9 +676,11 @@ int invalidate_partition(struct gendisk *disk, int index) { int res = 0; struct block_device *bdev = bdget_disk(disk, index); - if (bdev) - res = __invalidate_device(bdev, 1); - bdput(bdev); + if (bdev) { + fsync_bdev(bdev); + res = __invalidate_device(bdev); + bdput(bdev); + } return res; }