upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / drivers / block / genhd.c
index bfbdcf0..8bbe01d 100644 (file)
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
+#include <linux/buffer_head.h>
 
 #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)
 {
@@ -441,43 +431,58 @@ static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)
 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);
+       struct device *physdev;
+       struct gendisk *disk;
+       struct hd_struct *part;
        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;
+               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) {
-               struct gendisk *disk = container_of(kobj->parent, struct gendisk, kobj);
-               dev = disk->driverfs_dev;
-       }
+               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);
 
-       if (dev) {
-               /* add physical device, backing this device  */
-               char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+       /* 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);
 
-               /* add bus name of physical device */
-               if (dev->bus)
+               if (physdev->bus)
                        add_hotplug_env_var(envp, num_envp, &i,
                                            buffer, buffer_size, &length,
-                                           "PHYSDEVBUS=%s", dev->bus->name);
+                                           "PHYSDEVBUS=%s",
+                                           physdev->bus->name);
 
-               /* add driver name of physical device */
-               if (dev->driver)
+               if (physdev->driver)
                        add_hotplug_env_var(envp, num_envp, &i,
                                            buffer, buffer_size, &length,
-                                           "PHYSDEVDRIVER=%s", dev->driver->name);
-
-               envp[i] = NULL;
+                                           "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;
 }
 
@@ -506,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);
@@ -523,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)
@@ -671,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;
 }