vserver 1.9.5.x5
[linux-2.6.git] / drivers / block / genhd.c
index a0d7ef6..80da358 100644 (file)
 
 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 +31,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 +46,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) {
@@ -90,10 +90,9 @@ int register_blkdev(unsigned int major, const char *name)
 
        p->major = major;
        strlcpy(p->name, name, sizeof(p->name));
-       p->next = 0;
+       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 +101,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 +108,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 +120,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 +132,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 +226,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 +243,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,7 +300,7 @@ 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);
        blk_dev_init();
@@ -313,19 +308,13 @@ int __init device_init(void)
        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)
 {
@@ -352,24 +341,22 @@ static ssize_t disk_range_read(struct gendisk * disk, char *page)
 {
        return sprintf(page, "%d\n", disk->minors);
 }
+static ssize_t disk_removable_read(struct gendisk * disk, char *page)
+{
+       return sprintf(page, "%d\n",
+                      (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
+
+}
 static ssize_t disk_size_read(struct gendisk * disk, char *page)
 {
        return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk));
 }
 
-static inline unsigned jiffies_to_msec(unsigned jif)
-{
-#if 1000 % HZ == 0
-       return jif * (1000 / HZ);
-#elif HZ % 1000 == 0
-       return jif / (HZ / 1000);
-#else
-       return (jif / HZ) * 1000 + (jif % HZ) * 1000 / HZ;
-#endif
-}
 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 "
@@ -377,14 +364,14 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
                "\n",
                disk_stat_read(disk, reads), disk_stat_read(disk, read_merges),
                (unsigned long long)disk_stat_read(disk, read_sectors),
-               jiffies_to_msec(disk_stat_read(disk, read_ticks)),
+               jiffies_to_msecs(disk_stat_read(disk, read_ticks)),
                disk_stat_read(disk, writes), 
                disk_stat_read(disk, write_merges),
                (unsigned long long)disk_stat_read(disk, write_sectors),
-               jiffies_to_msec(disk_stat_read(disk, write_ticks)),
+               jiffies_to_msecs(disk_stat_read(disk, write_ticks)),
                disk->in_flight,
-               jiffies_to_msec(disk_stat_read(disk, io_ticks)),
-               jiffies_to_msec(disk_stat_read(disk, time_in_queue)));
+               jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
+               jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 }
 static struct disk_attribute disk_attr_dev = {
        .attr = {.name = "dev", .mode = S_IRUGO },
@@ -394,6 +381,10 @@ static struct disk_attribute disk_attr_range = {
        .attr = {.name = "range", .mode = S_IRUGO },
        .show   = disk_range_read
 };
+static struct disk_attribute disk_attr_removable = {
+       .attr = {.name = "removable", .mode = S_IRUGO },
+       .show   = disk_removable_read
+};
 static struct disk_attribute disk_attr_size = {
        .attr = {.name = "size", .mode = S_IRUGO },
        .show   = disk_size_read
@@ -406,6 +397,7 @@ static struct disk_attribute disk_attr_stat = {
 static struct attribute * default_attrs[] = {
        &disk_attr_dev.attr,
        &disk_attr_range.attr,
+       &disk_attr_removable.attr,
        &disk_attr_size.attr,
        &disk_attr_stat.attr,
        NULL,
@@ -435,8 +427,52 @@ 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 device *dev = NULL;
+       struct kobj_type *ktype = get_ktype(kobj);
+       int length = 0;
+       int i = 0;
+
+       /* get physical device backing disk or partition */
+       if (ktype == &ktype_block) {
+               struct gendisk *disk = container_of(kobj, struct gendisk, kobj);
+               dev = disk->driverfs_dev;
+       } else if (ktype == &ktype_part) {
+               struct gendisk *disk = container_of(kobj->parent, struct gendisk, kobj);
+               dev = disk->driverfs_dev;
+       }
+
+       if (dev) {
+               /* add physical device, backing this device  */
+               char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+
+               add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+                                   &length, "PHYSDEVPATH=%s", path);
+               kfree(path);
+
+               /* add bus name of physical device */
+               if (dev->bus)
+                       add_hotplug_env_var(envp, num_envp, &i,
+                                           buffer, buffer_size, &length,
+                                           "PHYSDEVBUS=%s", dev->bus->name);
+
+               /* add driver name of physical device */
+               if (dev->driver)
+                       add_hotplug_env_var(envp, num_envp, &i,
+                                           buffer, buffer_size, &length,
+                                           "PHYSDEVDRIVER=%s", dev->driver->name);
+
+               envp[i] = NULL;
+       }
+
+       return 0;
+}
+
 static struct kset_hotplug_ops block_hotplug_ops = {
-       .filter = block_hotplug_filter,
+       .filter         = block_hotplug_filter,
+       .hotplug        = block_hotplug,
 };
 
 /* declare block_subsys. */
@@ -459,7 +495,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);
@@ -476,7 +512,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)
@@ -493,18 +529,20 @@ 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),
                (unsigned long long)disk_stat_read(gp, read_sectors),
-               jiffies_to_msec(disk_stat_read(gp, read_ticks)),
+               jiffies_to_msecs(disk_stat_read(gp, read_ticks)),
                disk_stat_read(gp, writes), disk_stat_read(gp, write_merges),
                (unsigned long long)disk_stat_read(gp, write_sectors),
-               jiffies_to_msec(disk_stat_read(gp, write_ticks)),
+               jiffies_to_msecs(disk_stat_read(gp, write_ticks)),
                gp->in_flight,
-               jiffies_to_msec(disk_stat_read(gp, io_ticks)),
-               jiffies_to_msec(disk_stat_read(gp, time_in_queue)));
+               jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
+               jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
 
        /* now show all non-0 size partitions of it */
        for (n = 0; n < gp->minors - 1; n++) {
@@ -622,9 +660,10 @@ int invalidate_partition(struct gendisk *disk, int index)
 {
        int res = 0;
        struct block_device *bdev = bdget_disk(disk, index);
-       if (bdev)
+       if (bdev) {
                res = __invalidate_device(bdev, 1);
-       bdput(bdev);
+               bdput(bdev);
+       }
        return res;
 }