00001
00002
00003
00004
00005 #include <linux/module.h>
00006 #include <linux/fs.h>
00007 #include <linux/genhd.h>
00008 #include <linux/kdev_t.h>
00009 #include <linux/kernel.h>
00010 #include <linux/blkdev.h>
00011 #include <linux/init.h>
00012 #include <linux/spinlock.h>
00013 #include <linux/proc_fs.h>
00014 #include <linux/seq_file.h>
00015 #include <linux/slab.h>
00016 #include <linux/kmod.h>
00017 #include <linux/kobj_map.h>
00018 #include <linux/buffer_head.h>
00019 #include <linux/mutex.h>
00020 #include <linux/idr.h>
00021
00022 #include "blk.h"
00023 #ifdef DDE_LINUX
00024 #include "local.h"
00025 #endif
00026
00027 static DEFINE_MUTEX(block_class_lock);
00028 #ifndef CONFIG_SYSFS_DEPRECATED
00029 struct kobject *block_depr;
00030 #endif
00031
00032
00033 #define MAX_EXT_DEVT (1 << MINORBITS)
00034
00035
00036
00037
00038 static DEFINE_MUTEX(ext_devt_mutex);
00039 static DEFINE_IDR(ext_devt_idr);
00040
00041 static struct device_type disk_type;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
00058 {
00059 struct hd_struct *part = NULL;
00060 struct disk_part_tbl *ptbl;
00061
00062 if (unlikely(partno < 0))
00063 return NULL;
00064
00065 rcu_read_lock();
00066
00067 ptbl = rcu_dereference(disk->part_tbl);
00068 if (likely(partno < ptbl->len)) {
00069 part = rcu_dereference(ptbl->part[partno]);
00070 if (part)
00071 get_device(part_to_dev(part));
00072 }
00073
00074 rcu_read_unlock();
00075
00076 return part;
00077 }
00078 EXPORT_SYMBOL_GPL(disk_get_part);
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk,
00092 unsigned int flags)
00093 {
00094 struct disk_part_tbl *ptbl;
00095
00096 rcu_read_lock();
00097 ptbl = rcu_dereference(disk->part_tbl);
00098
00099 piter->disk = disk;
00100 piter->part = NULL;
00101
00102 if (flags & DISK_PITER_REVERSE)
00103 piter->idx = ptbl->len - 1;
00104 else if (flags & DISK_PITER_INCL_PART0)
00105 piter->idx = 0;
00106 else
00107 piter->idx = 1;
00108
00109 piter->flags = flags;
00110
00111 rcu_read_unlock();
00112 }
00113 EXPORT_SYMBOL_GPL(disk_part_iter_init);
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
00125 {
00126 struct disk_part_tbl *ptbl;
00127 int inc, end;
00128
00129
00130 disk_put_part(piter->part);
00131 piter->part = NULL;
00132
00133
00134 rcu_read_lock();
00135 ptbl = rcu_dereference(piter->disk->part_tbl);
00136
00137
00138 if (piter->flags & DISK_PITER_REVERSE) {
00139 inc = -1;
00140 if (piter->flags & DISK_PITER_INCL_PART0)
00141 end = -1;
00142 else
00143 end = 0;
00144 } else {
00145 inc = 1;
00146 end = ptbl->len;
00147 }
00148
00149
00150 for (; piter->idx != end; piter->idx += inc) {
00151 struct hd_struct *part;
00152
00153 part = rcu_dereference(ptbl->part[piter->idx]);
00154 if (!part)
00155 continue;
00156 if (!(piter->flags & DISK_PITER_INCL_EMPTY) && !part->nr_sects)
00157 continue;
00158
00159 get_device(part_to_dev(part));
00160 piter->part = part;
00161 piter->idx += inc;
00162 break;
00163 }
00164
00165 rcu_read_unlock();
00166
00167 return piter->part;
00168 }
00169 EXPORT_SYMBOL_GPL(disk_part_iter_next);
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 void disk_part_iter_exit(struct disk_part_iter *piter)
00181 {
00182 disk_put_part(piter->part);
00183 piter->part = NULL;
00184 }
00185 EXPORT_SYMBOL_GPL(disk_part_iter_exit);
00186
00187 static inline int sector_in_part(struct hd_struct *part, sector_t sector)
00188 {
00189 return part->start_sect <= sector &&
00190 sector < part->start_sect + part->nr_sects;
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
00209 {
00210 struct disk_part_tbl *ptbl;
00211 struct hd_struct *part;
00212 int i;
00213
00214 ptbl = rcu_dereference(disk->part_tbl);
00215
00216 part = rcu_dereference(ptbl->last_lookup);
00217 if (part && sector_in_part(part, sector))
00218 return part;
00219
00220 for (i = 1; i < ptbl->len; i++) {
00221 part = rcu_dereference(ptbl->part[i]);
00222
00223 if (part && sector_in_part(part, sector)) {
00224 rcu_assign_pointer(ptbl->last_lookup, part);
00225 return part;
00226 }
00227 }
00228 return &disk->part0;
00229 }
00230 EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
00231
00232
00233
00234
00235
00236 static struct blk_major_name {
00237 struct blk_major_name *next;
00238 int major;
00239 char name[16];
00240 } *major_names[BLKDEV_MAJOR_HASH_SIZE];
00241
00242
00243 static inline int major_to_index(int major)
00244 {
00245 return major % BLKDEV_MAJOR_HASH_SIZE;
00246 }
00247
00248 #ifdef CONFIG_PROC_FS
00249 void blkdev_show(struct seq_file *seqf, off_t offset)
00250 {
00251 struct blk_major_name *dp;
00252
00253 if (offset < BLKDEV_MAJOR_HASH_SIZE) {
00254 mutex_lock(&block_class_lock);
00255 for (dp = major_names[offset]; dp; dp = dp->next)
00256 seq_printf(seqf, "%3d %s\n", dp->major, dp->name);
00257 mutex_unlock(&block_class_lock);
00258 }
00259 }
00260 #endif
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 int register_blkdev(unsigned int major, const char *name)
00279 {
00280 struct blk_major_name **n, *p;
00281 int index, ret = 0;
00282
00283 mutex_lock(&block_class_lock);
00284
00285
00286 if (major == 0) {
00287 for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
00288 if (major_names[index] == NULL)
00289 break;
00290 }
00291
00292 if (index == 0) {
00293 printk("register_blkdev: failed to get major for %s\n",
00294 name);
00295 ret = -EBUSY;
00296 goto out;
00297 }
00298 major = index;
00299 ret = major;
00300 }
00301
00302 p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
00303 if (p == NULL) {
00304 ret = -ENOMEM;
00305 goto out;
00306 }
00307
00308 p->major = major;
00309 strlcpy(p->name, name, sizeof(p->name));
00310 p->next = NULL;
00311 index = major_to_index(major);
00312
00313 for (n = &major_names[index]; *n; n = &(*n)->next) {
00314 if ((*n)->major == major)
00315 break;
00316 }
00317 if (!*n)
00318 *n = p;
00319 else
00320 ret = -EBUSY;
00321
00322 if (ret < 0) {
00323 printk("register_blkdev: cannot get major %d for %s\n",
00324 major, name);
00325 kfree(p);
00326 }
00327 out:
00328 mutex_unlock(&block_class_lock);
00329 return ret;
00330 }
00331
00332 EXPORT_SYMBOL(register_blkdev);
00333
00334 void unregister_blkdev(unsigned int major, const char *name)
00335 {
00336 struct blk_major_name **n;
00337 struct blk_major_name *p = NULL;
00338 int index = major_to_index(major);
00339
00340 mutex_lock(&block_class_lock);
00341 for (n = &major_names[index]; *n; n = &(*n)->next)
00342 if ((*n)->major == major)
00343 break;
00344 if (!*n || strcmp((*n)->name, name)) {
00345 WARN_ON(1);
00346 } else {
00347 p = *n;
00348 *n = p->next;
00349 }
00350 mutex_unlock(&block_class_lock);
00351 kfree(p);
00352 }
00353
00354 EXPORT_SYMBOL(unregister_blkdev);
00355
00356 static struct kobj_map *bdev_map;
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 static int blk_mangle_minor(int minor)
00372 {
00373 #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
00374 int i;
00375
00376 for (i = 0; i < MINORBITS / 2; i++) {
00377 int low = minor & (1 << i);
00378 int high = minor & (1 << (MINORBITS - 1 - i));
00379 int distance = MINORBITS - 1 - 2 * i;
00380
00381 minor ^= low | high;
00382 low <<= distance;
00383 high >>= distance;
00384 minor |= low | high;
00385 }
00386 #endif
00387 return minor;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
00405 {
00406 struct gendisk *disk = part_to_disk(part);
00407 int idx, rc;
00408
00409
00410 if (part->partno < disk->minors) {
00411 *devt = MKDEV(disk->major, disk->first_minor + part->partno);
00412 return 0;
00413 }
00414
00415
00416 do {
00417 if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
00418 return -ENOMEM;
00419 rc = idr_get_new(&ext_devt_idr, part, &idx);
00420 } while (rc == -EAGAIN);
00421
00422 if (rc)
00423 return rc;
00424
00425 if (idx > MAX_EXT_DEVT) {
00426 idr_remove(&ext_devt_idr, idx);
00427 return -EBUSY;
00428 }
00429
00430 *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
00431 return 0;
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 void blk_free_devt(dev_t devt)
00444 {
00445 might_sleep();
00446
00447 if (devt == MKDEV(0, 0))
00448 return;
00449
00450 if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
00451 mutex_lock(&ext_devt_mutex);
00452 idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
00453 mutex_unlock(&ext_devt_mutex);
00454 }
00455 }
00456
00457 static char *bdevt_str(dev_t devt, char *buf)
00458 {
00459 if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
00460 char tbuf[BDEVT_SIZE];
00461 snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt));
00462 snprintf(buf, BDEVT_SIZE, "%-9s", tbuf);
00463 } else
00464 snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt));
00465
00466 return buf;
00467 }
00468
00469
00470
00471
00472
00473
00474 void blk_register_region(dev_t devt, unsigned long range, struct module *module,
00475 struct kobject *(*probe)(dev_t, int *, void *),
00476 int (*lock)(dev_t, void *), void *data)
00477 {
00478 kobj_map(bdev_map, devt, range, module, probe, lock, data);
00479 }
00480
00481 EXPORT_SYMBOL(blk_register_region);
00482
00483 void blk_unregister_region(dev_t devt, unsigned long range)
00484 {
00485 kobj_unmap(bdev_map, devt, range);
00486 }
00487
00488 EXPORT_SYMBOL(blk_unregister_region);
00489
00490 static struct kobject *exact_match(dev_t devt, int *partno, void *data)
00491 {
00492 struct gendisk *p = data;
00493
00494 return &disk_to_dev(p)->kobj;
00495 }
00496
00497 static int exact_lock(dev_t devt, void *data)
00498 {
00499 struct gendisk *p = data;
00500
00501 if (!get_disk(p))
00502 return -1;
00503 return 0;
00504 }
00505
00506 #ifndef DDE_LINUX
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 void add_disk(struct gendisk *disk)
00517 {
00518 struct backing_dev_info *bdi;
00519 dev_t devt;
00520 int retval;
00521
00522
00523
00524
00525
00526 WARN_ON(disk->minors && !(disk->major || disk->first_minor));
00527 WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
00528
00529 disk->flags |= GENHD_FL_UP;
00530
00531 retval = blk_alloc_devt(&disk->part0, &devt);
00532 if (retval) {
00533 WARN_ON(1);
00534 return;
00535 }
00536 disk_to_dev(disk)->devt = devt;
00537
00538
00539
00540
00541 disk->major = MAJOR(devt);
00542 disk->first_minor = MINOR(devt);
00543
00544 blk_register_region(disk_devt(disk), disk->minors, NULL,
00545 exact_match, exact_lock, disk);
00546 register_disk(disk);
00547 blk_register_queue(disk);
00548
00549 bdi = &disk->queue->backing_dev_info;
00550 bdi_register_dev(bdi, disk_devt(disk));
00551 retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
00552 "bdi");
00553 WARN_ON(retval);
00554 }
00555
00556 EXPORT_SYMBOL(add_disk);
00557 EXPORT_SYMBOL(del_gendisk);
00558 #endif
00559
00560 void unlink_gendisk(struct gendisk *disk)
00561 {
00562 sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
00563 bdi_unregister(&disk->queue->backing_dev_info);
00564 blk_unregister_queue(disk);
00565 blk_unregister_region(disk_devt(disk), disk->minors);
00566 }
00567
00568 #ifndef DDE_LINUX
00569
00570
00571
00572
00573
00574
00575
00576
00577 struct gendisk *get_gendisk(dev_t devt, int *partno)
00578 {
00579 struct gendisk *disk = NULL;
00580
00581 if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
00582 struct kobject *kobj;
00583
00584 kobj = kobj_lookup(bdev_map, devt, partno);
00585 if (kobj)
00586 disk = dev_to_disk(kobj_to_dev(kobj));
00587 } else {
00588 struct hd_struct *part;
00589
00590 mutex_lock(&ext_devt_mutex);
00591 part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
00592 if (part && get_disk(part_to_disk(part))) {
00593 *partno = part->partno;
00594 disk = part_to_disk(part);
00595 }
00596 mutex_unlock(&ext_devt_mutex);
00597 }
00598
00599 return disk;
00600 }
00601 #endif
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616 struct block_device *bdget_disk(struct gendisk *disk, int partno)
00617 {
00618 struct hd_struct *part;
00619 struct block_device *bdev = NULL;
00620
00621 part = disk_get_part(disk, partno);
00622 if (part)
00623 bdev = bdget(part_devt(part));
00624 disk_put_part(part);
00625
00626 return bdev;
00627 }
00628 EXPORT_SYMBOL(bdget_disk);
00629
00630
00631
00632
00633
00634
00635 void __init printk_all_partitions(void)
00636 {
00637 struct class_dev_iter iter;
00638 struct device *dev;
00639
00640 class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
00641 while ((dev = class_dev_iter_next(&iter))) {
00642 struct gendisk *disk = dev_to_disk(dev);
00643 struct disk_part_iter piter;
00644 struct hd_struct *part;
00645 char name_buf[BDEVNAME_SIZE];
00646 char devt_buf[BDEVT_SIZE];
00647
00648
00649
00650
00651
00652 if (get_capacity(disk) == 0 ||
00653 (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
00654 continue;
00655
00656
00657
00658
00659
00660
00661 disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
00662 while ((part = disk_part_iter_next(&piter))) {
00663 bool is_part0 = part == &disk->part0;
00664
00665 printk("%s%s %10llu %s", is_part0 ? "" : " ",
00666 bdevt_str(part_devt(part), devt_buf),
00667 (unsigned long long)part->nr_sects >> 1,
00668 disk_name(disk, part->partno, name_buf));
00669 if (is_part0) {
00670 if (disk->driverfs_dev != NULL &&
00671 disk->driverfs_dev->driver != NULL)
00672 printk(" driver: %s\n",
00673 disk->driverfs_dev->driver->name);
00674 else
00675 printk(" (driver?)\n");
00676 } else
00677 printk("\n");
00678 }
00679 disk_part_iter_exit(&piter);
00680 }
00681 class_dev_iter_exit(&iter);
00682 }
00683
00684 #ifdef CONFIG_PROC_FS
00685
00686 static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
00687 {
00688 loff_t skip = *pos;
00689 struct class_dev_iter *iter;
00690 struct device *dev;
00691
00692 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
00693 if (!iter)
00694 return ERR_PTR(-ENOMEM);
00695
00696 seqf->private = iter;
00697 class_dev_iter_init(iter, &block_class, NULL, &disk_type);
00698 do {
00699 dev = class_dev_iter_next(iter);
00700 if (!dev)
00701 return NULL;
00702 } while (skip--);
00703
00704 return dev_to_disk(dev);
00705 }
00706
00707 static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
00708 {
00709 struct device *dev;
00710
00711 (*pos)++;
00712 dev = class_dev_iter_next(seqf->private);
00713 if (dev)
00714 return dev_to_disk(dev);
00715
00716 return NULL;
00717 }
00718
00719 static void disk_seqf_stop(struct seq_file *seqf, void *v)
00720 {
00721 struct class_dev_iter *iter = seqf->private;
00722
00723
00724 if (iter) {
00725 class_dev_iter_exit(iter);
00726 kfree(iter);
00727 }
00728 }
00729
00730 static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
00731 {
00732 static void *p;
00733
00734 p = disk_seqf_start(seqf, pos);
00735 if (!IS_ERR(p) && p && !*pos)
00736 seq_puts(seqf, "major minor #blocks name\n\n");
00737 return p;
00738 }
00739
00740 static int show_partition(struct seq_file *seqf, void *v)
00741 {
00742 struct gendisk *sgp = v;
00743 struct disk_part_iter piter;
00744 struct hd_struct *part;
00745 char buf[BDEVNAME_SIZE];
00746
00747
00748 if (!get_capacity(sgp) || (!disk_partitionable(sgp) &&
00749 (sgp->flags & GENHD_FL_REMOVABLE)))
00750 return 0;
00751 if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
00752 return 0;
00753
00754
00755 disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
00756 while ((part = disk_part_iter_next(&piter)))
00757 seq_printf(seqf, "%4d %7d %10llu %s\n",
00758 MAJOR(part_devt(part)), MINOR(part_devt(part)),
00759 (unsigned long long)part->nr_sects >> 1,
00760 disk_name(sgp, part->partno, buf));
00761 disk_part_iter_exit(&piter);
00762
00763 return 0;
00764 }
00765
00766 static const struct seq_operations partitions_op = {
00767 .start = show_partition_start,
00768 .next = disk_seqf_next,
00769 .stop = disk_seqf_stop,
00770 .show = show_partition
00771 };
00772
00773 static int partitions_open(struct inode *inode, struct file *file)
00774 {
00775 return seq_open(file, &partitions_op);
00776 }
00777
00778 static const struct file_operations proc_partitions_operations = {
00779 .open = partitions_open,
00780 .read = seq_read,
00781 .llseek = seq_lseek,
00782 .release = seq_release,
00783 };
00784 #endif
00785
00786
00787 static struct kobject *base_probe(dev_t devt, int *partno, void *data)
00788 {
00789 if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
00790
00791 request_module("block-major-%d", MAJOR(devt));
00792 return NULL;
00793 }
00794
00795 static int __init genhd_device_init(void)
00796 {
00797 int error;
00798
00799 block_class.dev_kobj = sysfs_dev_block_kobj;
00800 error = class_register(&block_class);
00801 if (unlikely(error))
00802 return error;
00803 bdev_map = kobj_map_init(base_probe, &block_class_lock);
00804 blk_dev_init();
00805
00806 register_blkdev(BLOCK_EXT_MAJOR, "blkext");
00807
00808 #ifndef CONFIG_SYSFS_DEPRECATED
00809
00810 block_depr = kobject_create_and_add("block", NULL);
00811 #endif
00812 return 0;
00813 }
00814
00815 subsys_initcall(genhd_device_init);
00816
00817 static ssize_t disk_range_show(struct device *dev,
00818 struct device_attribute *attr, char *buf)
00819 {
00820 struct gendisk *disk = dev_to_disk(dev);
00821
00822 return sprintf(buf, "%d\n", disk->minors);
00823 }
00824
00825 static ssize_t disk_ext_range_show(struct device *dev,
00826 struct device_attribute *attr, char *buf)
00827 {
00828 struct gendisk *disk = dev_to_disk(dev);
00829
00830 return sprintf(buf, "%d\n", disk_max_parts(disk));
00831 }
00832
00833 static ssize_t disk_removable_show(struct device *dev,
00834 struct device_attribute *attr, char *buf)
00835 {
00836 struct gendisk *disk = dev_to_disk(dev);
00837
00838 return sprintf(buf, "%d\n",
00839 (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
00840 }
00841
00842 static ssize_t disk_ro_show(struct device *dev,
00843 struct device_attribute *attr, char *buf)
00844 {
00845 struct gendisk *disk = dev_to_disk(dev);
00846
00847 return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0);
00848 }
00849
00850 static ssize_t disk_capability_show(struct device *dev,
00851 struct device_attribute *attr, char *buf)
00852 {
00853 struct gendisk *disk = dev_to_disk(dev);
00854
00855 return sprintf(buf, "%x\n", disk->flags);
00856 }
00857
00858 static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
00859 static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
00860 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
00861 static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
00862 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
00863 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
00864 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
00865 #ifdef CONFIG_FAIL_MAKE_REQUEST
00866 static struct device_attribute dev_attr_fail =
00867 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
00868 #endif
00869 #ifdef CONFIG_FAIL_IO_TIMEOUT
00870 static struct device_attribute dev_attr_fail_timeout =
00871 __ATTR(io-timeout-fail, S_IRUGO|S_IWUSR, part_timeout_show,
00872 part_timeout_store);
00873 #endif
00874
00875 static struct attribute *disk_attrs[] = {
00876 &dev_attr_range.attr,
00877 &dev_attr_ext_range.attr,
00878 &dev_attr_removable.attr,
00879 &dev_attr_ro.attr,
00880 &dev_attr_size.attr,
00881 &dev_attr_capability.attr,
00882 &dev_attr_stat.attr,
00883 #ifdef CONFIG_FAIL_MAKE_REQUEST
00884 &dev_attr_fail.attr,
00885 #endif
00886 #ifdef CONFIG_FAIL_IO_TIMEOUT
00887 &dev_attr_fail_timeout.attr,
00888 #endif
00889 NULL
00890 };
00891
00892 static struct attribute_group disk_attr_group = {
00893 .attrs = disk_attrs,
00894 };
00895
00896 static struct attribute_group *disk_attr_groups[] = {
00897 &disk_attr_group,
00898 NULL
00899 };
00900
00901 static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
00902 {
00903 struct disk_part_tbl *ptbl =
00904 container_of(head, struct disk_part_tbl, rcu_head);
00905
00906 kfree(ptbl);
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920 static void disk_replace_part_tbl(struct gendisk *disk,
00921 struct disk_part_tbl *new_ptbl)
00922 {
00923 struct disk_part_tbl *old_ptbl = disk->part_tbl;
00924
00925 rcu_assign_pointer(disk->part_tbl, new_ptbl);
00926
00927 if (old_ptbl) {
00928 rcu_assign_pointer(old_ptbl->last_lookup, NULL);
00929 #ifndef DDE_LINUX
00930 call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
00931 #else
00932 disk_free_ptbl_rcu_cb(&old_ptbl->rcu_head);
00933 #endif
00934 }
00935 }
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951 int disk_expand_part_tbl(struct gendisk *disk, int partno)
00952 {
00953 struct disk_part_tbl *old_ptbl = disk->part_tbl;
00954 struct disk_part_tbl *new_ptbl;
00955 int len = old_ptbl ? old_ptbl->len : 0;
00956 int target = partno + 1;
00957 size_t size;
00958 int i;
00959
00960
00961 if (disk_max_parts(disk) && target > disk_max_parts(disk))
00962 return -EINVAL;
00963
00964 if (target <= len)
00965 return 0;
00966
00967 size = sizeof(*new_ptbl) + target * sizeof(new_ptbl->part[0]);
00968 new_ptbl = kzalloc_node(size, GFP_KERNEL, disk->node_id);
00969 if (!new_ptbl)
00970 return -ENOMEM;
00971
00972 INIT_RCU_HEAD(&new_ptbl->rcu_head);
00973 new_ptbl->len = target;
00974
00975 for (i = 0; i < len; i++)
00976 rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
00977
00978 disk_replace_part_tbl(disk, new_ptbl);
00979 return 0;
00980 }
00981
00982 static void disk_release(struct device *dev)
00983 {
00984 struct gendisk *disk = dev_to_disk(dev);
00985
00986 kfree(disk->random);
00987 disk_replace_part_tbl(disk, NULL);
00988 free_part_stats(&disk->part0);
00989 kfree(disk);
00990 }
00991 struct class block_class = {
00992 .name = "block",
00993 };
00994
00995 static struct device_type disk_type = {
00996 .name = "disk",
00997 .groups = disk_attr_groups,
00998 .release = disk_release,
00999 };
01000
01001 #ifdef CONFIG_PROC_FS
01002
01003
01004
01005
01006
01007
01008
01009 static int diskstats_show(struct seq_file *seqf, void *v)
01010 {
01011 struct gendisk *gp = v;
01012 struct disk_part_iter piter;
01013 struct hd_struct *hd;
01014 char buf[BDEVNAME_SIZE];
01015 int cpu;
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025 disk_part_iter_init(&piter, gp, DISK_PITER_INCL_PART0);
01026 while ((hd = disk_part_iter_next(&piter))) {
01027 cpu = part_stat_lock();
01028 part_round_stats(cpu, hd);
01029 part_stat_unlock();
01030 seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
01031 "%u %lu %lu %llu %u %u %u %u\n",
01032 MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
01033 disk_name(gp, hd->partno, buf),
01034 part_stat_read(hd, ios[0]),
01035 part_stat_read(hd, merges[0]),
01036 (unsigned long long)part_stat_read(hd, sectors[0]),
01037 jiffies_to_msecs(part_stat_read(hd, ticks[0])),
01038 part_stat_read(hd, ios[1]),
01039 part_stat_read(hd, merges[1]),
01040 (unsigned long long)part_stat_read(hd, sectors[1]),
01041 jiffies_to_msecs(part_stat_read(hd, ticks[1])),
01042 hd->in_flight,
01043 jiffies_to_msecs(part_stat_read(hd, io_ticks)),
01044 jiffies_to_msecs(part_stat_read(hd, time_in_queue))
01045 );
01046 }
01047 disk_part_iter_exit(&piter);
01048
01049 return 0;
01050 }
01051
01052 static const struct seq_operations diskstats_op = {
01053 .start = disk_seqf_start,
01054 .next = disk_seqf_next,
01055 .stop = disk_seqf_stop,
01056 .show = diskstats_show
01057 };
01058
01059 static int diskstats_open(struct inode *inode, struct file *file)
01060 {
01061 return seq_open(file, &diskstats_op);
01062 }
01063
01064 static const struct file_operations proc_diskstats_operations = {
01065 .open = diskstats_open,
01066 .read = seq_read,
01067 .llseek = seq_lseek,
01068 .release = seq_release,
01069 };
01070
01071 static int __init proc_genhd_init(void)
01072 {
01073 proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
01074 proc_create("partitions", 0, NULL, &proc_partitions_operations);
01075 return 0;
01076 }
01077 module_init(proc_genhd_init);
01078 #endif
01079
01080 static void media_change_notify_thread(struct work_struct *work)
01081 {
01082 struct gendisk *gd = container_of(work, struct gendisk, async_notify);
01083 char event[] = "MEDIA_CHANGE=1";
01084 char *envp[] = { event, NULL };
01085
01086
01087
01088
01089
01090 kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
01091 put_device(gd->driverfs_dev);
01092 }
01093
01094 #if 0
01095 void genhd_media_change_notify(struct gendisk *disk)
01096 {
01097 get_device(disk->driverfs_dev);
01098 schedule_work(&disk->async_notify);
01099 }
01100 EXPORT_SYMBOL_GPL(genhd_media_change_notify);
01101 #endif
01102
01103 dev_t blk_lookup_devt(const char *name, int partno)
01104 {
01105 dev_t devt = MKDEV(0, 0);
01106 struct class_dev_iter iter;
01107 struct device *dev;
01108
01109 class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
01110 while ((dev = class_dev_iter_next(&iter))) {
01111 struct gendisk *disk = dev_to_disk(dev);
01112 struct hd_struct *part;
01113
01114 if (strcmp(dev_name(dev), name))
01115 continue;
01116
01117 if (partno < disk->minors) {
01118
01119
01120
01121 devt = MKDEV(MAJOR(dev->devt),
01122 MINOR(dev->devt) + partno);
01123 break;
01124 }
01125 part = disk_get_part(disk, partno);
01126 if (part) {
01127 devt = part_devt(part);
01128 disk_put_part(part);
01129 break;
01130 }
01131 disk_put_part(part);
01132 }
01133 class_dev_iter_exit(&iter);
01134 return devt;
01135 }
01136 EXPORT_SYMBOL(blk_lookup_devt);
01137
01138 struct gendisk *alloc_disk(int minors)
01139 {
01140 return alloc_disk_node(minors, -1);
01141 }
01142 EXPORT_SYMBOL(alloc_disk);
01143
01144 struct gendisk *alloc_disk_node(int minors, int node_id)
01145 {
01146 struct gendisk *disk;
01147
01148 disk = kmalloc_node(sizeof(struct gendisk),
01149 GFP_KERNEL | __GFP_ZERO, node_id);
01150 if (disk) {
01151 if (!init_part_stats(&disk->part0)) {
01152 kfree(disk);
01153 return NULL;
01154 }
01155 disk->node_id = node_id;
01156 if (disk_expand_part_tbl(disk, 0)) {
01157 free_part_stats(&disk->part0);
01158 kfree(disk);
01159 return NULL;
01160 }
01161 disk->part_tbl->part[0] = &disk->part0;
01162
01163 disk->minors = minors;
01164 #ifndef DDE_LINUX
01165 rand_initialize_disk(disk);
01166 #endif
01167 disk_to_dev(disk)->class = &block_class;
01168 disk_to_dev(disk)->type = &disk_type;
01169 device_initialize(disk_to_dev(disk));
01170 INIT_WORK(&disk->async_notify,
01171 media_change_notify_thread);
01172 }
01173 return disk;
01174 }
01175 EXPORT_SYMBOL(alloc_disk_node);
01176
01177 struct kobject *get_disk(struct gendisk *disk)
01178 {
01179 struct module *owner;
01180 struct kobject *kobj;
01181
01182 if (!disk->fops)
01183 return NULL;
01184 owner = disk->fops->owner;
01185 if (owner && !try_module_get(owner))
01186 return NULL;
01187 kobj = kobject_get(&disk_to_dev(disk)->kobj);
01188 if (kobj == NULL) {
01189 module_put(owner);
01190 return NULL;
01191 }
01192 return kobj;
01193
01194 }
01195
01196 EXPORT_SYMBOL(get_disk);
01197
01198 void put_disk(struct gendisk *disk)
01199 {
01200 if (disk)
01201 kobject_put(&disk_to_dev(disk)->kobj);
01202 }
01203
01204 EXPORT_SYMBOL(put_disk);
01205
01206 void set_device_ro(struct block_device *bdev, int flag)
01207 {
01208 bdev->bd_part->policy = flag;
01209 }
01210
01211 EXPORT_SYMBOL(set_device_ro);
01212
01213 void set_disk_ro(struct gendisk *disk, int flag)
01214 {
01215 struct disk_part_iter piter;
01216 struct hd_struct *part;
01217
01218 disk_part_iter_init(&piter, disk,
01219 DISK_PITER_INCL_EMPTY | DISK_PITER_INCL_PART0);
01220 while ((part = disk_part_iter_next(&piter)))
01221 part->policy = flag;
01222 disk_part_iter_exit(&piter);
01223 }
01224
01225 EXPORT_SYMBOL(set_disk_ro);
01226
01227 int bdev_read_only(struct block_device *bdev)
01228 {
01229 if (!bdev)
01230 return 0;
01231 return bdev->bd_part->policy;
01232 }
01233
01234 EXPORT_SYMBOL(bdev_read_only);
01235
01236 int invalidate_partition(struct gendisk *disk, int partno)
01237 {
01238 int res = 0;
01239 struct block_device *bdev = bdget_disk(disk, partno);
01240 if (bdev) {
01241 fsync_bdev(bdev);
01242 res = __invalidate_device(bdev);
01243 bdput(bdev);
01244 }
01245 return res;
01246 }
01247
01248 EXPORT_SYMBOL(invalidate_partition);