Merge tag 'mmc-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[linux-2.6-microblaze.git] / block / genhd.c
index 9c2e13c..06b642b 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kdev_t.h>
@@ -26,7 +27,7 @@
 #include "blk.h"
 
 static DEFINE_MUTEX(block_class_lock);
-struct kobject *block_depr;
+static struct kobject *block_depr;
 
 /* for extended dynamic devt allocation, currently only one major is used */
 #define NR_EXT_DEVT            (1 << MINORBITS)
@@ -46,6 +47,78 @@ static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
 
+/*
+ * Set disk capacity and notify if the size is not currently
+ * zero and will not be set to zero
+ */
+void set_capacity_revalidate_and_notify(struct gendisk *disk, sector_t size,
+                                       bool revalidate)
+{
+       sector_t capacity = get_capacity(disk);
+
+       set_capacity(disk, size);
+
+       if (revalidate)
+               revalidate_disk(disk);
+
+       if (capacity != size && capacity != 0 && size != 0) {
+               char *envp[] = { "RESIZE=1", NULL };
+
+               kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
+       }
+}
+
+EXPORT_SYMBOL_GPL(set_capacity_revalidate_and_notify);
+
+/*
+ * Format the device name of the indicated disk into the supplied buffer and
+ * return a pointer to that same buffer for convenience.
+ */
+char *disk_name(struct gendisk *hd, int partno, char *buf)
+{
+       if (!partno)
+               snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
+       else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
+               snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
+       else
+               snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
+
+       return buf;
+}
+
+const char *bdevname(struct block_device *bdev, char *buf)
+{
+       return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
+}
+EXPORT_SYMBOL(bdevname);
+
+#ifdef CONFIG_SMP
+static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
+{
+       int cpu;
+
+       memset(stat, 0, sizeof(struct disk_stats));
+       for_each_possible_cpu(cpu) {
+               struct disk_stats *ptr = per_cpu_ptr(part->dkstats, cpu);
+               int group;
+
+               for (group = 0; group < NR_STAT_GROUPS; group++) {
+                       stat->nsecs[group] += ptr->nsecs[group];
+                       stat->sectors[group] += ptr->sectors[group];
+                       stat->ios[group] += ptr->ios[group];
+                       stat->merges[group] += ptr->merges[group];
+               }
+
+               stat->io_ticks += ptr->io_ticks;
+       }
+}
+#else /* CONFIG_SMP */
+static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
+{
+       memcpy(stat, &part->dkstats, sizeof(struct disk_stats));
+}
+#endif /* CONFIG_SMP */
+
 void part_inc_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
 {
        if (queue_is_mq(q))
@@ -66,7 +139,8 @@ void part_dec_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
                part_stat_local_dec(&part_to_disk(part)->part0, in_flight[rw]);
 }
 
-unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part)
+static unsigned int part_in_flight(struct request_queue *q,
+               struct hd_struct *part)
 {
        int cpu;
        unsigned int inflight;
@@ -86,8 +160,8 @@ unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part)
        return inflight;
 }
 
-void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
-                      unsigned int inflight[2])
+static void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
+               unsigned int inflight[2])
 {
        int cpu;
 
@@ -143,7 +217,6 @@ struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
 
        return part;
 }
