11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * gendisk handling 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/module.h> 61da177e4SLinus Torvalds #include <linux/fs.h> 71da177e4SLinus Torvalds #include <linux/genhd.h> 8b446b60eSAndrew Morton #include <linux/kdev_t.h> 91da177e4SLinus Torvalds #include <linux/kernel.h> 101da177e4SLinus Torvalds #include <linux/blkdev.h> 111da177e4SLinus Torvalds #include <linux/init.h> 121da177e4SLinus Torvalds #include <linux/spinlock.h> 131da177e4SLinus Torvalds #include <linux/seq_file.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 151da177e4SLinus Torvalds #include <linux/kmod.h> 161da177e4SLinus Torvalds #include <linux/kobj_map.h> 172ef41634SChristoph Hellwig #include <linux/buffer_head.h> 1858383af6SJes Sorensen #include <linux/mutex.h> 191da177e4SLinus Torvalds 20ff88972cSAdrian Bunk #include "blk.h" 21ff88972cSAdrian Bunk 22edfaa7c3SKay Sievers static DEFINE_MUTEX(block_class_lock); 23edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 24edfaa7c3SKay Sievers struct kobject *block_depr; 25edfaa7c3SKay Sievers #endif 261da177e4SLinus Torvalds 271826eadfSAdrian Bunk static struct device_type disk_type; 281826eadfSAdrian Bunk 29*e71bf0d0STejun Heo /** 30*e71bf0d0STejun Heo * disk_get_part - get partition 31*e71bf0d0STejun Heo * @disk: disk to look partition from 32*e71bf0d0STejun Heo * @partno: partition number 33*e71bf0d0STejun Heo * 34*e71bf0d0STejun Heo * Look for partition @partno from @disk. If found, increment 35*e71bf0d0STejun Heo * reference count and return it. 36*e71bf0d0STejun Heo * 37*e71bf0d0STejun Heo * CONTEXT: 38*e71bf0d0STejun Heo * Don't care. 39*e71bf0d0STejun Heo * 40*e71bf0d0STejun Heo * RETURNS: 41*e71bf0d0STejun Heo * Pointer to the found partition on success, NULL if not found. 42*e71bf0d0STejun Heo */ 43*e71bf0d0STejun Heo struct hd_struct *disk_get_part(struct gendisk *disk, int partno) 44*e71bf0d0STejun Heo { 45*e71bf0d0STejun Heo struct hd_struct *part; 46*e71bf0d0STejun Heo 47*e71bf0d0STejun Heo if (unlikely(partno < 1 || partno > disk_max_parts(disk))) 48*e71bf0d0STejun Heo return NULL; 49*e71bf0d0STejun Heo rcu_read_lock(); 50*e71bf0d0STejun Heo part = rcu_dereference(disk->__part[partno - 1]); 51*e71bf0d0STejun Heo if (part) 52*e71bf0d0STejun Heo get_device(&part->dev); 53*e71bf0d0STejun Heo rcu_read_unlock(); 54*e71bf0d0STejun Heo 55*e71bf0d0STejun Heo return part; 56*e71bf0d0STejun Heo } 57*e71bf0d0STejun Heo EXPORT_SYMBOL_GPL(disk_get_part); 58*e71bf0d0STejun Heo 59*e71bf0d0STejun Heo /** 60*e71bf0d0STejun Heo * disk_part_iter_init - initialize partition iterator 61*e71bf0d0STejun Heo * @piter: iterator to initialize 62*e71bf0d0STejun Heo * @disk: disk to iterate over 63*e71bf0d0STejun Heo * @flags: DISK_PITER_* flags 64*e71bf0d0STejun Heo * 65*e71bf0d0STejun Heo * Initialize @piter so that it iterates over partitions of @disk. 66*e71bf0d0STejun Heo * 67*e71bf0d0STejun Heo * CONTEXT: 68*e71bf0d0STejun Heo * Don't care. 69*e71bf0d0STejun Heo */ 70*e71bf0d0STejun Heo void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, 71*e71bf0d0STejun Heo unsigned int flags) 72*e71bf0d0STejun Heo { 73*e71bf0d0STejun Heo piter->disk = disk; 74*e71bf0d0STejun Heo piter->part = NULL; 75*e71bf0d0STejun Heo 76*e71bf0d0STejun Heo if (flags & DISK_PITER_REVERSE) 77*e71bf0d0STejun Heo piter->idx = disk_max_parts(piter->disk) - 1; 78*e71bf0d0STejun Heo else 79*e71bf0d0STejun Heo piter->idx = 0; 80*e71bf0d0STejun Heo 81*e71bf0d0STejun Heo piter->flags = flags; 82*e71bf0d0STejun Heo } 83*e71bf0d0STejun Heo EXPORT_SYMBOL_GPL(disk_part_iter_init); 84*e71bf0d0STejun Heo 85*e71bf0d0STejun Heo /** 86*e71bf0d0STejun Heo * disk_part_iter_next - proceed iterator to the next partition and return it 87*e71bf0d0STejun Heo * @piter: iterator of interest 88*e71bf0d0STejun Heo * 89*e71bf0d0STejun Heo * Proceed @piter to the next partition and return it. 90*e71bf0d0STejun Heo * 91*e71bf0d0STejun Heo * CONTEXT: 92*e71bf0d0STejun Heo * Don't care. 93*e71bf0d0STejun Heo */ 94*e71bf0d0STejun Heo struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter) 95*e71bf0d0STejun Heo { 96*e71bf0d0STejun Heo int inc, end; 97*e71bf0d0STejun Heo 98*e71bf0d0STejun Heo /* put the last partition */ 99*e71bf0d0STejun Heo disk_put_part(piter->part); 100*e71bf0d0STejun Heo piter->part = NULL; 101*e71bf0d0STejun Heo 102*e71bf0d0STejun Heo rcu_read_lock(); 103*e71bf0d0STejun Heo 104*e71bf0d0STejun Heo /* determine iteration parameters */ 105*e71bf0d0STejun Heo if (piter->flags & DISK_PITER_REVERSE) { 106*e71bf0d0STejun Heo inc = -1; 107*e71bf0d0STejun Heo end = -1; 108*e71bf0d0STejun Heo } else { 109*e71bf0d0STejun Heo inc = 1; 110*e71bf0d0STejun Heo end = disk_max_parts(piter->disk); 111*e71bf0d0STejun Heo } 112*e71bf0d0STejun Heo 113*e71bf0d0STejun Heo /* iterate to the next partition */ 114*e71bf0d0STejun Heo for (; piter->idx != end; piter->idx += inc) { 115*e71bf0d0STejun Heo struct hd_struct *part; 116*e71bf0d0STejun Heo 117*e71bf0d0STejun Heo part = rcu_dereference(piter->disk->__part[piter->idx]); 118*e71bf0d0STejun Heo if (!part) 119*e71bf0d0STejun Heo continue; 120*e71bf0d0STejun Heo if (!(piter->flags & DISK_PITER_INCL_EMPTY) && !part->nr_sects) 121*e71bf0d0STejun Heo continue; 122*e71bf0d0STejun Heo 123*e71bf0d0STejun Heo get_device(&part->dev); 124*e71bf0d0STejun Heo piter->part = part; 125*e71bf0d0STejun Heo piter->idx += inc; 126*e71bf0d0STejun Heo break; 127*e71bf0d0STejun Heo } 128*e71bf0d0STejun Heo 129*e71bf0d0STejun Heo rcu_read_unlock(); 130*e71bf0d0STejun Heo 131*e71bf0d0STejun Heo return piter->part; 132*e71bf0d0STejun Heo } 133*e71bf0d0STejun Heo EXPORT_SYMBOL_GPL(disk_part_iter_next); 134*e71bf0d0STejun Heo 135*e71bf0d0STejun Heo /** 136*e71bf0d0STejun Heo * disk_part_iter_exit - finish up partition iteration 137*e71bf0d0STejun Heo * @piter: iter of interest 138*e71bf0d0STejun Heo * 139*e71bf0d0STejun Heo * Called when iteration is over. Cleans up @piter. 140*e71bf0d0STejun Heo * 141*e71bf0d0STejun Heo * CONTEXT: 142*e71bf0d0STejun Heo * Don't care. 143*e71bf0d0STejun Heo */ 144*e71bf0d0STejun Heo void disk_part_iter_exit(struct disk_part_iter *piter) 145*e71bf0d0STejun Heo { 146*e71bf0d0STejun Heo disk_put_part(piter->part); 147*e71bf0d0STejun Heo piter->part = NULL; 148*e71bf0d0STejun Heo } 149*e71bf0d0STejun Heo EXPORT_SYMBOL_GPL(disk_part_iter_exit); 150*e71bf0d0STejun Heo 151*e71bf0d0STejun Heo /** 152*e71bf0d0STejun Heo * disk_map_sector_rcu - map sector to partition 153*e71bf0d0STejun Heo * @disk: gendisk of interest 154*e71bf0d0STejun Heo * @sector: sector to map 155*e71bf0d0STejun Heo * 156*e71bf0d0STejun Heo * Find out which partition @sector maps to on @disk. This is 157*e71bf0d0STejun Heo * primarily used for stats accounting. 158*e71bf0d0STejun Heo * 159*e71bf0d0STejun Heo * CONTEXT: 160*e71bf0d0STejun Heo * RCU read locked. The returned partition pointer is valid only 161*e71bf0d0STejun Heo * while preemption is disabled. 162*e71bf0d0STejun Heo * 163*e71bf0d0STejun Heo * RETURNS: 164*e71bf0d0STejun Heo * Found partition on success, NULL if there's no matching partition. 165*e71bf0d0STejun Heo */ 166*e71bf0d0STejun Heo struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) 167*e71bf0d0STejun Heo { 168*e71bf0d0STejun Heo int i; 169*e71bf0d0STejun Heo 170*e71bf0d0STejun Heo for (i = 0; i < disk_max_parts(disk); i++) { 171*e71bf0d0STejun Heo struct hd_struct *part = rcu_dereference(disk->__part[i]); 172*e71bf0d0STejun Heo 173*e71bf0d0STejun Heo if (part && part->start_sect <= sector && 174*e71bf0d0STejun Heo sector < part->start_sect + part->nr_sects) 175*e71bf0d0STejun Heo return part; 176*e71bf0d0STejun Heo } 177*e71bf0d0STejun Heo return NULL; 178*e71bf0d0STejun Heo } 179*e71bf0d0STejun Heo EXPORT_SYMBOL_GPL(disk_map_sector_rcu); 180*e71bf0d0STejun Heo 1811da177e4SLinus Torvalds /* 1821da177e4SLinus Torvalds * Can be deleted altogether. Later. 1831da177e4SLinus Torvalds * 1841da177e4SLinus Torvalds */ 1851da177e4SLinus Torvalds static struct blk_major_name { 1861da177e4SLinus Torvalds struct blk_major_name *next; 1871da177e4SLinus Torvalds int major; 1881da177e4SLinus Torvalds char name[16]; 18968eef3b4SJoe Korty } *major_names[BLKDEV_MAJOR_HASH_SIZE]; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds /* index in the above - for now: assume no multimajor ranges */ 1921da177e4SLinus Torvalds static inline int major_to_index(int major) 1931da177e4SLinus Torvalds { 19468eef3b4SJoe Korty return major % BLKDEV_MAJOR_HASH_SIZE; 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 19768eef3b4SJoe Korty #ifdef CONFIG_PROC_FS 198cf771cb5STejun Heo void blkdev_show(struct seq_file *seqf, off_t offset) 1997170be5fSNeil Horman { 20068eef3b4SJoe Korty struct blk_major_name *dp; 2017170be5fSNeil Horman 20268eef3b4SJoe Korty if (offset < BLKDEV_MAJOR_HASH_SIZE) { 203edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 20468eef3b4SJoe Korty for (dp = major_names[offset]; dp; dp = dp->next) 205cf771cb5STejun Heo seq_printf(seqf, "%3d %s\n", dp->major, dp->name); 206edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 20768eef3b4SJoe Korty } 2087170be5fSNeil Horman } 20968eef3b4SJoe Korty #endif /* CONFIG_PROC_FS */ 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds int register_blkdev(unsigned int major, const char *name) 2121da177e4SLinus Torvalds { 2131da177e4SLinus Torvalds struct blk_major_name **n, *p; 2141da177e4SLinus Torvalds int index, ret = 0; 2151da177e4SLinus Torvalds 216edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* temporary */ 2191da177e4SLinus Torvalds if (major == 0) { 2201da177e4SLinus Torvalds for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) { 2211da177e4SLinus Torvalds if (major_names[index] == NULL) 2221da177e4SLinus Torvalds break; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds if (index == 0) { 2261da177e4SLinus Torvalds printk("register_blkdev: failed to get major for %s\n", 2271da177e4SLinus Torvalds name); 2281da177e4SLinus Torvalds ret = -EBUSY; 2291da177e4SLinus Torvalds goto out; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds major = index; 2321da177e4SLinus Torvalds ret = major; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); 2361da177e4SLinus Torvalds if (p == NULL) { 2371da177e4SLinus Torvalds ret = -ENOMEM; 2381da177e4SLinus Torvalds goto out; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds p->major = major; 2421da177e4SLinus Torvalds strlcpy(p->name, name, sizeof(p->name)); 2431da177e4SLinus Torvalds p->next = NULL; 2441da177e4SLinus Torvalds index = major_to_index(major); 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds for (n = &major_names[index]; *n; n = &(*n)->next) { 2471da177e4SLinus Torvalds if ((*n)->major == major) 2481da177e4SLinus Torvalds break; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds if (!*n) 2511da177e4SLinus Torvalds *n = p; 2521da177e4SLinus Torvalds else 2531da177e4SLinus Torvalds ret = -EBUSY; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds if (ret < 0) { 2561da177e4SLinus Torvalds printk("register_blkdev: cannot get major %d for %s\n", 2571da177e4SLinus Torvalds major, name); 2581da177e4SLinus Torvalds kfree(p); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds out: 261edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 2621da177e4SLinus Torvalds return ret; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds EXPORT_SYMBOL(register_blkdev); 2661da177e4SLinus Torvalds 267f4480240SAkinobu Mita void unregister_blkdev(unsigned int major, const char *name) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds struct blk_major_name **n; 2701da177e4SLinus Torvalds struct blk_major_name *p = NULL; 2711da177e4SLinus Torvalds int index = major_to_index(major); 2721da177e4SLinus Torvalds 273edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 2741da177e4SLinus Torvalds for (n = &major_names[index]; *n; n = &(*n)->next) 2751da177e4SLinus Torvalds if ((*n)->major == major) 2761da177e4SLinus Torvalds break; 277294462a5SAkinobu Mita if (!*n || strcmp((*n)->name, name)) { 278294462a5SAkinobu Mita WARN_ON(1); 279294462a5SAkinobu Mita } else { 2801da177e4SLinus Torvalds p = *n; 2811da177e4SLinus Torvalds *n = p->next; 2821da177e4SLinus Torvalds } 283edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 2841da177e4SLinus Torvalds kfree(p); 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_blkdev); 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds static struct kobj_map *bdev_map; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* 2921da177e4SLinus Torvalds * Register device numbers dev..(dev+range-1) 2931da177e4SLinus Torvalds * range must be nonzero 2941da177e4SLinus Torvalds * The hash chain is sorted on range, so that subranges can override. 2951da177e4SLinus Torvalds */ 296edfaa7c3SKay Sievers void blk_register_region(dev_t devt, unsigned long range, struct module *module, 2971da177e4SLinus Torvalds struct kobject *(*probe)(dev_t, int *, void *), 2981da177e4SLinus Torvalds int (*lock)(dev_t, void *), void *data) 2991da177e4SLinus Torvalds { 300edfaa7c3SKay Sievers kobj_map(bdev_map, devt, range, module, probe, lock, data); 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds EXPORT_SYMBOL(blk_register_region); 3041da177e4SLinus Torvalds 305edfaa7c3SKay Sievers void blk_unregister_region(dev_t devt, unsigned long range) 3061da177e4SLinus Torvalds { 307edfaa7c3SKay Sievers kobj_unmap(bdev_map, devt, range); 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds EXPORT_SYMBOL(blk_unregister_region); 3111da177e4SLinus Torvalds 312cf771cb5STejun Heo static struct kobject *exact_match(dev_t devt, int *partno, void *data) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds struct gendisk *p = data; 315edfaa7c3SKay Sievers 316edfaa7c3SKay Sievers return &p->dev.kobj; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 319edfaa7c3SKay Sievers static int exact_lock(dev_t devt, void *data) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds struct gendisk *p = data; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds if (!get_disk(p)) 3241da177e4SLinus Torvalds return -1; 3251da177e4SLinus Torvalds return 0; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds /** 3291da177e4SLinus Torvalds * add_disk - add partitioning information to kernel list 3301da177e4SLinus Torvalds * @disk: per-device partitioning information 3311da177e4SLinus Torvalds * 3321da177e4SLinus Torvalds * This function registers the partitioning information in @disk 3331da177e4SLinus Torvalds * with the kernel. 3341da177e4SLinus Torvalds */ 3351da177e4SLinus Torvalds void add_disk(struct gendisk *disk) 3361da177e4SLinus Torvalds { 337cf0ca9feSPeter Zijlstra struct backing_dev_info *bdi; 3386ffeea77SGreg Kroah-Hartman int retval; 339cf0ca9feSPeter Zijlstra 3401da177e4SLinus Torvalds disk->flags |= GENHD_FL_UP; 341f331c029STejun Heo disk->dev.devt = MKDEV(disk->major, disk->first_minor); 342f331c029STejun Heo blk_register_region(disk_devt(disk), disk->minors, NULL, 343f331c029STejun Heo exact_match, exact_lock, disk); 3441da177e4SLinus Torvalds register_disk(disk); 3451da177e4SLinus Torvalds blk_register_queue(disk); 346cf0ca9feSPeter Zijlstra 347cf0ca9feSPeter Zijlstra bdi = &disk->queue->backing_dev_info; 348f331c029STejun Heo bdi_register_dev(bdi, disk_devt(disk)); 3496ffeea77SGreg Kroah-Hartman retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); 3506ffeea77SGreg Kroah-Hartman WARN_ON(retval); 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds EXPORT_SYMBOL(add_disk); 3541da177e4SLinus Torvalds EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds void unlink_gendisk(struct gendisk *disk) 3571da177e4SLinus Torvalds { 358cf0ca9feSPeter Zijlstra sysfs_remove_link(&disk->dev.kobj, "bdi"); 359cf0ca9feSPeter Zijlstra bdi_unregister(&disk->queue->backing_dev_info); 3601da177e4SLinus Torvalds blk_unregister_queue(disk); 361f331c029STejun Heo blk_unregister_region(disk_devt(disk), disk->minors); 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds /** 3651da177e4SLinus Torvalds * get_gendisk - get partitioning information for a given device 366710027a4SRandy Dunlap * @devt: device to get partitioning information for 367710027a4SRandy Dunlap * @part: returned partition index 3681da177e4SLinus Torvalds * 3691da177e4SLinus Torvalds * This function gets the structure containing partitioning 370710027a4SRandy Dunlap * information for the given device @devt. 3711da177e4SLinus Torvalds */ 372cf771cb5STejun Heo struct gendisk *get_gendisk(dev_t devt, int *partno) 3731da177e4SLinus Torvalds { 374cf771cb5STejun Heo struct kobject *kobj = kobj_lookup(bdev_map, devt, partno); 375edfaa7c3SKay Sievers struct device *dev = kobj_to_dev(kobj); 376edfaa7c3SKay Sievers 377edfaa7c3SKay Sievers return kobj ? dev_to_disk(dev) : NULL; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 380f331c029STejun Heo /** 381f331c029STejun Heo * bdget_disk - do bdget() by gendisk and partition number 382f331c029STejun Heo * @disk: gendisk of interest 383f331c029STejun Heo * @partno: partition number 384f331c029STejun Heo * 385f331c029STejun Heo * Find partition @partno from @disk, do bdget() on it. 386f331c029STejun Heo * 387f331c029STejun Heo * CONTEXT: 388f331c029STejun Heo * Don't care. 389f331c029STejun Heo * 390f331c029STejun Heo * RETURNS: 391f331c029STejun Heo * Resulting block_device on success, NULL on failure. 392f331c029STejun Heo */ 393f331c029STejun Heo extern struct block_device *bdget_disk(struct gendisk *disk, int partno) 394f331c029STejun Heo { 395f331c029STejun Heo dev_t devt = MKDEV(0, 0); 396f331c029STejun Heo 397f331c029STejun Heo if (partno == 0) 398f331c029STejun Heo devt = disk_devt(disk); 399f331c029STejun Heo else { 400*e71bf0d0STejun Heo struct hd_struct *part; 401f331c029STejun Heo 402*e71bf0d0STejun Heo part = disk_get_part(disk, partno); 403f331c029STejun Heo if (part && part->nr_sects) 404f331c029STejun Heo devt = part_devt(part); 405*e71bf0d0STejun Heo disk_put_part(part); 406f331c029STejun Heo } 407f331c029STejun Heo 408f331c029STejun Heo if (likely(devt != MKDEV(0, 0))) 409f331c029STejun Heo return bdget(devt); 410f331c029STejun Heo return NULL; 411f331c029STejun Heo } 412f331c029STejun Heo EXPORT_SYMBOL(bdget_disk); 413f331c029STejun Heo 414dd2a345fSDave Gilbert /* 4155c6f35c5SGreg Kroah-Hartman * print a full list of all partitions - intended for places where the root 4165c6f35c5SGreg Kroah-Hartman * filesystem can't be mounted and thus to give the victim some idea of what 4175c6f35c5SGreg Kroah-Hartman * went wrong 4185c6f35c5SGreg Kroah-Hartman */ 4195c6f35c5SGreg Kroah-Hartman void __init printk_all_partitions(void) 4205c6f35c5SGreg Kroah-Hartman { 421def4e38dSTejun Heo struct class_dev_iter iter; 422def4e38dSTejun Heo struct device *dev; 423def4e38dSTejun Heo 424def4e38dSTejun Heo class_dev_iter_init(&iter, &block_class, NULL, &disk_type); 425def4e38dSTejun Heo while ((dev = class_dev_iter_next(&iter))) { 426def4e38dSTejun Heo struct gendisk *disk = dev_to_disk(dev); 427*e71bf0d0STejun Heo struct disk_part_iter piter; 428*e71bf0d0STejun Heo struct hd_struct *part; 429def4e38dSTejun Heo char buf[BDEVNAME_SIZE]; 430def4e38dSTejun Heo 431def4e38dSTejun Heo /* 432def4e38dSTejun Heo * Don't show empty devices or things that have been 433def4e38dSTejun Heo * surpressed 434def4e38dSTejun Heo */ 435def4e38dSTejun Heo if (get_capacity(disk) == 0 || 436def4e38dSTejun Heo (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) 437def4e38dSTejun Heo continue; 438def4e38dSTejun Heo 439def4e38dSTejun Heo /* 440def4e38dSTejun Heo * Note, unlike /proc/partitions, I am showing the 441def4e38dSTejun Heo * numbers in hex - the same format as the root= 442def4e38dSTejun Heo * option takes. 443def4e38dSTejun Heo */ 444def4e38dSTejun Heo printk("%02x%02x %10llu %s", 445f331c029STejun Heo MAJOR(disk_devt(disk)), MINOR(disk_devt(disk)), 446def4e38dSTejun Heo (unsigned long long)get_capacity(disk) >> 1, 447def4e38dSTejun Heo disk_name(disk, 0, buf)); 448def4e38dSTejun Heo if (disk->driverfs_dev != NULL && 449def4e38dSTejun Heo disk->driverfs_dev->driver != NULL) 450def4e38dSTejun Heo printk(" driver: %s\n", 451def4e38dSTejun Heo disk->driverfs_dev->driver->name); 452def4e38dSTejun Heo else 453def4e38dSTejun Heo printk(" (driver?)\n"); 454def4e38dSTejun Heo 455def4e38dSTejun Heo /* now show the partitions */ 456*e71bf0d0STejun Heo disk_part_iter_init(&piter, disk, 0); 457*e71bf0d0STejun Heo while ((part = disk_part_iter_next(&piter))) 458def4e38dSTejun Heo printk(" %02x%02x %10llu %s\n", 459f331c029STejun Heo MAJOR(part_devt(part)), MINOR(part_devt(part)), 460f331c029STejun Heo (unsigned long long)part->nr_sects >> 1, 461f331c029STejun Heo disk_name(disk, part->partno, buf)); 462*e71bf0d0STejun Heo disk_part_iter_exit(&piter); 463def4e38dSTejun Heo } 464def4e38dSTejun Heo class_dev_iter_exit(&iter); 465dd2a345fSDave Gilbert } 466dd2a345fSDave Gilbert 4671da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 4681da177e4SLinus Torvalds /* iterator */ 469def4e38dSTejun Heo static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) 47068c4d4a7SGreg Kroah-Hartman { 471def4e38dSTejun Heo loff_t skip = *pos; 472def4e38dSTejun Heo struct class_dev_iter *iter; 473def4e38dSTejun Heo struct device *dev; 47468c4d4a7SGreg Kroah-Hartman 475def4e38dSTejun Heo iter = kmalloc(GFP_KERNEL, sizeof(*iter)); 476def4e38dSTejun Heo if (!iter) 477def4e38dSTejun Heo return ERR_PTR(-ENOMEM); 478def4e38dSTejun Heo 479def4e38dSTejun Heo seqf->private = iter; 480def4e38dSTejun Heo class_dev_iter_init(iter, &block_class, NULL, &disk_type); 481def4e38dSTejun Heo do { 482def4e38dSTejun Heo dev = class_dev_iter_next(iter); 483def4e38dSTejun Heo if (!dev) 484def4e38dSTejun Heo return NULL; 485def4e38dSTejun Heo } while (skip--); 486def4e38dSTejun Heo 487def4e38dSTejun Heo return dev_to_disk(dev); 48868c4d4a7SGreg Kroah-Hartman } 48968c4d4a7SGreg Kroah-Hartman 490def4e38dSTejun Heo static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos) 4911da177e4SLinus Torvalds { 492edfaa7c3SKay Sievers struct device *dev; 49366c64afeSGreg Kroah-Hartman 494def4e38dSTejun Heo (*pos)++; 495def4e38dSTejun Heo dev = class_dev_iter_next(seqf->private); 4962ac3cee5STejun Heo if (dev) 497edfaa7c3SKay Sievers return dev_to_disk(dev); 4982ac3cee5STejun Heo 4991da177e4SLinus Torvalds return NULL; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 502def4e38dSTejun Heo static void disk_seqf_stop(struct seq_file *seqf, void *v) 50327f30251SGreg Kroah-Hartman { 504def4e38dSTejun Heo struct class_dev_iter *iter = seqf->private; 505def4e38dSTejun Heo 506def4e38dSTejun Heo /* stop is called even after start failed :-( */ 507def4e38dSTejun Heo if (iter) { 508def4e38dSTejun Heo class_dev_iter_exit(iter); 509def4e38dSTejun Heo kfree(iter); 510def4e38dSTejun Heo } 51127f30251SGreg Kroah-Hartman } 51227f30251SGreg Kroah-Hartman 513def4e38dSTejun Heo static void *show_partition_start(struct seq_file *seqf, loff_t *pos) 5141da177e4SLinus Torvalds { 515def4e38dSTejun Heo static void *p; 5161da177e4SLinus Torvalds 517def4e38dSTejun Heo p = disk_seqf_start(seqf, pos); 518def4e38dSTejun Heo if (!IS_ERR(p) && p) 519def4e38dSTejun Heo seq_puts(seqf, "major minor #blocks name\n\n"); 520def4e38dSTejun Heo return p; 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 523cf771cb5STejun Heo static int show_partition(struct seq_file *seqf, void *v) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds struct gendisk *sgp = v; 526*e71bf0d0STejun Heo struct disk_part_iter piter; 527*e71bf0d0STejun Heo struct hd_struct *part; 5281da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /* Don't show non-partitionable removeable devices or empty devices */ 531f331c029STejun Heo if (!get_capacity(sgp) || (!disk_max_parts(sgp) && 532f331c029STejun Heo (sgp->flags & GENHD_FL_REMOVABLE))) 5331da177e4SLinus Torvalds return 0; 5341da177e4SLinus Torvalds if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) 5351da177e4SLinus Torvalds return 0; 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /* show the full disk and all non-0 size partitions of it */ 538cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %10llu %s\n", 539f331c029STejun Heo MAJOR(disk_devt(sgp)), MINOR(disk_devt(sgp)), 5401da177e4SLinus Torvalds (unsigned long long)get_capacity(sgp) >> 1, 5411da177e4SLinus Torvalds disk_name(sgp, 0, buf)); 542*e71bf0d0STejun Heo 543*e71bf0d0STejun Heo disk_part_iter_init(&piter, sgp, 0); 544*e71bf0d0STejun Heo while ((part = disk_part_iter_next(&piter))) 545cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %10llu %s\n", 546f331c029STejun Heo MAJOR(part_devt(part)), MINOR(part_devt(part)), 547f331c029STejun Heo (unsigned long long)part->nr_sects >> 1, 548f331c029STejun Heo disk_name(sgp, part->partno, buf)); 549*e71bf0d0STejun Heo disk_part_iter_exit(&piter); 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds return 0; 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 55412f32bb3SJan Engelhardt const struct seq_operations partitions_op = { 555def4e38dSTejun Heo .start = show_partition_start, 556def4e38dSTejun Heo .next = disk_seqf_next, 557def4e38dSTejun Heo .stop = disk_seqf_stop, 5581da177e4SLinus Torvalds .show = show_partition 5591da177e4SLinus Torvalds }; 5601da177e4SLinus Torvalds #endif 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds 563cf771cb5STejun Heo static struct kobject *base_probe(dev_t devt, int *partno, void *data) 5641da177e4SLinus Torvalds { 565edfaa7c3SKay Sievers if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 5661da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */ 567edfaa7c3SKay Sievers request_module("block-major-%d", MAJOR(devt)); 5681da177e4SLinus Torvalds return NULL; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds static int __init genhd_device_init(void) 5721da177e4SLinus Torvalds { 573e105b8bfSDan Williams int error; 574e105b8bfSDan Williams 575e105b8bfSDan Williams block_class.dev_kobj = sysfs_dev_block_kobj; 576e105b8bfSDan Williams error = class_register(&block_class); 577ee27a558SRoland McGrath if (unlikely(error)) 578ee27a558SRoland McGrath return error; 579edfaa7c3SKay Sievers bdev_map = kobj_map_init(base_probe, &block_class_lock); 5801da177e4SLinus Torvalds blk_dev_init(); 581edfaa7c3SKay Sievers 582edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 583edfaa7c3SKay Sievers /* create top-level block dir */ 584edfaa7c3SKay Sievers block_depr = kobject_create_and_add("block", NULL); 585edfaa7c3SKay Sievers #endif 586830d3cfbSGreg Kroah-Hartman return 0; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds subsys_initcall(genhd_device_init); 5901da177e4SLinus Torvalds 591edfaa7c3SKay Sievers static ssize_t disk_range_show(struct device *dev, 592edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 5931da177e4SLinus Torvalds { 594edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 5951da177e4SLinus Torvalds 596edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->minors); 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds 599edfaa7c3SKay Sievers static ssize_t disk_removable_show(struct device *dev, 600edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 601a7fd6706SKay Sievers { 602edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 603a7fd6706SKay Sievers 604edfaa7c3SKay Sievers return sprintf(buf, "%d\n", 6051da177e4SLinus Torvalds (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 606edfaa7c3SKay Sievers } 6071da177e4SLinus Torvalds 6081c9ce527SKay Sievers static ssize_t disk_ro_show(struct device *dev, 6091c9ce527SKay Sievers struct device_attribute *attr, char *buf) 6101c9ce527SKay Sievers { 6111c9ce527SKay Sievers struct gendisk *disk = dev_to_disk(dev); 6121c9ce527SKay Sievers 6131c9ce527SKay Sievers return sprintf(buf, "%d\n", disk->policy ? 1 : 0); 6141c9ce527SKay Sievers } 6151c9ce527SKay Sievers 616edfaa7c3SKay Sievers static ssize_t disk_size_show(struct device *dev, 617edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 6181da177e4SLinus Torvalds { 619edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 620edfaa7c3SKay Sievers 621edfaa7c3SKay Sievers return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); 6221da177e4SLinus Torvalds } 623edfaa7c3SKay Sievers 624edfaa7c3SKay Sievers static ssize_t disk_capability_show(struct device *dev, 625edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 62686ce18d7SKristen Carlson Accardi { 627edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 628edfaa7c3SKay Sievers 629edfaa7c3SKay Sievers return sprintf(buf, "%x\n", disk->flags); 63086ce18d7SKristen Carlson Accardi } 631edfaa7c3SKay Sievers 632edfaa7c3SKay Sievers static ssize_t disk_stat_show(struct device *dev, 633edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 6341da177e4SLinus Torvalds { 635edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 636edfaa7c3SKay Sievers 6371da177e4SLinus Torvalds preempt_disable(); 6381da177e4SLinus Torvalds disk_round_stats(disk); 6391da177e4SLinus Torvalds preempt_enable(); 640edfaa7c3SKay Sievers return sprintf(buf, 641837c7878SBen Woodard "%8lu %8lu %8llu %8u " 642837c7878SBen Woodard "%8lu %8lu %8llu %8u " 6431da177e4SLinus Torvalds "%8u %8u %8u" 6441da177e4SLinus Torvalds "\n", 64547a00410SJens Axboe disk_stat_read(disk, ios[READ]), 64647a00410SJens Axboe disk_stat_read(disk, merges[READ]), 64747a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[READ]), 64847a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), 64947a00410SJens Axboe disk_stat_read(disk, ios[WRITE]), 65047a00410SJens Axboe disk_stat_read(disk, merges[WRITE]), 65147a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[WRITE]), 65247a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), 6531da177e4SLinus Torvalds disk->in_flight, 6541da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, io_ticks)), 6551da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds 658c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 659edfaa7c3SKay Sievers static ssize_t disk_fail_show(struct device *dev, 660edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 661edfaa7c3SKay Sievers { 662edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 663c17bb495SAkinobu Mita 664edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); 665edfaa7c3SKay Sievers } 666edfaa7c3SKay Sievers 667edfaa7c3SKay Sievers static ssize_t disk_fail_store(struct device *dev, 668edfaa7c3SKay Sievers struct device_attribute *attr, 669c17bb495SAkinobu Mita const char *buf, size_t count) 670c17bb495SAkinobu Mita { 671edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 672c17bb495SAkinobu Mita int i; 673c17bb495SAkinobu Mita 674c17bb495SAkinobu Mita if (count > 0 && sscanf(buf, "%d", &i) > 0) { 675c17bb495SAkinobu Mita if (i == 0) 676c17bb495SAkinobu Mita disk->flags &= ~GENHD_FL_FAIL; 677c17bb495SAkinobu Mita else 678c17bb495SAkinobu Mita disk->flags |= GENHD_FL_FAIL; 679c17bb495SAkinobu Mita } 680c17bb495SAkinobu Mita 681c17bb495SAkinobu Mita return count; 682c17bb495SAkinobu Mita } 683c17bb495SAkinobu Mita 684c17bb495SAkinobu Mita #endif 685c17bb495SAkinobu Mita 686edfaa7c3SKay Sievers static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 687edfaa7c3SKay Sievers static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 6881c9ce527SKay Sievers static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 689edfaa7c3SKay Sievers static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 690edfaa7c3SKay Sievers static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 691edfaa7c3SKay Sievers static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 692c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 693edfaa7c3SKay Sievers static struct device_attribute dev_attr_fail = 694edfaa7c3SKay Sievers __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); 695c17bb495SAkinobu Mita #endif 696edfaa7c3SKay Sievers 697edfaa7c3SKay Sievers static struct attribute *disk_attrs[] = { 698edfaa7c3SKay Sievers &dev_attr_range.attr, 699edfaa7c3SKay Sievers &dev_attr_removable.attr, 7001c9ce527SKay Sievers &dev_attr_ro.attr, 701edfaa7c3SKay Sievers &dev_attr_size.attr, 702edfaa7c3SKay Sievers &dev_attr_capability.attr, 703edfaa7c3SKay Sievers &dev_attr_stat.attr, 704edfaa7c3SKay Sievers #ifdef CONFIG_FAIL_MAKE_REQUEST 705edfaa7c3SKay Sievers &dev_attr_fail.attr, 706edfaa7c3SKay Sievers #endif 707edfaa7c3SKay Sievers NULL 7081da177e4SLinus Torvalds }; 7091da177e4SLinus Torvalds 710edfaa7c3SKay Sievers static struct attribute_group disk_attr_group = { 711edfaa7c3SKay Sievers .attrs = disk_attrs, 712edfaa7c3SKay Sievers }; 713edfaa7c3SKay Sievers 714edfaa7c3SKay Sievers static struct attribute_group *disk_attr_groups[] = { 715edfaa7c3SKay Sievers &disk_attr_group, 716edfaa7c3SKay Sievers NULL 717edfaa7c3SKay Sievers }; 718edfaa7c3SKay Sievers 719edfaa7c3SKay Sievers static void disk_release(struct device *dev) 7201da177e4SLinus Torvalds { 721edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 722edfaa7c3SKay Sievers 7231da177e4SLinus Torvalds kfree(disk->random); 724*e71bf0d0STejun Heo kfree(disk->__part); 7251da177e4SLinus Torvalds free_disk_stats(disk); 7261da177e4SLinus Torvalds kfree(disk); 7271da177e4SLinus Torvalds } 728edfaa7c3SKay Sievers struct class block_class = { 729edfaa7c3SKay Sievers .name = "block", 7301da177e4SLinus Torvalds }; 7311da177e4SLinus Torvalds 7321826eadfSAdrian Bunk static struct device_type disk_type = { 733edfaa7c3SKay Sievers .name = "disk", 734edfaa7c3SKay Sievers .groups = disk_attr_groups, 735edfaa7c3SKay Sievers .release = disk_release, 7361da177e4SLinus Torvalds }; 7371da177e4SLinus Torvalds 738a6e2ba88SRandy Dunlap #ifdef CONFIG_PROC_FS 739cf771cb5STejun Heo /* 740cf771cb5STejun Heo * aggregate disk stat collector. Uses the same stats that the sysfs 741cf771cb5STejun Heo * entries do, above, but makes them available through one seq_file. 742cf771cb5STejun Heo * 743cf771cb5STejun Heo * The output looks suspiciously like /proc/partitions with a bunch of 744cf771cb5STejun Heo * extra fields. 745cf771cb5STejun Heo */ 746cf771cb5STejun Heo static int diskstats_show(struct seq_file *seqf, void *v) 7471da177e4SLinus Torvalds { 7481da177e4SLinus Torvalds struct gendisk *gp = v; 749*e71bf0d0STejun Heo struct disk_part_iter piter; 750*e71bf0d0STejun Heo struct hd_struct *hd; 7511da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds /* 754edfaa7c3SKay Sievers if (&gp->dev.kobj.entry == block_class.devices.next) 755cf771cb5STejun Heo seq_puts(seqf, "major minor name" 7561da177e4SLinus Torvalds " rio rmerge rsect ruse wio wmerge " 7571da177e4SLinus Torvalds "wsect wuse running use aveq" 7581da177e4SLinus Torvalds "\n\n"); 7591da177e4SLinus Torvalds */ 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds preempt_disable(); 7621da177e4SLinus Torvalds disk_round_stats(gp); 7631da177e4SLinus Torvalds preempt_enable(); 764cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 765f331c029STejun Heo MAJOR(disk_devt(gp)), MINOR(disk_devt(gp)), 766f331c029STejun Heo disk_name(gp, 0, buf), 767a362357bSJens Axboe disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), 768a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[0]), 769a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[0])), 770a362357bSJens Axboe disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), 771a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[1]), 772a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[1])), 7731da177e4SLinus Torvalds gp->in_flight, 7741da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, io_ticks)), 7751da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds /* now show all non-0 size partitions of it */ 778*e71bf0d0STejun Heo disk_part_iter_init(&piter, gp, 0); 779*e71bf0d0STejun Heo while ((hd = disk_part_iter_next(&piter))) { 78028f39d55SJerome Marchand preempt_disable(); 78128f39d55SJerome Marchand part_round_stats(hd); 78228f39d55SJerome Marchand preempt_enable(); 783cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %s %lu %lu %llu " 78428f39d55SJerome Marchand "%u %lu %lu %llu %u %u %u %u\n", 785f331c029STejun Heo MAJOR(part_devt(hd)), MINOR(part_devt(hd)), 786f331c029STejun Heo disk_name(gp, hd->partno, buf), 78728f39d55SJerome Marchand part_stat_read(hd, ios[0]), 78828f39d55SJerome Marchand part_stat_read(hd, merges[0]), 78928f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[0]), 79028f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[0])), 79128f39d55SJerome Marchand part_stat_read(hd, ios[1]), 79228f39d55SJerome Marchand part_stat_read(hd, merges[1]), 79328f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[1]), 79428f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[1])), 79528f39d55SJerome Marchand hd->in_flight, 79628f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, io_ticks)), 79728f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, time_in_queue)) 79828f39d55SJerome Marchand ); 7991da177e4SLinus Torvalds } 800*e71bf0d0STejun Heo disk_part_iter_exit(&piter); 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds return 0; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 80512f32bb3SJan Engelhardt const struct seq_operations diskstats_op = { 806def4e38dSTejun Heo .start = disk_seqf_start, 807def4e38dSTejun Heo .next = disk_seqf_next, 808def4e38dSTejun Heo .stop = disk_seqf_stop, 8091da177e4SLinus Torvalds .show = diskstats_show 8101da177e4SLinus Torvalds }; 811a6e2ba88SRandy Dunlap #endif /* CONFIG_PROC_FS */ 8121da177e4SLinus Torvalds 8138ce7ad7bSKristen Carlson Accardi static void media_change_notify_thread(struct work_struct *work) 8148ce7ad7bSKristen Carlson Accardi { 8158ce7ad7bSKristen Carlson Accardi struct gendisk *gd = container_of(work, struct gendisk, async_notify); 8168ce7ad7bSKristen Carlson Accardi char event[] = "MEDIA_CHANGE=1"; 8178ce7ad7bSKristen Carlson Accardi char *envp[] = { event, NULL }; 8188ce7ad7bSKristen Carlson Accardi 8198ce7ad7bSKristen Carlson Accardi /* 8208ce7ad7bSKristen Carlson Accardi * set enviroment vars to indicate which event this is for 8218ce7ad7bSKristen Carlson Accardi * so that user space will know to go check the media status. 8228ce7ad7bSKristen Carlson Accardi */ 823edfaa7c3SKay Sievers kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); 8248ce7ad7bSKristen Carlson Accardi put_device(gd->driverfs_dev); 8258ce7ad7bSKristen Carlson Accardi } 8268ce7ad7bSKristen Carlson Accardi 8271826eadfSAdrian Bunk #if 0 8288ce7ad7bSKristen Carlson Accardi void genhd_media_change_notify(struct gendisk *disk) 8298ce7ad7bSKristen Carlson Accardi { 8308ce7ad7bSKristen Carlson Accardi get_device(disk->driverfs_dev); 8318ce7ad7bSKristen Carlson Accardi schedule_work(&disk->async_notify); 8328ce7ad7bSKristen Carlson Accardi } 8338ce7ad7bSKristen Carlson Accardi EXPORT_SYMBOL_GPL(genhd_media_change_notify); 8341826eadfSAdrian Bunk #endif /* 0 */ 8358ce7ad7bSKristen Carlson Accardi 836cf771cb5STejun Heo dev_t blk_lookup_devt(const char *name, int partno) 837edfaa7c3SKay Sievers { 838edfaa7c3SKay Sievers dev_t devt = MKDEV(0, 0); 839def4e38dSTejun Heo struct class_dev_iter iter; 840def4e38dSTejun Heo struct device *dev; 841edfaa7c3SKay Sievers 842def4e38dSTejun Heo class_dev_iter_init(&iter, &block_class, NULL, &disk_type); 843def4e38dSTejun Heo while ((dev = class_dev_iter_next(&iter))) { 844def4e38dSTejun Heo struct gendisk *disk = dev_to_disk(dev); 845def4e38dSTejun Heo 846f331c029STejun Heo if (strcmp(dev->bus_id, name)) 847f331c029STejun Heo continue; 848f331c029STejun Heo if (partno < 0 || partno > disk_max_parts(disk)) 849f331c029STejun Heo continue; 850f331c029STejun Heo 851f331c029STejun Heo if (partno == 0) 852f331c029STejun Heo devt = disk_devt(disk); 853f331c029STejun Heo else { 854*e71bf0d0STejun Heo struct hd_struct *part; 855f331c029STejun Heo 856*e71bf0d0STejun Heo part = disk_get_part(disk, partno); 857*e71bf0d0STejun Heo if (!part || !part->nr_sects) { 858*e71bf0d0STejun Heo disk_put_part(part); 859f331c029STejun Heo continue; 860*e71bf0d0STejun Heo } 861f331c029STejun Heo 862f331c029STejun Heo devt = part_devt(part); 863*e71bf0d0STejun Heo disk_put_part(part); 8645c0ef6d0SKay Sievers } 865f331c029STejun Heo break; 866def4e38dSTejun Heo } 867def4e38dSTejun Heo class_dev_iter_exit(&iter); 868edfaa7c3SKay Sievers return devt; 869edfaa7c3SKay Sievers } 870edfaa7c3SKay Sievers EXPORT_SYMBOL(blk_lookup_devt); 871edfaa7c3SKay Sievers 8721da177e4SLinus Torvalds struct gendisk *alloc_disk(int minors) 8731da177e4SLinus Torvalds { 8741946089aSChristoph Lameter return alloc_disk_node(minors, -1); 8751946089aSChristoph Lameter } 8761946089aSChristoph Lameter 8771946089aSChristoph Lameter struct gendisk *alloc_disk_node(int minors, int node_id) 8781946089aSChristoph Lameter { 8791946089aSChristoph Lameter struct gendisk *disk; 8801946089aSChristoph Lameter 88194f6030cSChristoph Lameter disk = kmalloc_node(sizeof(struct gendisk), 88294f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 8831da177e4SLinus Torvalds if (disk) { 8841da177e4SLinus Torvalds if (!init_disk_stats(disk)) { 8851da177e4SLinus Torvalds kfree(disk); 8861da177e4SLinus Torvalds return NULL; 8871da177e4SLinus Torvalds } 8881da177e4SLinus Torvalds if (minors > 1) { 8891da177e4SLinus Torvalds int size = (minors - 1) * sizeof(struct hd_struct *); 890*e71bf0d0STejun Heo disk->__part = kmalloc_node(size, 89194f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 892*e71bf0d0STejun Heo if (!disk->__part) { 893c7674030SJerome Marchand free_disk_stats(disk); 8941da177e4SLinus Torvalds kfree(disk); 8951da177e4SLinus Torvalds return NULL; 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds disk->minors = minors; 8991da177e4SLinus Torvalds rand_initialize_disk(disk); 900edfaa7c3SKay Sievers disk->dev.class = &block_class; 901edfaa7c3SKay Sievers disk->dev.type = &disk_type; 902edfaa7c3SKay Sievers device_initialize(&disk->dev); 9038ce7ad7bSKristen Carlson Accardi INIT_WORK(&disk->async_notify, 9048ce7ad7bSKristen Carlson Accardi media_change_notify_thread); 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds return disk; 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_disk); 9101946089aSChristoph Lameter EXPORT_SYMBOL(alloc_disk_node); 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds struct kobject *get_disk(struct gendisk *disk) 9131da177e4SLinus Torvalds { 9141da177e4SLinus Torvalds struct module *owner; 9151da177e4SLinus Torvalds struct kobject *kobj; 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds if (!disk->fops) 9181da177e4SLinus Torvalds return NULL; 9191da177e4SLinus Torvalds owner = disk->fops->owner; 9201da177e4SLinus Torvalds if (owner && !try_module_get(owner)) 9211da177e4SLinus Torvalds return NULL; 922edfaa7c3SKay Sievers kobj = kobject_get(&disk->dev.kobj); 9231da177e4SLinus Torvalds if (kobj == NULL) { 9241da177e4SLinus Torvalds module_put(owner); 9251da177e4SLinus Torvalds return NULL; 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds return kobj; 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds } 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds EXPORT_SYMBOL(get_disk); 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds void put_disk(struct gendisk *disk) 9341da177e4SLinus Torvalds { 9351da177e4SLinus Torvalds if (disk) 936edfaa7c3SKay Sievers kobject_put(&disk->dev.kobj); 9371da177e4SLinus Torvalds } 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds EXPORT_SYMBOL(put_disk); 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds void set_device_ro(struct block_device *bdev, int flag) 9421da177e4SLinus Torvalds { 9431da177e4SLinus Torvalds if (bdev->bd_contains != bdev) 9441da177e4SLinus Torvalds bdev->bd_part->policy = flag; 9451da177e4SLinus Torvalds else 9461da177e4SLinus Torvalds bdev->bd_disk->policy = flag; 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds EXPORT_SYMBOL(set_device_ro); 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds void set_disk_ro(struct gendisk *disk, int flag) 9521da177e4SLinus Torvalds { 953*e71bf0d0STejun Heo struct disk_part_iter piter; 954*e71bf0d0STejun Heo struct hd_struct *part; 955*e71bf0d0STejun Heo 9561da177e4SLinus Torvalds disk->policy = flag; 957*e71bf0d0STejun Heo disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); 958*e71bf0d0STejun Heo while ((part = disk_part_iter_next(&piter))) 959*e71bf0d0STejun Heo part->policy = flag; 960*e71bf0d0STejun Heo disk_part_iter_exit(&piter); 9611da177e4SLinus Torvalds } 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds EXPORT_SYMBOL(set_disk_ro); 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds int bdev_read_only(struct block_device *bdev) 9661da177e4SLinus Torvalds { 9671da177e4SLinus Torvalds if (!bdev) 9681da177e4SLinus Torvalds return 0; 9691da177e4SLinus Torvalds else if (bdev->bd_contains != bdev) 9701da177e4SLinus Torvalds return bdev->bd_part->policy; 9711da177e4SLinus Torvalds else 9721da177e4SLinus Torvalds return bdev->bd_disk->policy; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds EXPORT_SYMBOL(bdev_read_only); 9761da177e4SLinus Torvalds 977cf771cb5STejun Heo int invalidate_partition(struct gendisk *disk, int partno) 9781da177e4SLinus Torvalds { 9791da177e4SLinus Torvalds int res = 0; 980cf771cb5STejun Heo struct block_device *bdev = bdget_disk(disk, partno); 9811da177e4SLinus Torvalds if (bdev) { 9822ef41634SChristoph Hellwig fsync_bdev(bdev); 9832ef41634SChristoph Hellwig res = __invalidate_device(bdev); 9841da177e4SLinus Torvalds bdput(bdev); 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds return res; 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds 9891da177e4SLinus Torvalds EXPORT_SYMBOL(invalidate_partition); 990