RHEL5/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/kernel.h>
   9#include <linux/blkdev.h>
  10#include <linux/init.h>
  11#include <linux/spinlock.h>
  12#include <linux/seq_file.h>
  13#include <linux/slab.h>
  14#include <linux/kmod.h>
  15#include <linux/kobj_map.h>
  16#include <linux/buffer_head.h>
  17#include <linux/mutex.h>
  18
  19struct subsystem block_subsys;
  20static DEFINE_MUTEX(block_subsys_lock);
  21
  22/*
  23 * Can be deleted altogether. Later.
  24 *
  25 */
  26static struct blk_major_name {
  27        struct blk_major_name *next;
  28        int major;
  29        char name[16];
  30} *major_names[BLKDEV_MAJOR_HASH_SIZE];
  31
  32/* index in the above - for now: assume no multimajor ranges */
  33static inline int major_to_index(int major)
  34{
  35        return major % BLKDEV_MAJOR_HASH_SIZE;
  36}
  37
  38#ifdef CONFIG_PROC_FS
  39
  40void blkdev_show(struct seq_file *f, off_t offset)
  41{
  42        struct blk_major_name *dp;
  43
  44        if (offset < BLKDEV_MAJOR_HASH_SIZE) {
  45                mutex_lock(&block_subsys_lock);
  46                for (dp = major_names[offset]; dp; dp = dp->next)
  47                        seq_printf(f, "%3d %s\n", dp->major, dp->name);
  48                mutex_unlock(&block_subsys_lock);
  49        }
  50}
  51
  52#endif /* CONFIG_PROC_FS */
  53
  54int register_blkdev(unsigned int major, const char *name)
  55{
  56        struct blk_major_name **n, *p;
  57        int index, ret = 0;
  58
  59        mutex_lock(&block_subsys_lock);
  60
  61        /* temporary */
  62        if (major == 0) {
  63                for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
  64                        if (major_names[index] == NULL)
  65                                break;
  66                }
  67
  68                if (index == 0) {
  69                        printk("register_blkdev: failed to get major for %s\n",
  70                               name);
  71                        ret = -EBUSY;
  72                        goto out;
  73                }
  74                major = index;
  75                ret = major;
  76        }
  77
  78        p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
  79        if (p == NULL) {
  80                ret = -ENOMEM;
  81                goto out;
  82        }
  83
  84        p->major = major;
  85        strlcpy(p->name, name, sizeof(p->name));
  86        p->next = NULL;
  87        index = major_to_index(major);
  88
  89        for (n = &major_names[index]; *n; n = &(*n)->next) {
  90                if ((*n)->major == major)
  91                        break;
  92        }
  93        if (!*n)
  94                *n = p;
  95        else
  96                ret = -EBUSY;
  97
  98        if (ret < 0) {
  99                printk("register_blkdev: cannot get major %d for %s\n",
 100                       major, name);
 101                kfree(p);
 102        }
 103out:
 104        mutex_unlock(&block_subsys_lock);
 105        return ret;
 106}
 107
 108EXPORT_SYMBOL(register_blkdev);
 109
 110/* todo: make void - error printk here */
 111int unregister_blkdev(unsigned int major, const char *name)
 112{
 113        struct blk_major_name **n;
 114        struct blk_major_name *p = NULL;
 115        int index = major_to_index(major);
 116        int ret = 0;
 117
 118        mutex_lock(&block_subsys_lock);
 119        for (n = &major_names[index]; *n; n = &(*n)->next)
 120                if ((*n)->major == major)
 121                        break;
 122        if (!*n || strcmp((*n)->name, name))
 123                ret = -EINVAL;
 124        else {
 125                p = *n;
 126                *n = p->next;
 127        }
 128        mutex_unlock(&block_subsys_lock);
 129        kfree(p);
 130
 131        return ret;
 132}
 133
 134EXPORT_SYMBOL(unregister_blkdev);
 135
 136static struct kobj_map *bdev_map;
 137
 138/*
 139 * Register device numbers dev..(dev+range-1)
 140 * range must be nonzero
 141 * The hash chain is sorted on range, so that subranges can override.
 142 */
 143void blk_register_region(dev_t dev, unsigned long range, struct module *module,
 144                         struct kobject *(*probe)(dev_t, int *, void *),
 145                         int (*lock)(dev_t, void *), void *data)
 146{
 147        kobj_map(bdev_map, dev, range, module, probe, lock, data);
 148}
 149
 150EXPORT_SYMBOL(blk_register_region);
 151
 152void blk_unregister_region(dev_t dev, unsigned long range)
 153{
 154        kobj_unmap(bdev_map, dev, range);
 155}
 156
 157EXPORT_SYMBOL(blk_unregister_region);
 158
 159static struct kobject *exact_match(dev_t dev, int *part, void *data)
 160{
 161        struct gendisk *p = data;
 162        return &p->kobj;
 163}
 164
 165static int exact_lock(dev_t dev, void *data)
 166{
 167        struct gendisk *p = data;
 168
 169        if (!get_disk(p))
 170                return -1;
 171        return 0;
 172}
 173
 174/**
 175 * add_disk - add partitioning information to kernel list
 176 * @disk: per-device partitioning information
 177 *
 178 * This function registers the partitioning information in @disk
 179 * with the kernel.
 180 */
 181void add_disk(struct gendisk *disk)
 182{
 183        disk->flags |= GENHD_FL_UP;
 184        blk_register_region(MKDEV(disk->major, disk->first_minor),
 185                            disk->minors, NULL, exact_match, exact_lock, disk);
 186        register_disk(disk);
 187        blk_register_queue(disk);
 188}
 189
 190EXPORT_SYMBOL(add_disk);
 191EXPORT_SYMBOL(del_gendisk);     /* in partitions/check.c */
 192
 193void unlink_gendisk(struct gendisk *disk)
 194{
 195        blk_unregister_queue(disk);
 196        blk_unregister_region(MKDEV(disk->major, disk->first_minor),
 197                              disk->minors);
 198}
 199
 200#define to_disk(obj) container_of(obj,struct gendisk,kobj)
 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 dev, int *part)
 210{
 211        struct kobject *kobj = kobj_lookup(bdev_map, dev, part);
 212        return  kobj ? to_disk(kobj) : NULL;
 213}
 214
 215#ifdef CONFIG_PROC_FS
 216/* iterator */
 217static void *part_start(struct seq_file *part, loff_t *pos)
 218{
 219        struct list_head *p;
 220        loff_t l = *pos;
 221
 222        mutex_lock(&block_subsys_lock);
 223        list_for_each(p, &block_subsys.kset.list)
 224                if (!l--)
 225                        return list_entry(p, struct gendisk, kobj.entry);
 226        return NULL;
 227}
 228
 229static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 230{
 231        struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
 232        ++*pos;
 233        return p==&block_subsys.kset.list ? NULL : 
 234                list_entry(p, struct gendisk, kobj.entry);
 235}
 236
 237static void part_stop(struct seq_file *part, void *v)
 238{
 239        mutex_unlock(&block_subsys_lock);
 240}
 241
 242static int show_partition(struct seq_file *part, void *v)
 243{
 244        struct gendisk *sgp = v;
 245        int n;
 246        char buf[BDEVNAME_SIZE];
 247
 248        if (&sgp->kobj.entry == block_subsys.kset.list.next)
 249                seq_puts(part, "major minor  #blocks  name\n\n");
 250
 251        /* Don't show non-partitionable removeable devices or empty devices */
 252        if (!get_capacity(sgp) ||
 253                        (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
 254                return 0;
 255        if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
 256                return 0;
 257
 258        /* show the full disk and all non-0 size partitions of it */
 259        seq_printf(part, "%4d  %4d %10llu %s\n",
 260                sgp->major, sgp->first_minor,
 261                (unsigned long long)get_capacity(sgp) >> 1,
 262                disk_name(sgp, 0, buf));
 263        for (n = 0; n < sgp->minors - 1; n++) {
 264                if (!sgp->part[n])
 265                        continue;
 266                if (sgp->part[n]->nr_sects == 0)
 267                        continue;
 268                seq_printf(part, "%4d  %4d %10llu %s\n",
 269                        sgp->major, n + 1 + sgp->first_minor,
 270                        (unsigned long long)sgp->part[n]->nr_sects >> 1 ,
 271                        disk_name(sgp, n + 1, buf));
 272        }
 273
 274        return 0;
 275}
 276
 277struct seq_operations partitions_op = {
 278        .start =part_start,
 279        .next = part_next,
 280        .stop = part_stop,
 281        .show = show_partition
 282};
 283#endif
 284
 285
 286extern int blk_dev_init(void);
 287
 288static struct kobject *base_probe(dev_t dev, int *part, void *data)
 289{
 290        if (request_module("block-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
 291                /* Make old-style 2.4 aliases work */
 292                request_module("block-major-%d", MAJOR(dev));
 293        return NULL;
 294}
 295
 296static int __init genhd_device_init(void)
 297{
 298        bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
 299        blk_dev_init();
 300        subsystem_register(&block_subsys);
 301        return 0;
 302}
 303
 304subsys_initcall(genhd_device_init);
 305
 306
 307
 308/*
 309 * kobject & sysfs bindings for block devices
 310 */
 311static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
 312                              char *page)
 313{
 314        struct gendisk *disk = to_disk(kobj);
 315        struct disk_attribute *disk_attr =
 316                container_of(attr,struct disk_attribute,attr);
 317        ssize_t ret = -EIO;
 318
 319        if (disk_attr->show)
 320                ret = disk_attr->show(disk,page);
 321        return ret;
 322}
 323
 324static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr,
 325                               const char *page, size_t count)
 326{
 327        struct gendisk *disk = to_disk(kobj);
 328        struct disk_attribute *disk_attr =
 329                container_of(attr,struct disk_attribute,attr);
 330        ssize_t ret = 0;
 331
 332        if (disk_attr->store)
 333                ret = disk_attr->store(disk, page, count);
 334        return ret;
 335}
 336
 337static struct sysfs_ops disk_sysfs_ops = {
 338        .show   = &disk_attr_show,
 339        .store  = &disk_attr_store,
 340};
 341
 342static ssize_t disk_uevent_store(struct gendisk * disk,
 343                                 const char *buf, size_t count)
 344{
 345        kobject_uevent(&disk->kobj, KOBJ_ADD);
 346        return count;
 347}
 348static ssize_t disk_dev_read(struct gendisk * disk, char *page)
 349{
 350        dev_t base = MKDEV(disk->major, disk->first_minor); 
 351        return print_dev_t(page, base);
 352}
 353static ssize_t disk_range_read(struct gendisk * disk, char *page)
 354{
 355        return sprintf(page, "%d\n", disk->minors);
 356}
 357static ssize_t disk_removable_read(struct gendisk * disk, char *page)
 358{
 359        return sprintf(page, "%d\n",
 360                       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
 361
 362}
 363static ssize_t disk_size_read(struct gendisk * disk, char *page)
 364{
 365        return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk));
 366}
 367
 368static ssize_t disk_stats_read(struct gendisk * disk, char *page)
 369{
 370        preempt_disable();
 371        disk_round_stats(disk);
 372        preempt_enable();
 373        return sprintf(page,
 374                "%8lu %8lu %8llu %8u "
 375                "%8lu %8lu %8llu %8u "
 376                "%8u %8u %8u"
 377                "\n",
 378                disk_stat_read(disk, ios[READ]),
 379                disk_stat_read(disk, merges[READ]),
 380                (unsigned long long)disk_stat_read(disk, sectors[READ]),
 381                jiffies_to_msecs(disk_stat_read(disk, ticks[READ])),
 382                disk_stat_read(disk, ios[WRITE]),
 383                disk_stat_read(disk, merges[WRITE]),
 384                (unsigned long long)disk_stat_read(disk, sectors[WRITE]),
 385                jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])),
 386                disk->in_flight,
 387                jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
 388                jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
 389}
 390static struct disk_attribute disk_attr_uevent = {
 391        .attr = {.name = "uevent", .mode = S_IWUSR },
 392        .store  = disk_uevent_store
 393};
 394static struct disk_attribute disk_attr_dev = {
 395        .attr = {.name = "dev", .mode = S_IRUGO },
 396        .show   = disk_dev_read
 397};
 398static struct disk_attribute disk_attr_range = {
 399        .attr = {.name = "range", .mode = S_IRUGO },
 400        .show   = disk_range_read
 401};
 402static struct disk_attribute disk_attr_removable = {
 403        .attr = {.name = "removable", .mode = S_IRUGO },
 404        .show   = disk_removable_read
 405};
 406static struct disk_attribute disk_attr_size = {
 407        .attr = {.name = "size", .mode = S_IRUGO },
 408        .show   = disk_size_read
 409};
 410static struct disk_attribute disk_attr_stat = {
 411        .attr = {.name = "stat", .mode = S_IRUGO },
 412        .show   = disk_stats_read
 413};
 414
 415static struct attribute * default_attrs[] = {
 416        &disk_attr_uevent.attr,
 417        &disk_attr_dev.attr,
 418        &disk_attr_range.attr,
 419        &disk_attr_removable.attr,
 420        &disk_attr_size.attr,
 421        &disk_attr_stat.attr,
 422        NULL,
 423};
 424
 425static void disk_release(struct kobject * kobj)
 426{
 427        struct gendisk *disk = to_disk(kobj);
 428        kfree(disk->random);
 429        kfree(disk->part);
 430        free_disk_stats(disk);
 431        kfree(disk);
 432}
 433
 434static struct kobj_type ktype_block = {
 435        .release        = disk_release,
 436        .sysfs_ops      = &disk_sysfs_ops,
 437        .default_attrs  = default_attrs,
 438};
 439
 440extern struct kobj_type ktype_part;
 441
 442static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
 443{
 444        struct kobj_type *ktype = get_ktype(kobj);
 445
 446        return ((ktype == &ktype_block) || (ktype == &ktype_part));
 447}
 448
 449static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
 450                         int num_envp, char *buffer, int buffer_size)
 451{
 452        struct kobj_type *ktype = get_ktype(kobj);
 453        struct device *physdev;
 454        struct gendisk *disk;
 455        struct hd_struct *part;
 456        int length = 0;
 457        int i = 0;
 458
 459        if (ktype == &ktype_block) {
 460                disk = container_of(kobj, struct gendisk, kobj);
 461                add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
 462                               &length, "MINOR=%u", disk->first_minor);
 463        } else if (ktype == &ktype_part) {
 464                disk = container_of(kobj->parent, struct gendisk, kobj);
 465                part = container_of(kobj, struct hd_struct, kobj);
 466                add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
 467                               &length, "MINOR=%u",
 468                               disk->first_minor + part->partno);
 469        } else
 470                return 0;
 471
 472        add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
 473                       "MAJOR=%u", disk->major);
 474
 475        /* add physical device, backing this device  */
 476        physdev = disk->driverfs_dev;
 477        if (physdev) {
 478                char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
 479
 480                add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
 481                               &length, "PHYSDEVPATH=%s", path);
 482                kfree(path);
 483
 484                if (physdev->bus)
 485                        add_uevent_var(envp, num_envp, &i,
 486                                       buffer, buffer_size, &length,
 487                                       "PHYSDEVBUS=%s",
 488                                       physdev->bus->name);
 489
 490                if (physdev->driver)
 491                        add_uevent_var(envp, num_envp, &i,
 492                                       buffer, buffer_size, &length,
 493                                       "PHYSDEVDRIVER=%s",
 494                                       physdev->driver->name);
 495        }
 496
 497        /* terminate, set to next free slot, shrink available space */
 498        envp[i] = NULL;
 499        envp = &envp[i];
 500        num_envp -= i;
 501        buffer = &buffer[length];
 502        buffer_size -= length;
 503
 504        return 0;
 505}
 506
 507static struct kset_uevent_ops block_uevent_ops = {
 508        .filter         = block_uevent_filter,
 509        .uevent         = block_uevent,
 510};
 511
 512decl_subsys(block, &ktype_block, &block_uevent_ops);
 513
 514/*
 515 * aggregate disk stat collector.  Uses the same stats that the sysfs
 516 * entries do, above, but makes them available through one seq_file.
 517 * Watching a few disks may be efficient through sysfs, but watching
 518 * all of them will be more efficient through this interface.
 519 *
 520 * The output looks suspiciously like /proc/partitions with a bunch of
 521 * extra fields.
 522 */
 523
 524/* iterator */
 525static void *diskstats_start(struct seq_file *part, loff_t *pos)
 526{
 527        loff_t k = *pos;
 528        struct list_head *p;
 529
 530        mutex_lock(&block_subsys_lock);
 531        list_for_each(p, &block_subsys.kset.list)
 532                if (!k--)
 533                        return list_entry(p, struct gendisk, kobj.entry);
 534        return NULL;
 535}
 536
 537static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 538{
 539        struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
 540        ++*pos;
 541        return p==&block_subsys.kset.list ? NULL :
 542                list_entry(p, struct gendisk, kobj.entry);
 543}
 544
 545static void diskstats_stop(struct seq_file *part, void *v)
 546{
 547        mutex_unlock(&block_subsys_lock);
 548}
 549
 550static int diskstats_show(struct seq_file *s, void *v)
 551{
 552        struct gendisk *gp = v;
 553        char buf[BDEVNAME_SIZE];
 554        int n = 0;
 555
 556        /*
 557        if (&sgp->kobj.entry == block_subsys.kset.list.next)
 558                seq_puts(s,     "major minor name"
 559                                "     rio rmerge rsect ruse wio wmerge "
 560                                "wsect wuse running use aveq"
 561                                "\n\n");
 562        */
 563 
 564        preempt_disable();
 565        disk_round_stats(gp);
 566        preempt_enable();
 567        seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
 568                gp->major, n + gp->first_minor, disk_name(gp, n, buf),
 569                disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
 570                (unsigned long long)disk_stat_read(gp, sectors[0]),
 571                jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
 572                disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
 573                (unsigned long long)disk_stat_read(gp, sectors[1]),
 574                jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
 575                gp->in_flight,
 576                jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
 577                jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
 578
 579        /* now show all non-0 size partitions of it */
 580        for (n = 0; n < gp->minors - 1; n++) {
 581                struct hd_struct *hd = gp->part[n];
 582
 583                if (hd && hd->nr_sects)
 584                        seq_printf(s, "%4d %4d %s %u %u %u %u\n",
 585                                gp->major, n + gp->first_minor + 1,
 586                                disk_name(gp, n + 1, buf),
 587                                hd->ios[0], hd->sectors[0],
 588                                hd->ios[1], hd->sectors[1]);
 589        }
 590 
 591        return 0;
 592}
 593
 594struct seq_operations diskstats_op = {
 595        .start  = diskstats_start,
 596        .next   = diskstats_next,
 597        .stop   = diskstats_stop,
 598        .show   = diskstats_show
 599};
 600
 601struct gendisk *alloc_disk(int minors)
 602{
 603        return alloc_disk_node(minors, -1);
 604}
 605
 606struct gendisk *alloc_disk_node(int minors, int node_id)
 607{
 608        struct gendisk *disk;
 609
 610        disk = kmalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
 611        if (disk) {
 612                memset(disk, 0, sizeof(struct gendisk));
 613                if (!init_disk_stats(disk)) {
 614                        kfree(disk);
 615                        return NULL;
 616                }
 617                if (minors > 1) {
 618                        int size = (minors - 1) * sizeof(struct hd_struct *);
 619                        disk->part = kmalloc_node(size, GFP_KERNEL, node_id);
 620                        if (!disk->part) {
 621                                kfree(disk);
 622                                return NULL;
 623                        }
 624                        memset(disk->part, 0, size);
 625                }
 626                disk->minors = minors;
 627                kobj_set_kset_s(disk,block_subsys);
 628                kobject_init(&disk->kobj);
 629                rand_initialize_disk(disk);
 630        }
 631        return disk;
 632}
 633
 634EXPORT_SYMBOL(alloc_disk);
 635EXPORT_SYMBOL(alloc_disk_node);
 636
 637struct kobject *get_disk(struct gendisk *disk)
 638{
 639        struct module *owner;
 640        struct kobject *kobj;
 641
 642        if (!disk->fops)
 643                return NULL;
 644        owner = disk->fops->owner;
 645        if (owner && !try_module_get(owner))
 646                return NULL;
 647        kobj = kobject_get(&disk->kobj);
 648        if (kobj == NULL) {
 649                module_put(owner);
 650                return NULL;
 651        }
 652        return kobj;
 653
 654}
 655
 656EXPORT_SYMBOL(get_disk);
 657
 658void put_disk(struct gendisk *disk)
 659{
 660        if (disk)
 661                kobject_put(&disk->kobj);
 662}
 663
 664EXPORT_SYMBOL(put_disk);
 665
 666void set_device_ro(struct block_device *bdev, int flag)
 667{
 668        if (bdev->bd_contains != bdev)
 669                bdev->bd_part->policy = flag;
 670        else
 671                bdev->bd_disk->policy = flag;
 672}
 673
 674EXPORT_SYMBOL(set_device_ro);
 675
 676void set_disk_ro(struct gendisk *disk, int flag)
 677{
 678        int i;
 679        disk->policy = flag;
 680        for (i = 0; i < disk->minors - 1; i++)
 681                if (disk->part[i]) disk->part[i]->policy = flag;
 682}
 683
 684EXPORT_SYMBOL(set_disk_ro);
 685
 686int bdev_read_only(struct block_device *bdev)
 687{
 688        if (!bdev)
 689                return 0;
 690        else if (bdev->bd_contains != bdev)
 691                return bdev->bd_part->policy;
 692        else
 693                return bdev->bd_disk->policy;
 694}
 695
 696EXPORT_SYMBOL(bdev_read_only);
 697
 698int invalidate_partition(struct gendisk *disk, int index)
 699{
 700        int res = 0;
 701        struct block_device *bdev = bdget_disk(disk, index);
 702        if (bdev) {
 703                fsync_bdev(bdev);
 704                res = __invalidate_device(bdev);
 705                bdput(bdev);
 706        }
 707        return res;
 708}
 709
 710EXPORT_SYMBOL(invalidate_partition);
 711