-EXPORT_SYMBOL_GPL(disk_get_part);
 
 /**
  * disk_part_iter_init - initialize partition iterator
@@ -299,7 +372,6 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
        }
        return &disk->part0;
 }
-EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
 
 /**
  * disk_has_partitions
@@ -944,7 +1016,6 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
        }
        return disk;
 }
-EXPORT_SYMBOL(get_gendisk);
 
 /**
  * bdget_disk - do bdget() by gendisk and partition number
@@ -1190,6 +1261,67 @@ static ssize_t disk_ro_show(struct device *dev,
        return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0);
 }
 
+ssize_t part_size_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+
+       return sprintf(buf, "%llu\n",
+               (unsigned long long)part_nr_sects_read(p));
+}
+
+ssize_t part_stat_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       struct request_queue *q = part_to_disk(p)->queue;
+       struct disk_stats stat;
+       unsigned int inflight;
+
+       part_stat_read_all(p, &stat);
+       inflight = part_in_flight(q, p);
+
+       return sprintf(buf,
+               "%8lu %8lu %8llu %8u "
+               "%8lu %8lu %8llu %8u "
+               "%8u %8u %8u "
+               "%8lu %8lu %8llu %8u "
+               "%8lu %8u"
+               "\n",
+               stat.ios[STAT_READ],
+               stat.merges[STAT_READ],
+               (unsigned long long)stat.sectors[STAT_READ],
+               (unsigned int)div_u64(stat.nsecs[STAT_READ], NSEC_PER_MSEC),
+               stat.ios[STAT_WRITE],
+               stat.merges[STAT_WRITE],
+               (unsigned long long)stat.sectors[STAT_WRITE],
+               (unsigned int)div_u64(stat.nsecs[STAT_WRITE], NSEC_PER_MSEC),
+               inflight,
+               jiffies_to_msecs(stat.io_ticks),
+               (unsigned int)div_u64(stat.nsecs[STAT_READ] +
+                                     stat.nsecs[STAT_WRITE] +
+                                     stat.nsecs[STAT_DISCARD] +
+                                     stat.nsecs[STAT_FLUSH],
+                                               NSEC_PER_MSEC),
+               stat.ios[STAT_DISCARD],
+               stat.merges[STAT_DISCARD],
+               (unsigned long long)stat.sectors[STAT_DISCARD],
+               (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], NSEC_PER_MSEC),
+               stat.ios[STAT_FLUSH],
+               (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], NSEC_PER_MSEC));
+}
+
+ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       struct request_queue *q = part_to_disk(p)->queue;
+       unsigned int inflight[2];
+
+       part_in_flight_rw(q, p, inflight);
+       return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]);
+}
+
 static ssize_t disk_capability_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -1228,10 +1360,33 @@ static DEVICE_ATTR(capability, 0444, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, 0444, part_stat_show, NULL);
 static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL);
 static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store);
+
 #ifdef CONFIG_FAIL_MAKE_REQUEST
+ssize_t part_fail_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+
+       return sprintf(buf, "%d\n", p->make_it_fail);
+}
+
+ssize_t part_fail_store(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       int i;
+
+       if (count > 0 && sscanf(buf, "%d", &i) > 0)
+               p->make_it_fail = (i == 0) ? 0 : 1;
+
+       return count;
+}
+
 static struct device_attribute dev_attr_fail =
        __ATTR(make-it-fail, 0644, part_fail_show, part_fail_store);
-#endif
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
+
 #ifdef CONFIG_FAIL_IO_TIMEOUT
 static struct device_attribute dev_attr_fail_timeout =
        __ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store);
@@ -1378,8 +1533,8 @@ static char *block_devnode(struct device *dev, umode_t *mode,
 {
        struct gendisk *disk = dev_to_disk(dev);
 
-       if (disk->devnode)
-               return disk->devnode(disk, mode);
+       if (disk->fops->devnode)
+               return disk->fops->devnode(disk, mode);
        return NULL;
 }
 
@@ -1405,6 +1560,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
        struct hd_struct *hd;
        char buf[BDEVNAME_SIZE];
        unsigned int inflight;
+       struct disk_stats stat;
 
        /*
        if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
@@ -1416,7 +1572,9 @@ static int diskstats_show(struct seq_file *seqf, void *v)
 
        disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
        while ((hd = disk_part_iter_next(&piter))) {
+               part_stat_read_all(hd, &stat);
                inflight = part_in_flight(gp->queue, hd);
+
                seq_printf(seqf, "%4d %7d %s "
                           "%lu %lu %lu %u "
                           "%lu %lu %lu %u "
@@ -1426,23 +1584,31 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                           "\n",
                           MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
                           disk_name(gp, hd->partno, buf),
-                          part_stat_read(hd, ios[STAT_READ]),
-                          part_stat_read(hd, merges[STAT_READ]),
-                          part_stat_read(hd, sectors[STAT_READ]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_READ),
-                          part_stat_read(hd, ios[STAT_WRITE]),
-                          part_stat_read(hd, merges[STAT_WRITE]),
-                          part_stat_read(hd, sectors[STAT_WRITE]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_WRITE),
+                          stat.ios[STAT_READ],
+                          stat.merges[STAT_READ],
+                          stat.sectors[STAT_READ],
+                          (unsigned int)div_u64(stat.nsecs[STAT_READ],
+                                                       NSEC_PER_MSEC),
+                          stat.ios[STAT_WRITE],
+                          stat.merges[STAT_WRITE],
+                          stat.sectors[STAT_WRITE],
+                          (unsigned int)div_u64(stat.nsecs[STAT_WRITE],
+                                                       NSEC_PER_MSEC),
                           inflight,
-                          jiffies_to_msecs(part_stat_read(hd, io_ticks)),
-                          jiffies_to_msecs(part_stat_read(hd, time_in_queue)),
-                          part_stat_read(hd, ios[STAT_DISCARD]),
-                          part_stat_read(hd, merges[STAT_DISCARD]),
-                          part_stat_read(hd, sectors[STAT_DISCARD]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD),
-                          part_stat_read(hd, ios[STAT_FLUSH]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_FLUSH)
+                          jiffies_to_msecs(stat.io_ticks),
+                          (unsigned int)div_u64(stat.nsecs[STAT_READ] +
+                                                stat.nsecs[STAT_WRITE] +
+                                                stat.nsecs[STAT_DISCARD] +
+                                                stat.nsecs[STAT_FLUSH],
+                                                       NSEC_PER_MSEC),
+                          stat.ios[STAT_DISCARD],
+                          stat.merges[STAT_DISCARD],
+                          stat.sectors[STAT_DISCARD],
+                          (unsigned int)div_u64(stat.nsecs[STAT_DISCARD],
+                                                NSEC_PER_MSEC),
+                          stat.ios[STAT_FLUSH],
+                          (unsigned int)div_u64(stat.nsecs[STAT_FLUSH],
+                                                NSEC_PER_MSEC)
                        );
        }
        disk_part_iter_exit(&piter);
@@ -1499,7 +1665,6 @@ dev_t blk_lookup_devt(const char *name, int partno)
        class_dev_iter_exit(&iter);
        return devt;
 }
-EXPORT_SYMBOL(blk_lookup_devt);
 
 struct gendisk *__alloc_disk_node(int minors, int node_id)
 {