linux/block/genhd.c
<<
>>
Prefs
   1/*
   2 *  gendisk handling
   3 */
   4
   5#include <linux/module.h>
   6#include <linux/fs.h>
   7#include <linux/genhd.h>
   8#include <linux/kdev_t.h>
   9#include <linux/kernel.h>
  10#include <linux/blkdev.h>
  11#include <linux/init.h>
  12#include <linux/spinlock.h>
  13#include <linux/seq_file.h>
  14#include <linux/slab.h>
  15#include <linux/kmod.h>
  16#include <linux/kobj_map.h>
  17#include <linux/buffer_head.h>
  18#include <linux/mutex.h>
  19
  20#include "blk.h"
  21
  22static DEFINE_MUTEX(block_class_lock);
  23#ifndef CONFIG_SYSFS_DEPRECATED
  24struct kobject *block_depr;
  25#endif
  26
  27static struct device_type disk_type;
  28
  29/*
  30 * Can be deleted altogether. Later.
  31 *
  32 */
  33static struct blk_major_name {
  34        struct blk_major_name *next;
  35        int major;
  36        char name[16];
  37} *major_names[BLKDEV_MAJOR_HASH_SIZE];
  38
  39/* index in the above - for now: assume no multimajor ranges */
  40static inline int major_to_index(int major)
  41{
  42        return major % BLKDEV_MAJOR_HASH_SIZE;
  43}
  44
  45#ifdef CONFIG_PROC_FS
  46void blkdev_show(struct seq_file *f, off_t offset)
  47{
  48        struct blk_major_name *dp;
  49
  50        if (offset < BLKDEV_MAJOR_HASH_SIZE) {
  51                mutex_lock(&block_class_lock);
  52                for (dp = major_names[offset]; dp; dp = dp->next)
  53                        seq_printf(f, "%3d %s\n", dp->major, dp->name);
  54                mutex_unlock(&block_class_lock);
  55        }
  56}
  57#endif /* CONFIG_PROC_FS */
  58
  59int register_blkdev(unsigned int major, const char *name)
  60{
  61        struct blk_major_name **n, *p;
  62        int index, ret = 0;
  63
  64        mutex_lock(&block_class_lock);
  65
  66        /* temporary */
  67        if (major == 0) {
  68                for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
  69                        if (major_names[index] == NULL)
  70                                break;
  71                }
  72
  73                if (index == 0) {
  74                        printk("register_blkdev: failed to get major for %s\n",
  75                               name);
  76                        ret = -EBUSY;
  77                        goto out;
  78                }
  79                major = index;
  80                ret = major;
  81        }
  82
  83        p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
  84        if (p == NULL) {
  85                ret = -ENOMEM;
  86                goto out;
  87        }
  88
  89        p->major = major;
  90        strlcpy(p->name, name, sizeof(p->name));
  91        p->next = NULL;
  92        index = major_to_index(major);
  93
  94        for (n = &major_names[index]; *n; n = &(*n)->next) {
  95                if ((*n)->major == major)
  96                        break;
  97        }
  98        if (!*n)
  99                *n = p;
 100        else
 101                ret = -EBUSY;
 102
 103        if (ret < 0) {
 104                printk("register_blkdev: cannot get major %d for %s\n",
 105                       major, name);
 106                kfree(p);
 107        }
 108out:
 109        mutex_unlock(&block_class_lock);
 110        return ret;
 111}
 112
 113EXPORT_SYMBOL(register_blkdev);
 114
 115void unregister_blkdev(unsigned int major, const char *name)
 116{
 117        struct blk_major_name **n;
 118        struct blk_major_name *p = NULL;
 119        int index = major_to_index(major);
 120
 121        mutex_lock(&block_class_lock);
 122        for (n = &major_names[index]; *n; n = &(*n)->next)
 123                if ((*n)->major == major)
 124                        break;
 125        if (!*n || strcmp((*n)->name, name)) {
 126                WARN_ON(1);
 127        } else {
 128                p = *n;
 129                *n = p->next;
 130        }
 131        mutex_unlock(&block_class_lock);
 132        kfree(p);
 133}
 134
 135EXPORT_SYMBOL(unregister_blkdev);
 136
 137static struct kobj_map *bdev_map;
 138
 139/*
 140 * Register device numbers dev..(dev+range-1)
 141 * range must be nonzero
 142 * The hash chain is sorted on range, so that subranges can override.
 143 */
 144void blk_register_region(dev_t devt, unsigned long range, struct module *module,
 145                         struct kobject *(*probe)(dev_t, int *, void *),
 146                         int (*lock)(dev_t, void *), void *data)
 147{
 148        kobj_map(bdev_map, devt, range, module, probe, lock, data);
 149}
 150
 151EXPORT_SYMBOL(blk_register_region);
 152
 153void blk_unregister_region(dev_t devt, unsigned long range)
 154{
 155        kobj_unmap(bdev_map, devt, range);
 156}
 157
 158EXPORT_SYMBOL(blk_unregister_region);
 159
 160static struct kobject *exact_match(dev_t devt, int *part, void *data)
 161{
 162        struct gendisk *p = data;
 163
 164        return &p->dev.kobj;
 165}
 166
 167static int exact_lock(dev_t devt, void *data)
 168{
 169        struct gendisk *p = data;
 170
 171        if (!get_disk(p))
 172                return -1;
 173        return 0;
 174}
 175
 176/**
 177 * add_disk - add partitioning information to kernel list
 178 * @disk: per-device partitioning information
 179 *
 180 * This function registers the partitioning information in @disk
 181 * with the kernel.
 182 */
 183void add_disk(struct gendisk *disk)
 184{
 185        struct backing_dev_info *bdi;
 186        int retval;
 187
 188        disk->flags |= GENHD_FL_UP;
 189        blk_register_region(MKDEV(disk->major, disk->first_minor),
 190                            disk->minors, NULL, exact_match, exact_lock, disk);
 191        register_disk(disk);
 192        blk_register_queue(disk);
 193
 194        bdi = &disk->queue->backing_dev_info;
 195        bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
 196        retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
 197        WARN_ON(retval);
 198}
 199
 200EXPORT_SYMBOL(add_disk);
 201EXPORT_SYMBOL(del_gendisk);     /* in partitions/check.c */
 202
 203void unlink_gendisk(struct gendisk *disk)
 204{
 205        sysfs_remove_link(&disk->dev.kobj, "bdi");
 206        bdi_unregister(&disk->queue->backing_dev_info);
 207        blk_unregister_queue(disk);
 208        blk_unregister_region(MKDEV(disk->major, disk->first_minor),
 209                              disk->minors);
 210}
 211
 212/**
 213 * get_gendisk - get partitioning information for a given device
 214 * @dev: device to get partitioning information for
 215 *
 216 * This function gets the structure containing partitioning
 217 * information for the given device @dev.
 218 */
 219struct gendisk *get_gendisk(dev_t devt, int *part)
 220{
 221        struct kobject *kobj = kobj_lookup(bdev_map, devt, part);
 222        struct device *dev = kobj_to_dev(kobj);
 223
 224        return  kobj ? dev_to_disk(dev) : NULL;
 225}
 226
 227/*
 228 * print a partitions - intended for places where the root filesystem can't be
 229 * mounted and thus to give the victim some idea of what went wrong
 230 */
 231static int printk_partition(struct device *dev, void *data)
 232{
 233        struct gendisk *sgp;
 234        char buf[BDEVNAME_SIZE];
 235        int n;
 236
 237        if (dev->type != &disk_type)
 238                goto exit;
 239
 240        sgp = dev_to_disk(dev);
 241        /*
 242         * Don't show empty devices or things that have been surpressed
 243         */
 244        if (get_capacity(sgp) == 0 ||
 245            (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
 246                goto exit;
 247
 248        /*
 249         * Note, unlike /proc/partitions, I am showing the numbers in
 250         * hex - the same format as the root= option takes.
 251         */
 252        printk("%02x%02x %10llu %s",
 253                sgp->major, sgp->first_minor,
 254                (unsigned long long)get_capacity(sgp) >> 1,
 255                disk_name(sgp, 0, buf));
 256        if (sgp->driverfs_dev != NULL &&
 257            sgp->driverfs_dev->driver != NULL)
 258                printk(" driver: %s\n",
 259                        sgp->driverfs_dev->driver->name);
 260        else
 261                printk(" (driver?)\n");
 262
 263        /* now show the partitions */
 264        for (n = 0; n < sgp->minors - 1; ++n) {
 265                if (sgp->part[n] == NULL)
 266                        goto exit;
 267                if (sgp->part[n]->nr_sects == 0)
 268                        goto exit;
 269                printk("  %02x%02x %10llu %s\n",
 270                        sgp->major, n + 1 + sgp->first_minor,
 271                        (unsigned long long)sgp->part[n]->nr_sects >> 1,
 272                        disk_name(sgp, n + 1, buf));
 273        }
 274exit:
 275        return 0;
 276}
 277
 278/*
 279 * print a full list of all partitions - intended for places where the root
 280 * filesystem can't be mounted and thus to give the victim some idea of what
 281 * went wrong
 282 */
 283void __init printk_all_partitions(void)
 284{
 285        mutex_lock(&block_class_lock);
 286        class_for_each_device(&block_class, NULL, NULL, printk_partition);
 287        mutex_unlock(&block_class_lock);
 288}
 289
 290#ifdef CONFIG_PROC_FS
 291/* iterator */
 292static int find_start(struct device *dev, void *data)
 293{
 294        loff_t *k = data;
 295
 296        if (dev->type != &disk_type)
 297                return 0;
 298        if (!*k)
 299                return 1;
 300        (*k)--;
 301        return 0;
 302}
 303
 304static void *part_start(struct seq_file *part, loff_t *pos)
 305{
 306        struct device *dev;
 307        loff_t k = *pos;
 308
 309        if (!k)
 310                part->private = (void *)1LU;    /* tell show to print header */
 311
 312        mutex_lock(&block_class_lock);
 313        dev = class_find_device(&block_class, NULL, &k, find_start);
 314        if (dev) {
 315                put_device(dev);
 316                return dev_to_disk(dev);
 317        }
 318        return NULL;
 319}
 320
 321static int find_next(struct device *dev, void *data)
 322{
 323        if (dev->type == &disk_type)
 324                return 1;
 325        return 0;
 326}
 327
 328static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 329{
 330        struct gendisk *gp = v;
 331        struct device *dev;
 332        ++*pos;
 333        dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
 334        if (dev) {
 335                put_device(dev);
 336                return dev_to_disk(dev);
 337        }
 338        return NULL;
 339}
 340
 341static void part_stop(struct seq_file *part, void *v)
 342{
 343        mutex_unlock(&block_class_lock);
 344}
 345
 346static int show_partition(struct seq_file *part, void *v)
 347{
 348        struct gendisk *sgp = v;
 349        int n;
 350        char buf[BDEVNAME_SIZE];
 351
 352        /*
 353         * Print header if start told us to do.  This is to preserve
 354         * the original behavior of not printing header if no
 355         * partition exists.  This hackery will be removed later with
 356         * class iteration clean up.
 357         */
 358        if (part->private) {
 359                seq_puts(part, "major minor  #blocks  name\n\n");
 360                part->private = NULL;
 361        }
 362
 363        /* Don't show non-partitionable removeable devices or empty devices */
 364        if (!get_capacity(sgp) ||
 365                        (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
 366                return 0;
 367        if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
 368                return 0;
 369
 370        /* show the full disk and all non-0 size partitions of it */
 371        seq_printf(part, "%4d  %4d %10llu %s\n",
 372                sgp->major, sgp->first_minor,
 373                (unsigned long long)get_capacity(sgp) >> 1,
 374                disk_name(sgp, 0, buf));
 375        for (n = 0; n < sgp->minors - 1; n++) {
 376                if (!sgp->part[n])
 377                        continue;
 378                if (sgp->part[n]->nr_sects == 0)
 379                        continue;
 380                seq_printf(part, "%4d  %4d %10llu %s\n",
 381                        sgp->major, n + 1 + sgp->first_minor,
 382                        (unsigned long long)sgp->part[n]->nr_sects >> 1 ,
 383                        disk_name(sgp, n + 1, buf));
 384        }
 385
 386        return 0;
 387}
 388
 389const struct seq_operations partitions_op = {
 390        .start  = part_start,
 391        .next   = part_next,
 392        .stop   = part_stop,
 393        .show   = show_partition
 394};
 395#endif
 396
 397
 398static struct kobject *base_probe(dev_t devt, int *part, void *data)
 399{
 400        if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
 401                /* Make old-style 2.4 aliases work */
 402                request_module("block-major-%d", MAJOR(devt));
 403        return NULL;
 404}
 405
 406static int __init genhd_device_init(void)
 407{
 408        int error;
 409
 410        block_class.dev_kobj = sysfs_dev_block_kobj;
 411        error = class_register(&block_class);
 412        if (unlikely(error))
 413                return error;
 414        bdev_map = kobj_map_init(base_probe, &block_class_lock);
 415        blk_dev_init();
 416
 417#ifndef CONFIG_SYSFS_DEPRECATED
 418        /* create top-level block dir */
 419        block_depr = kobject_create_and_add("block", NULL);
 420#endif
 421        return 0;
 422}
 423
 424subsys_initcall(genhd_device_init);
 425
 426static ssize_t disk_range_show(struct device *dev,
 427                               struct device_attribute *attr, char *buf)
 428{
 429        struct gendisk *disk = dev_to_disk(dev);
 430
 431        return sprintf(buf, "%d\n", disk->minors);
 432}
 433
 434static ssize_t disk_removable_show(struct device *dev,
 435                                   struct device_attribute *attr, char *buf)
 436{
 437        struct gendisk *disk = dev_to_disk(dev);
 438
 439        return sprintf(buf, "%d\n",
 440                       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
 441}
 442
 443static ssize_t disk_ro_show(struct device *dev,
 444                                   struct device_attribute *attr, char *buf)
 445{
 446        struct gendisk *disk = dev_to_disk(dev);
 447
 448        return sprintf(buf, "%d\n", disk->policy ? 1 : 0);
 449}
 450
 451static ssize_t disk_size_show(struct device *dev,
 452                              struct device_attribute *attr, char *buf)
 453{
 454        struct gendisk *disk = dev_to_disk(dev);
 455
 456        return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk));
 457}
 458
 459static ssize_t disk_capability_show(struct device *dev,
 460                                    struct device_attribute *attr, char *buf)
 461{
 462        struct gendisk *disk = dev_to_disk(dev);
 463
 464        return sprintf(buf, "%x\n", disk->flags);
 465}
 466
 467static ssize_t disk_stat_show(struct device *dev,
 468                              struct device_attribute *attr, char *buf)
 469{
 470        struct gendisk *disk = dev_to_disk(dev);
 471
 472        preempt_disable();
 473        disk_round_stats(disk);
 474        preempt_enable();
 475        return sprintf(buf,
 476                "%8lu %8lu %8llu %8u "
 477                "%8lu %8lu %8llu %8u "
 478                "%8u %8u %8u"
 479                "\n",
 480                disk_stat_read(disk, ios[READ]),
 481                disk_stat_read(disk, merges[READ]),
 482                (unsigned long long)disk_stat_read(disk, sectors[READ]),
 483                jiffies_to_msecs(disk_stat_read(disk, ticks[READ])),
 484                disk_stat_read(disk, ios[WRITE]),
 485                disk_stat_read(disk, merges[WRITE]),
 486                (unsigned long long)disk_stat_read(disk, sectors[WRITE]),
 487                jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])),
 488                disk->in_flight,
 489                jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
 490                jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 491}
 492
 493#ifdef CONFIG_FAIL_MAKE_REQUEST
 494static ssize_t disk_fail_show(struct device *dev,
 495                              struct device_attribute *attr, char *buf)
 496{
 497        struct gendisk *disk = dev_to_disk(dev);
 498
 499        return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
 500}
 501
 502static ssize_t disk_fail_store(struct device *dev,
 503                               struct device_attribute *attr,
 504                               const char *buf, size_t count)
 505{
 506        struct gendisk *disk = dev_to_disk(dev);
 507        int i;
 508
 509        if (count > 0 && sscanf(buf, "%d", &i) > 0) {
 510                if (i == 0)
 511                        disk->flags &= ~GENHD_FL_FAIL;
 512                else
 513                        disk->flags |= GENHD_FL_FAIL;
 514        }
 515
 516        return count;
 517}
 518
 519#endif
 520
 521static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
 522static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 523static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
 524static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
 525static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 526static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
 527#ifdef CONFIG_FAIL_MAKE_REQUEST
 528static struct device_attribute dev_attr_fail =
 529        __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store);
 530#endif
 531
 532static struct attribute *disk_attrs[] = {
 533        &dev_attr_range.attr,
 534        &dev_attr_removable.attr,
 535        &dev_attr_ro.attr,
 536        &dev_attr_size.attr,
 537        &dev_attr_capability.attr,
 538        &dev_attr_stat.attr,
 539#ifdef CONFIG_FAIL_MAKE_REQUEST
 540        &dev_attr_fail.attr,
 541#endif
 542        NULL
 543};
 544
 545static struct attribute_group disk_attr_group = {
 546        .attrs = disk_attrs,
 547};
 548
 549static struct attribute_group *disk_attr_groups[] = {
 550        &disk_attr_group,
 551        NULL
 552};
 553
 554static void disk_release(struct device *dev)
 555{
 556        struct gendisk *disk = dev_to_disk(dev);
 557
 558        kfree(disk->random);
 559        kfree(disk->part);
 560        free_disk_stats(disk);
 561        kfree(disk);
 562}
 563struct class block_class = {
 564        .name           = "block",
 565};
 566
 567static struct device_type disk_type = {
 568        .name           = "disk",
 569        .groups         = disk_attr_groups,
 570        .release        = disk_release,
 571};
 572
 573#ifdef CONFIG_PROC_FS
 574/*
 575 * aggregate disk stat collector.  Uses the same stats that the sysfs
 576 * entries do, above, but makes them available through one seq_file.
 577 *
 578 * The output looks suspiciously like /proc/partitions with a bunch of
 579 * extra fields.
 580 */
 581
 582static void *diskstats_start(struct seq_file *part, loff_t *pos)
 583{
 584        struct device *dev;
 585        loff_t k = *pos;
 586
 587        mutex_lock(&block_class_lock);
 588        dev = class_find_device(&block_class, NULL, &k, find_start);
 589        if (dev) {
 590                put_device(dev);
 591                return dev_to_disk(dev);
 592        }
 593        return NULL;
 594}
 595
 596static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 597{
 598        struct gendisk *gp = v;
 599        struct device *dev;
 600
 601        ++*pos;
 602        dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
 603        if (dev) {
 604                put_device(dev);
 605                return dev_to_disk(dev);
 606        }
 607        return NULL;
 608}
 609
 610static void diskstats_stop(struct seq_file *part, void *v)
 611{
 612        mutex_unlock(&block_class_lock);
 613}
 614
 615static int diskstats_show(struct seq_file *s, void *v)
 616{
 617        struct gendisk *gp = v;
 618        char buf[BDEVNAME_SIZE];
 619        int n = 0;
 620
 621        /*
 622        if (&gp->dev.kobj.entry == block_class.devices.next)
 623                seq_puts(s,     "major minor name"
 624                                "     rio rmerge rsect ruse wio wmerge "
 625                                "wsect wuse running use aveq"
 626                                "\n\n");
 627        */
 628 
 629        preempt_disable();
 630        disk_round_stats(gp);
 631        preempt_enable();
 632        seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
 633                gp->major, n + gp->first_minor, disk_name(gp, n, buf),
 634                disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
 635                (unsigned long long)disk_stat_read(gp, sectors[0]),
 636                jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
 637                disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
 638                (unsigned long long)disk_stat_read(gp, sectors[1]),
 639                jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
 640                gp->in_flight,
 641                jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
 642                jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
 643
 644        /* now show all non-0 size partitions of it */
 645        for (n = 0; n < gp->minors - 1; n++) {
 646                struct hd_struct *hd = gp->part[n];
 647
 648                if (!hd || !hd->nr_sects)
 649                        continue;
 650
 651                preempt_disable();
 652                part_round_stats(hd);
 653                preempt_enable();
 654                seq_printf(s, "%4d %4d %s %lu %lu %llu "
 655                           "%u %lu %lu %llu %u %u %u %u\n",
 656                           gp->major, n + gp->first_minor + 1,
 657                           disk_name(gp, n + 1, buf),
 658                           part_stat_read(hd, ios[0]),
 659                           part_stat_read(hd, merges[0]),
 660                           (unsigned long long)part_stat_read(hd, sectors[0]),
 661                           jiffies_to_msecs(part_stat_read(hd, ticks[0])),
 662                           part_stat_read(hd, ios[1]),
 663                           part_stat_read(hd, merges[1]),
 664                           (unsigned long long)part_stat_read(hd, sectors[1]),
 665                           jiffies_to_msecs(part_stat_read(hd, ticks[1])),
 666                           hd->in_flight,
 667                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
 668                           jiffies_to_msecs(part_stat_read(hd, time_in_queue))
 669                        );
 670        }
 671 
 672        return 0;
 673}
 674
 675const struct seq_operations diskstats_op = {
 676        .start  = diskstats_start,
 677        .next   = diskstats_next,
 678        .stop   = diskstats_stop,
 679        .show   = diskstats_show
 680};
 681#endif /* CONFIG_PROC_FS */
 682
 683static void media_change_notify_thread(struct work_struct *work)
 684{
 685        struct gendisk *gd = container_of(work, struct gendisk, async_notify);
 686        char event[] = "MEDIA_CHANGE=1";
 687        char *envp[] = { event, NULL };
 688
 689        /*
 690         * set enviroment vars to indicate which event this is for
 691         * so that user space will know to go check the media status.
 692         */
 693        kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp);
 694        put_device(gd->driverfs_dev);
 695}
 696
 697#if 0
 698void genhd_media_change_notify(struct gendisk *disk)
 699{
 700        get_device(disk->driverfs_dev);
 701        schedule_work(&disk->async_notify);
 702}
 703EXPORT_SYMBOL_GPL(genhd_media_change_notify);
 704#endif  /*  0  */
 705
 706struct find_block {
 707        const char *name;
 708        int part;
 709};
 710
 711static int match_id(struct device *dev, void *data)
 712{
 713        struct find_block *find = data;
 714
 715        if (dev->type != &disk_type)
 716                return 0;
 717        if (strcmp(dev->bus_id, find->name) == 0) {
 718                struct gendisk *disk = dev_to_disk(dev);
 719                if (find->part < disk->minors)
 720                        return 1;
 721        }
 722        return 0;
 723}
 724
 725dev_t blk_lookup_devt(const char *name, int part)
 726{
 727        struct device *dev;
 728        dev_t devt = MKDEV(0, 0);
 729        struct find_block find;
 730
 731        mutex_lock(&block_class_lock);
 732        find.name = name;
 733        find.part = part;
 734        dev = class_find_device(&block_class, NULL, &find, match_id);
 735        if (dev) {
 736                put_device(dev);
 737                devt = MKDEV(MAJOR(dev->devt),
 738                             MINOR(dev->devt) + part);
 739        }
 740        mutex_unlock(&block_class_lock);
 741
 742        return devt;
 743}
 744EXPORT_SYMBOL(blk_lookup_devt);
 745
 746struct gendisk *alloc_disk(int minors)
 747{
 748        return alloc_disk_node(minors, -1);
 749}
 750
 751struct gendisk *alloc_disk_node(int minors, int node_id)
 752{
 753        struct gendisk *disk;
 754
 755        disk = kmalloc_node(sizeof(struct gendisk),
 756                                GFP_KERNEL | __GFP_ZERO, node_id);
 757        if (disk) {
 758                if (!init_disk_stats(disk)) {
 759                        kfree(disk);
 760                        return NULL;
 761                }
 762                if (minors > 1) {
 763                        int size = (minors - 1) * sizeof(struct hd_struct *);
 764                        disk->part = kmalloc_node(size,
 765                                GFP_KERNEL | __GFP_ZERO, node_id);
 766                        if (!disk->part) {
 767                                free_disk_stats(disk);
 768                                kfree(disk);
 769                                return NULL;
 770                        }
 771                }
 772                disk->minors = minors;
 773                rand_initialize_disk(disk);
 774                disk->dev.class = &block_class;
 775                disk->dev.type = &disk_type;
 776                device_initialize(&disk->dev);
 777                INIT_WORK(&disk->async_notify,
 778                        media_change_notify_thread);
 779        }
 780        return disk;
 781}
 782
 783EXPORT_SYMBOL(alloc_disk);
 784EXPORT_SYMBOL(alloc_disk_node);
 785
 786struct kobject *get_disk(struct gendisk *disk)
 787{
 788        struct module *owner;
 789        struct kobject *kobj;
 790
 791        if (!disk->fops)
 792                return NULL;
 793        owner = disk->fops->owner;
 794        if (owner && !try_module_get(owner))
 795                return NULL;
 796        kobj = kobject_get(&disk->dev.kobj);
 797        if (kobj == NULL) {
 798                module_put(owner);
 799                return NULL;
 800        }
 801        return kobj;
 802
 803}
 804
 805EXPORT_SYMBOL(get_disk);
 806
 807void put_disk(struct gendisk *disk)
 808{
 809        if (disk)
 810                kobject_put(&disk->dev.kobj);
 811}
 812
 813EXPORT_SYMBOL(put_disk);
 814
 815void set_device_ro(struct block_device *bdev, int flag)
 816{
 817        if (bdev->bd_contains != bdev)
 818                bdev->bd_part->policy = flag;
 819        else
 820                bdev->bd_disk->policy = flag;
 821}
 822
 823EXPORT_SYMBOL(set_device_ro);
 824
 825void set_disk_ro(struct gendisk *disk, int flag)
 826{
 827        int i;
 828        disk->policy = flag;
 829        for (i = 0; i < disk->minors - 1; i++)
 830                if (disk->part[i]) disk->part[i]->policy = flag;
 831}
 832
 833EXPORT_SYMBOL(set_disk_ro);
 834
 835int bdev_read_only(struct block_device *bdev)
 836{
 837        if (!bdev)
 838                return 0;
 839        else if (bdev->bd_contains != bdev)
 840                return bdev->bd_part->policy;
 841        else
 842                return bdev->bd_disk->policy;
 843}
 844
 845EXPORT_SYMBOL(bdev_read_only);
 846
 847int invalidate_partition(struct gendisk *disk, int index)
 848{
 849        int res = 0;
 850        struct block_device *bdev = bdget_disk(disk, index);
 851        if (bdev) {
 852                fsync_bdev(bdev);
 853                res = __invalidate_device(bdev);
 854                bdput(bdev);
 855        }
 856        return res;
 857}
 858
 859EXPORT_SYMBOL(invalidate_partition);
 860