Merge branch 'master'
[powerpc.git] / drivers / block / genhd.c
index ab4db71..486ce1f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
+#include <linux/buffer_head.h>
 
 #define MAX_PROBE_HASH 255     /* random */
 
@@ -39,19 +40,27 @@ static inline int major_to_index(int major)
 
 #ifdef CONFIG_PROC_FS
 /* get block device names in somewhat random order */
-int get_blkdev_list(char *p)
+int get_blkdev_list(char *p, int used)
 {
        struct blk_major_name *n;
        int i, len;
 
-       len = sprintf(p, "\nBlock devices:\n");
+       len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
 
        down(&block_subsys_sem);
        for (i = 0; i < ARRAY_SIZE(major_names); i++) {
-               for (n = major_names[i]; n; n = n->next)
+               for (n = major_names[i]; n; n = n->next) {
+                       /*
+                        * If the curent string plus the 5 extra characters
+                        * in the line would run us off the page, then we're done
+                        */
+                       if ((len + used + strlen(n->name) + 5) >= PAGE_SIZE)
+                               goto page_full;
                        len += sprintf(p+len, "%3d %s\n",
                                       n->major, n->name);
+               }
        }
+page_full:
        up(&block_subsys_sem);
 
        return len;
@@ -321,17 +330,37 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
        struct gendisk *disk = to_disk(kobj);
        struct disk_attribute *disk_attr =
                container_of(attr,struct disk_attribute,attr);
-       ssize_t ret = 0;
+       ssize_t ret = -EIO;
 
        if (disk_attr->show)
                ret = disk_attr->show(disk,page);
        return ret;
 }
 
+static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr,
+                              const char *page, size_t count)
+{
+       struct gendisk *disk = to_disk(kobj);
+       struct disk_attribute *disk_attr =
+               container_of(attr,struct disk_attribute,attr);
+       ssize_t ret = 0;
+
+       if (disk_attr->store)
+               ret = disk_attr->store(disk, page, count);
+       return ret;
+}
+
 static struct sysfs_ops disk_sysfs_ops = {
        .show   = &disk_attr_show,
+       .store  = &disk_attr_store,
 };
 
+static ssize_t disk_uevent_store(struct gendisk * disk,
+                                const char *buf, size_t count)
+{
+       kobject_hotplug(&disk->kobj, KOBJ_ADD);
+       return count;
+}
 static ssize_t disk_dev_read(struct gendisk * disk, char *page)
 {
        dev_t base = MKDEV(disk->major, disk->first_minor); 
@@ -373,6 +402,10 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
                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_uevent = {
+       .attr = {.name = "uevent", .mode = S_IWUSR },
+       .store  = disk_uevent_store
+};
 static struct disk_attribute disk_attr_dev = {
        .attr = {.name = "dev", .mode = S_IRUGO },
        .show   = disk_dev_read
@@ -395,6 +428,7 @@ static struct disk_attribute disk_attr_stat = {
 };
 
 static struct attribute * default_attrs[] = {
+       &disk_attr_uevent.attr,
        &disk_attr_dev.attr,
        &disk_attr_range.attr,
        &disk_attr_removable.attr,
@@ -581,10 +615,16 @@ struct seq_operations diskstats_op = {
        .show   = diskstats_show
 };
 
-
 struct gendisk *alloc_disk(int minors)
 {
-       struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+       return alloc_disk_node(minors, -1);
+}
+
+struct gendisk *alloc_disk_node(int minors, int node_id)
+{
+       struct gendisk *disk;
+
+       disk = kmalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
        if (disk) {
                memset(disk, 0, sizeof(struct gendisk));
                if (!init_disk_stats(disk)) {
@@ -593,7 +633,7 @@ struct gendisk *alloc_disk(int minors)
                }
                if (minors > 1) {
                        int size = (minors - 1) * sizeof(struct hd_struct *);
-                       disk->part = kmalloc(size, GFP_KERNEL);
+                       disk->part = kmalloc_node(size, GFP_KERNEL, node_id);
                        if (!disk->part) {
                                kfree(disk);
                                return NULL;
@@ -609,6 +649,7 @@ struct gendisk *alloc_disk(int minors)
 }
 
 EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(alloc_disk_node);
 
 struct kobject *get_disk(struct gendisk *disk)
 {
@@ -676,7 +717,8 @@ 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);
+               fsync_bdev(bdev);
+               res = __invalidate_device(bdev);
                bdput(bdev);
        }
        return res;