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        disk->flags |= GENHD_FL_UP;
 186        blk_register_region(MKDEV(disk->major, disk->first_minor),
 187                            disk->minors, NULL, exact_match, exact_lock, disk);
 188        register_disk(disk);
 189        blk_register_queue(disk);
 190}
 191
 192EXPORT_SYMBOL(add_disk);
 193EXPORT_SYMBOL(del_gendisk);     /* in partitions/check.c */
 194
 195void unlink_gendisk(struct gendisk *disk)
 196{
 197        blk_unregister_queue(disk);
 198        blk_unregister_region(MKDEV(disk->major, disk->first_minor),
 199                              disk->minors);
 200}
 201
 202/**
 203 * get_gendisk - get partitioning information for a given device
 204 * @dev: device to get partitioning information for
 205 *
 206 * This function gets the structure containing partitioning
 207 * information for the given device @dev.
 208 */
 209struct gendisk *get_gendisk(dev_t devt, int *part)
 210{
 211        struct kobject *kobj = kobj_lookup(bdev_map, devt, part);
 212        struct device *dev = kobj_to_dev(kobj);
 213
 214        return  kobj ? dev_to_disk(dev) : NULL;
 215}
 216
 217/*
 218 * print a full list of all partitions - intended for places where the root
 219 * filesystem can't be mounted and thus to give the victim some idea of what
 220 * went wrong
 221 */
 222void __init printk_all_partitions(void)
 223{
 224        struct device *dev;
 225        struct gendisk *sgp;
 226        char buf[BDEVNAME_SIZE];
 227        int n;
 228
 229        mutex_lock(&block_class_lock);
 230        /* For each block device... */
 231        list_for_each_entry(dev, &block_class.devices, node) {
 232                if (dev->type != &disk_type)
 233                        continue;
 234                sgp = dev_to_disk(dev);
 235                /*
 236                 * Don't show empty devices or things that have been surpressed
 237                 */
 238                if (get_capacity(sgp) == 0 ||
 239                    (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
 240                        continue;
 241
 242                /*
 243                 * Note, unlike /proc/partitions, I am showing the numbers in
 244                 * hex - the same format as the root= option takes.
 245                 */
 246                printk("%02x%02x %10llu %s",
 247                        sgp->major, sgp->first_minor,
 248                        (unsigned long long)get_capacity(sgp) >> 1,
 249                        disk_name(sgp, 0, buf));
 250                if (sgp->driverfs_dev != NULL &&
 251                    sgp->driverfs_dev->driver != NULL)
 252                        printk(" driver: %s\n",
 253                                sgp->driverfs_dev->driver->name);
 254                else
 255                        printk(" (driver?)\n");
 256
 257                /* now show the partitions */
 258                for (n = 0; n < sgp->minors - 1; ++n) {
 259                        if (sgp->part[n] == NULL)
 260                                continue;
 261                        if (sgp->part[n]->nr_sects == 0)
 262                                continue;
 263                        printk("  %02x%02x %10llu %s\n",
 264                                sgp->major, n + 1 + sgp->first_minor,
 265                                (unsigned long long)sgp->part[n]->nr_sects >> 1,
 266                                disk_name(sgp, n + 1, buf));
 267                }
 268        }
 269
 270        mutex_unlock(&block_class_lock);
 271}
 272
 273#ifdef CONFIG_PROC_FS
 274/* iterator */
 275static void *part_start(struct seq_file *part, loff_t *pos)
 276{
 277        loff_t k = *pos;
 278        struct device *dev;
 279
 280        mutex_lock(&block_class_lock);
 281        list_for_each_entry(dev, &block_class.devices, node) {
 282                if (dev->type != &disk_type)
 283                        continue;
 284                if (!k--)
 285                        return dev_to_disk(dev);
 286        }
 287        return NULL;
 288}
 289
 290static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 291{
 292        struct gendisk *gp = v;
 293        struct device *dev;
 294        ++*pos;
 295        list_for_each_entry(dev, &gp->dev.node, node) {
 296                if (&dev->node == &block_class.devices)
 297                        return NULL;
 298                if (dev->type == &disk_type)
 299                        return dev_to_disk(dev);
 300        }
 301        return NULL;
 302}
 303
 304static void part_stop(struct seq_file *part, void *v)
 305{
 306        mutex_unlock(&block_class_lock);
 307}
 308
 309static int show_partition(struct seq_file *part, void *v)
 310{
 311        struct gendisk *sgp = v;
 312        int n;
 313        char buf[BDEVNAME_SIZE];
 314
 315        if (&sgp->dev.node == block_class.devices.next)
 316                seq_puts(part, "major minor  #blocks  name\n\n");
 317
 318        /* Don't show non-partitionable removeable devices or empty devices */
 319        if (!get_capacity(sgp) ||
 320                        (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
 321                return 0;
 322        if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
 323                return 0;
 324
 325        /* show the full disk and all non-0 size partitions of it */
 326        seq_printf(part, "%4d  %4d %10llu %s\n",
 327                sgp->major, sgp->first_minor,
 328                (unsigned long long)get_capacity(sgp) >> 1,
 329                disk_name(sgp, 0, buf));
 330        for (n = 0; n < sgp->minors - 1; n++) {
 331                if (!sgp->part[n])
 332                        continue;
 333                if (sgp->part[n]->nr_sects == 0)
 334                        continue;
 335                seq_printf(part, "%4d  %4d %10llu %s\n",
 336                        sgp->major, n + 1 + sgp->first_minor,
 337                        (unsigned long long)sgp->part[n]->nr_sects >> 1 ,
 338                        disk_name(sgp, n + 1, buf));
 339        }
 340
 341        return 0;
 342}
 343
 344const struct seq_operations partitions_op = {
 345        .start  = part_start,
 346        .next   = part_next,
 347        .stop   = part_stop,
 348        .show   = show_partition
 349};
 350#endif
 351
 352
 353static struct kobject *base_probe(dev_t devt, int *part, void *data)
 354{
 355        if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
 356                /* Make old-style 2.4 aliases work */
 357                request_module("block-major-%d", MAJOR(devt));
 358        return NULL;
 359}
 360
 361static int __init genhd_device_init(void)
 362{
 363        int error = class_register(&block_class);
 364        if (unlikely(error))
 365                return error;
 366        bdev_map = kobj_map_init(base_probe, &block_class_lock);
 367        blk_dev_init();
 368
 369#ifndef CONFIG_SYSFS_DEPRECATED
 370        /* create top-level block dir */
 371        block_depr = kobject_create_and_add("block", NULL);
 372#endif
 373        return 0;
 374}
 375
 376subsys_initcall(genhd_device_init);
 377
 378static ssize_t disk_range_show(struct device *dev,
 379                               struct device_attribute *attr, char *buf)
 380{
 381        struct gendisk *disk = dev_to_disk(dev);
 382
 383        return sprintf(buf, "%d\n", disk->minors);
 384}
 385
 386static ssize_t disk_removable_show(struct device *dev,
 387                                   struct device_attribute *attr, char *buf)
 388{
 389        struct gendisk *disk = dev_to_disk(dev);
 390
 391        return sprintf(buf, "%d\n",
 392                       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
 393}
 394
 395static ssize_t disk_size_show(struct device *dev,
 396                              struct device_attribute *attr, char *buf)
 397{
 398        struct gendisk *disk = dev_to_disk(dev);
 399
 400        return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk));
 401}
 402
 403static ssize_t disk_capability_show(struct device *dev,
 404                                    struct device_attribute *attr, char *buf)
 405{
 406        struct gendisk *disk = dev_to_disk(dev);
 407
 408        return sprintf(buf, "%x\n", disk->flags);
 409}
 410
 411static ssize_t disk_stat_show(struct device *dev,
 412                              struct device_attribute *attr, char *buf)
 413{
 414        struct gendisk *disk = dev_to_disk(dev);
 415
 416        preempt_disable();
 417        disk_round_stats(disk);
 418        preempt_enable();
 419        return sprintf(buf,
 420                "%8lu %8lu %8llu %8u "
 421                "%8lu %8lu %8llu %8u "
 422                "%8u %8u %8u"
 423                "\n",
 424                disk_stat_read(disk, ios[READ]),
 425                disk_stat_read(disk, merges[READ]),
 426                (unsigned long long)disk_stat_read(disk, sectors[READ]),
 427                jiffies_to_msecs(disk_stat_read(disk, ticks[READ])),
 428                disk_stat_read(disk, ios[WRITE]),
 429                disk_stat_read(disk, merges[WRITE]),
 430                (unsigned long long)disk_stat_read(disk, sectors[WRITE]),
 431                jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])),
 432                disk->in_flight,
 433                jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
 434                jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 435}
 436
 437#ifdef CONFIG_FAIL_MAKE_REQUEST
 438static ssize_t disk_fail_show(struct device *dev,
 439                              struct device_attribute *attr, char *buf)
 440{
 441        struct gendisk *disk = dev_to_disk(dev);
 442
 443        return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
 444}
 445
 446static ssize_t disk_fail_store(struct device *dev,
 447                               struct device_attribute *attr,
 448                               const char *buf, size_t count)
 449{
 450        struct gendisk *disk = dev_to_disk(dev);
 451        int i;
 452
 453        if (count > 0 && sscanf(buf, "%d", &i) > 0) {
 454                if (i == 0)
 455                        disk->flags &= ~GENHD_FL_FAIL;
 456                else
 457                        disk->flags |= GENHD_FL_FAIL;
 458        }
 459
 460        return count;
 461}
 462
 463#endif
 464
 465static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
 466static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 467static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL);
 468static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 469static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
 470#ifdef CONFIG_FAIL_MAKE_REQUEST
 471static struct device_attribute dev_attr_fail =
 472        __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store);
 473#endif
 474
 475static struct attribute *disk_attrs[] = {
 476        &dev_attr_range.attr,
 477        &dev_attr_removable.attr,
 478        &dev_attr_size.attr,
 479        &dev_attr_capability.attr,
 480        &dev_attr_stat.attr,
 481#ifdef CONFIG_FAIL_MAKE_REQUEST
 482        &dev_attr_fail.attr,
 483#endif
 484        NULL
 485};
 486
 487static struct attribute_group disk_attr_group = {
 488        .attrs = disk_attrs,
 489};
 490
 491static struct attribute_group *disk_attr_groups[] = {
 492        &disk_attr_group,
 493        NULL
 494};
 495
 496static void disk_release(struct device *dev)
 497{
 498        struct gendisk *disk = dev_to_disk(dev);
 499
 500        kfree(disk->random);
 501        kfree(disk->part);
 502        free_disk_stats(disk);
 503        kfree(disk);
 504}
 505struct class block_class = {
 506        .name           = "block",
 507};
 508
 509static struct device_type disk_type = {
 510        .name           = "disk",
 511        .groups         = disk_attr_groups,
 512        .release        = disk_release,
 513};
 514
 515/*
 516 * aggregate disk stat collector.  Uses the same stats that the sysfs
 517 * entries do, above, but makes them available through one seq_file.
 518 *
 519 * The output looks suspiciously like /proc/partitions with a bunch of
 520 * extra fields.
 521 */
 522
 523static void *diskstats_start(struct seq_file *part, loff_t *pos)
 524{
 525        loff_t k = *pos;
 526        struct device *dev;
 527
 528        mutex_lock(&block_class_lock);
 529        list_for_each_entry(dev, &block_class.devices, node) {
 530                if (dev->type != &disk_type)
 531                        continue;
 532                if (!k--)
 533                        return dev_to_disk(dev);
 534        }
 535        return NULL;
 536}
 537
 538static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 539{
 540        struct gendisk *gp = v;
 541        struct device *dev;
 542
 543        ++*pos;
 544        list_for_each_entry(dev, &gp->dev.node, node) {
 545                if (&dev->node == &block_class.devices)
 546                        return NULL;
 547                if (dev->type == &disk_type)
 548                        return dev_to_disk(dev);
 549        }
 550        return NULL;
 551}
 552
 553static void diskstats_stop(struct seq_file *part, void *v)
 554{
 555        mutex_unlock(&block_class_lock);
 556}
 557
 558static int diskstats_show(struct seq_file *s, void *v)
 559{
 560        struct gendisk *gp = v;
 561        char buf[BDEVNAME_SIZE];
 562        int n = 0;
 563
 564        /*
 565        if (&gp->dev.kobj.entry == block_class.devices.next)
 566                seq_puts(s,     "major minor name"
 567                                "     rio rmerge rsect ruse wio wmerge "
 568                                "wsect wuse running use aveq"
 569                                "\n\n");
 570        */
 571 
 572        preempt_disable();
 573        disk_round_stats(gp);
 574        preempt_enable();
 575        seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
 576                gp->major, n + gp->first_minor, disk_name(gp, n, buf),
 577                disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
 578                (unsigned long long)disk_stat_read(gp, sectors[0]),
 579                jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
 580                disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
 581                (unsigned long long)disk_stat_read(gp, sectors[1]),
 582                jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
 583                gp->in_flight,
 584                jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
 585                jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
 586
 587        /* now show all non-0 size partitions of it */
 588        for (n = 0; n < gp->minors - 1; n++) {
 589                struct hd_struct *hd = gp->part[n];
 590
 591                if (!hd || !hd->nr_sects)
 592                        continue;
 593
 594                preempt_disable();
 595                part_round_stats(hd);
 596                preempt_enable();
 597                seq_printf(s, "%4d %4d %s %lu %lu %llu "
 598                           "%u %lu %lu %llu %u %u %u %u\n",
 599                           gp->major, n + gp->first_minor + 1,
 600                           disk_name(gp, n + 1, buf),
 601                           part_stat_read(hd, ios[0]),
 602                           part_stat_read(hd, merges[0]),
 603                           (unsigned long long)part_stat_read(hd, sectors[0]),
 604                           jiffies_to_msecs(part_stat_read(hd, ticks[0])),
 605                           part_stat_read(hd, ios[1]),
 606                           part_stat_read(hd, merges[1]),
 607                           (unsigned long long)part_stat_read(hd, sectors[1]),
 608                           jiffies_to_msecs(part_stat_read(hd, ticks[1])),
 609                           hd->in_flight,
 610                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
 611                           jiffies_to_msecs(part_stat_read(hd, time_in_queue))
 612                        );
 613        }
 614 
 615        return 0;
 616}
 617
 618const struct seq_operations diskstats_op = {
 619        .start  = diskstats_start,
 620        .next   = diskstats_next,
 621        .stop   = diskstats_stop,
 622        .show   = diskstats_show
 623};
 624
 625static void media_change_notify_thread(struct work_struct *work)
 626{
 627        struct gendisk *gd = container_of(work, struct gendisk, async_notify);
 628        char event[] = "MEDIA_CHANGE=1";
 629        char *envp[] = { event, NULL };
 630
 631        /*
 632         * set enviroment vars to indicate which event this is for
 633         * so that user space will know to go check the media status.
 634         */
 635        kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp);
 636        put_device(gd->driverfs_dev);
 637}
 638
 639#if 0
 640void genhd_media_change_notify(struct gendisk *disk)
 641{
 642        get_device(disk->driverfs_dev);
 643        schedule_work(&disk->async_notify);
 644}
 645EXPORT_SYMBOL_GPL(genhd_media_change_notify);
 646#endif  /*  0  */
 647
 648dev_t blk_lookup_devt(const char *name)
 649{
 650        struct device *dev;
 651        dev_t devt = MKDEV(0, 0);
 652
 653        mutex_lock(&block_class_lock);
 654        list_for_each_entry(dev, &block_class.devices, node) {
 655                if (strcmp(dev->bus_id, name) == 0) {
 656                        devt = dev->devt;
 657                        break;
 658                }
 659        }
 660        mutex_unlock(&block_class_lock);
 661
 662        return devt;
 663}
 664
 665EXPORT_SYMBOL(blk_lookup_devt);
 666
 667struct gendisk *alloc_disk(int minors)
 668{
 669        return alloc_disk_node(minors, -1);
 670}
 671
 672struct gendisk *alloc_disk_node(int minors, int node_id)
 673{
 674        struct gendisk *disk;
 675
 676        disk = kmalloc_node(sizeof(struct gendisk),
 677                                GFP_KERNEL | __GFP_ZERO, node_id);
 678        if (disk) {
 679                if (!init_disk_stats(disk)) {
 680                        kfree(disk);
 681                        return NULL;
 682                }
 683                if (minors > 1) {
 684                        int size = (minors - 1) * sizeof(struct hd_struct *);
 685                        disk->part = kmalloc_node(size,
 686                                GFP_KERNEL | __GFP_ZERO, node_id);
 687                        if (!disk->part) {
 688                                free_disk_stats(disk);
 689                                kfree(disk);
 690                                return NULL;
 691                        }
 692                }
 693                disk->minors = minors;
 694                rand_initialize_disk(disk);
 695                disk->dev.class = &block_class;
 696                disk->dev.type = &disk_type;
 697                device_initialize(&disk->dev);
 698                INIT_WORK(&disk->async_notify,
 699                        media_change_notify_thread);
 700        }
 701        return disk;
 702}
 703
 704EXPORT_SYMBOL(alloc_disk);
 705EXPORT_SYMBOL(alloc_disk_node);
 706
 707struct kobject *get_disk(struct gendisk *disk)
 708{
 709        struct module *owner;
 710        struct kobject *kobj;
 711
 712        if (!disk->fops)
 713                return NULL;
 714        owner = disk->fops->owner;
 715        if (owner && !try_module_get(owner))
 716                return NULL;
 717        kobj = kobject_get(&disk->dev.kobj);
 718        if (kobj == NULL) {
 719                module_put(owner);
 720                return NULL;
 721        }
 722        return kobj;
 723
 724}
 725
 726EXPORT_SYMBOL(get_disk);
 727
 728void put_disk(struct gendisk *disk)
 729{
 730        if (disk)
 731                kobject_put(&disk->dev.kobj);
 732}
 733
 734EXPORT_SYMBOL(put_disk);
 735
 736void set_device_ro(struct block_device *bdev, int flag)
 737{
 738        if (bdev->bd_contains != bdev)
 739                bdev->bd_part->policy = flag;
 740        else
 741                bdev->bd_disk->policy = flag;
 742}
 743
 744EXPORT_SYMBOL(set_device_ro);
 745
 746void set_disk_ro(struct gendisk *disk, int flag)
 747{
 748        int i;
 749        disk->policy = flag;
 750        for (i = 0; i < disk->minors - 1; i++)
 751                if (disk->part[i]) disk->part[i]->policy = flag;
 752}
 753
 754EXPORT_SYMBOL(set_disk_ro);
 755
 756int bdev_read_only(struct block_device *bdev)
 757{
 758        if (!bdev)
 759                return 0;
 760        else if (bdev->bd_contains != bdev)
 761                return bdev->bd_part->policy;
 762        else
 763                return bdev->bd_disk->policy;
 764}
 765
 766EXPORT_SYMBOL(bdev_read_only);
 767
 768int invalidate_partition(struct gendisk *disk, int index)
 769{
 770        int res = 0;
 771        struct block_device *bdev = bdget_disk(disk, index);
 772        if (bdev) {
 773                fsync_bdev(bdev);
 774                res = __invalidate_device(bdev);
 775                bdput(bdev);
 776        }
 777        return res;
 778}
 779
 780EXPORT_SYMBOL(invalidate_partition);
 781
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.