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 291da177e4SLinus Torvalds /* 301da177e4SLinus Torvalds * Can be deleted altogether. Later. 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds static struct blk_major_name { 341da177e4SLinus Torvalds struct blk_major_name *next; 351da177e4SLinus Torvalds int major; 361da177e4SLinus Torvalds char name[16]; 3768eef3b4SJoe Korty } *major_names[BLKDEV_MAJOR_HASH_SIZE]; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* index in the above - for now: assume no multimajor ranges */ 401da177e4SLinus Torvalds static inline int major_to_index(int major) 411da177e4SLinus Torvalds { 4268eef3b4SJoe Korty return major % BLKDEV_MAJOR_HASH_SIZE; 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 4568eef3b4SJoe Korty #ifdef CONFIG_PROC_FS 46*cf771cb5STejun Heo void blkdev_show(struct seq_file *seqf, off_t offset) 477170be5fSNeil Horman { 4868eef3b4SJoe Korty struct blk_major_name *dp; 497170be5fSNeil Horman 5068eef3b4SJoe Korty if (offset < BLKDEV_MAJOR_HASH_SIZE) { 51edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 5268eef3b4SJoe Korty for (dp = major_names[offset]; dp; dp = dp->next) 53*cf771cb5STejun Heo seq_printf(seqf, "%3d %s\n", dp->major, dp->name); 54edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 5568eef3b4SJoe Korty } 567170be5fSNeil Horman } 5768eef3b4SJoe Korty #endif /* CONFIG_PROC_FS */ 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds int register_blkdev(unsigned int major, const char *name) 601da177e4SLinus Torvalds { 611da177e4SLinus Torvalds struct blk_major_name **n, *p; 621da177e4SLinus Torvalds int index, ret = 0; 631da177e4SLinus Torvalds 64edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /* temporary */ 671da177e4SLinus Torvalds if (major == 0) { 681da177e4SLinus Torvalds for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) { 691da177e4SLinus Torvalds if (major_names[index] == NULL) 701da177e4SLinus Torvalds break; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds if (index == 0) { 741da177e4SLinus Torvalds printk("register_blkdev: failed to get major for %s\n", 751da177e4SLinus Torvalds name); 761da177e4SLinus Torvalds ret = -EBUSY; 771da177e4SLinus Torvalds goto out; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds major = index; 801da177e4SLinus Torvalds ret = major; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); 841da177e4SLinus Torvalds if (p == NULL) { 851da177e4SLinus Torvalds ret = -ENOMEM; 861da177e4SLinus Torvalds goto out; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds p->major = major; 901da177e4SLinus Torvalds strlcpy(p->name, name, sizeof(p->name)); 911da177e4SLinus Torvalds p->next = NULL; 921da177e4SLinus Torvalds index = major_to_index(major); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds for (n = &major_names[index]; *n; n = &(*n)->next) { 951da177e4SLinus Torvalds if ((*n)->major == major) 961da177e4SLinus Torvalds break; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds if (!*n) 991da177e4SLinus Torvalds *n = p; 1001da177e4SLinus Torvalds else 1011da177e4SLinus Torvalds ret = -EBUSY; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds if (ret < 0) { 1041da177e4SLinus Torvalds printk("register_blkdev: cannot get major %d for %s\n", 1051da177e4SLinus Torvalds major, name); 1061da177e4SLinus Torvalds kfree(p); 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds out: 109edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 1101da177e4SLinus Torvalds return ret; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds EXPORT_SYMBOL(register_blkdev); 1141da177e4SLinus Torvalds 115f4480240SAkinobu Mita void unregister_blkdev(unsigned int major, const char *name) 1161da177e4SLinus Torvalds { 1171da177e4SLinus Torvalds struct blk_major_name **n; 1181da177e4SLinus Torvalds struct blk_major_name *p = NULL; 1191da177e4SLinus Torvalds int index = major_to_index(major); 1201da177e4SLinus Torvalds 121edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 1221da177e4SLinus Torvalds for (n = &major_names[index]; *n; n = &(*n)->next) 1231da177e4SLinus Torvalds if ((*n)->major == major) 1241da177e4SLinus Torvalds break; 125294462a5SAkinobu Mita if (!*n || strcmp((*n)->name, name)) { 126294462a5SAkinobu Mita WARN_ON(1); 127294462a5SAkinobu Mita } else { 1281da177e4SLinus Torvalds p = *n; 1291da177e4SLinus Torvalds *n = p->next; 1301da177e4SLinus Torvalds } 131edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 1321da177e4SLinus Torvalds kfree(p); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_blkdev); 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds static struct kobj_map *bdev_map; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* 1401da177e4SLinus Torvalds * Register device numbers dev..(dev+range-1) 1411da177e4SLinus Torvalds * range must be nonzero 1421da177e4SLinus Torvalds * The hash chain is sorted on range, so that subranges can override. 1431da177e4SLinus Torvalds */ 144edfaa7c3SKay Sievers void blk_register_region(dev_t devt, unsigned long range, struct module *module, 1451da177e4SLinus Torvalds struct kobject *(*probe)(dev_t, int *, void *), 1461da177e4SLinus Torvalds int (*lock)(dev_t, void *), void *data) 1471da177e4SLinus Torvalds { 148edfaa7c3SKay Sievers kobj_map(bdev_map, devt, range, module, probe, lock, data); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds EXPORT_SYMBOL(blk_register_region); 1521da177e4SLinus Torvalds 153edfaa7c3SKay Sievers void blk_unregister_region(dev_t devt, unsigned long range) 1541da177e4SLinus Torvalds { 155edfaa7c3SKay Sievers kobj_unmap(bdev_map, devt, range); 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds EXPORT_SYMBOL(blk_unregister_region); 1591da177e4SLinus Torvalds 160*cf771cb5STejun Heo static struct kobject *exact_match(dev_t devt, int *partno, void *data) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct gendisk *p = data; 163edfaa7c3SKay Sievers 164edfaa7c3SKay Sievers return &p->dev.kobj; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 167edfaa7c3SKay Sievers static int exact_lock(dev_t devt, void *data) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds struct gendisk *p = data; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds if (!get_disk(p)) 1721da177e4SLinus Torvalds return -1; 1731da177e4SLinus Torvalds return 0; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds /** 1771da177e4SLinus Torvalds * add_disk - add partitioning information to kernel list 1781da177e4SLinus Torvalds * @disk: per-device partitioning information 1791da177e4SLinus Torvalds * 1801da177e4SLinus Torvalds * This function registers the partitioning information in @disk 1811da177e4SLinus Torvalds * with the kernel. 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds void add_disk(struct gendisk *disk) 1841da177e4SLinus Torvalds { 185cf0ca9feSPeter Zijlstra struct backing_dev_info *bdi; 1866ffeea77SGreg Kroah-Hartman int retval; 187cf0ca9feSPeter Zijlstra 1881da177e4SLinus Torvalds disk->flags |= GENHD_FL_UP; 1891da177e4SLinus Torvalds blk_register_region(MKDEV(disk->major, disk->first_minor), 1901da177e4SLinus Torvalds disk->minors, NULL, exact_match, exact_lock, disk); 1911da177e4SLinus Torvalds register_disk(disk); 1921da177e4SLinus Torvalds blk_register_queue(disk); 193cf0ca9feSPeter Zijlstra 194cf0ca9feSPeter Zijlstra bdi = &disk->queue->backing_dev_info; 195cf0ca9feSPeter Zijlstra bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); 1966ffeea77SGreg Kroah-Hartman retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); 1976ffeea77SGreg Kroah-Hartman WARN_ON(retval); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds EXPORT_SYMBOL(add_disk); 2011da177e4SLinus Torvalds EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds void unlink_gendisk(struct gendisk *disk) 2041da177e4SLinus Torvalds { 205cf0ca9feSPeter Zijlstra sysfs_remove_link(&disk->dev.kobj, "bdi"); 206cf0ca9feSPeter Zijlstra bdi_unregister(&disk->queue->backing_dev_info); 2071da177e4SLinus Torvalds blk_unregister_queue(disk); 2081da177e4SLinus Torvalds blk_unregister_region(MKDEV(disk->major, disk->first_minor), 2091da177e4SLinus Torvalds disk->minors); 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /** 2131da177e4SLinus Torvalds * get_gendisk - get partitioning information for a given device 214710027a4SRandy Dunlap * @devt: device to get partitioning information for 215710027a4SRandy Dunlap * @part: returned partition index 2161da177e4SLinus Torvalds * 2171da177e4SLinus Torvalds * This function gets the structure containing partitioning 218710027a4SRandy Dunlap * information for the given device @devt. 2191da177e4SLinus Torvalds */ 220*cf771cb5STejun Heo struct gendisk *get_gendisk(dev_t devt, int *partno) 2211da177e4SLinus Torvalds { 222*cf771cb5STejun Heo struct kobject *kobj = kobj_lookup(bdev_map, devt, partno); 223edfaa7c3SKay Sievers struct device *dev = kobj_to_dev(kobj); 224edfaa7c3SKay Sievers 225edfaa7c3SKay Sievers return kobj ? dev_to_disk(dev) : NULL; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 228dd2a345fSDave Gilbert /* 2295c6f35c5SGreg Kroah-Hartman * print a full list of all partitions - intended for places where the root 2305c6f35c5SGreg Kroah-Hartman * filesystem can't be mounted and thus to give the victim some idea of what 2315c6f35c5SGreg Kroah-Hartman * went wrong 2325c6f35c5SGreg Kroah-Hartman */ 2335c6f35c5SGreg Kroah-Hartman void __init printk_all_partitions(void) 2345c6f35c5SGreg Kroah-Hartman { 235def4e38dSTejun Heo struct class_dev_iter iter; 236def4e38dSTejun Heo struct device *dev; 237def4e38dSTejun Heo 238def4e38dSTejun Heo class_dev_iter_init(&iter, &block_class, NULL, &disk_type); 239def4e38dSTejun Heo while ((dev = class_dev_iter_next(&iter))) { 240def4e38dSTejun Heo struct gendisk *disk = dev_to_disk(dev); 241def4e38dSTejun Heo char buf[BDEVNAME_SIZE]; 242def4e38dSTejun Heo int n; 243def4e38dSTejun Heo 244def4e38dSTejun Heo /* 245def4e38dSTejun Heo * Don't show empty devices or things that have been 246def4e38dSTejun Heo * surpressed 247def4e38dSTejun Heo */ 248def4e38dSTejun Heo if (get_capacity(disk) == 0 || 249def4e38dSTejun Heo (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) 250def4e38dSTejun Heo continue; 251def4e38dSTejun Heo 252def4e38dSTejun Heo /* 253def4e38dSTejun Heo * Note, unlike /proc/partitions, I am showing the 254def4e38dSTejun Heo * numbers in hex - the same format as the root= 255def4e38dSTejun Heo * option takes. 256def4e38dSTejun Heo */ 257def4e38dSTejun Heo printk("%02x%02x %10llu %s", 258def4e38dSTejun Heo disk->major, disk->first_minor, 259def4e38dSTejun Heo (unsigned long long)get_capacity(disk) >> 1, 260def4e38dSTejun Heo disk_name(disk, 0, buf)); 261def4e38dSTejun Heo if (disk->driverfs_dev != NULL && 262def4e38dSTejun Heo disk->driverfs_dev->driver != NULL) 263def4e38dSTejun Heo printk(" driver: %s\n", 264def4e38dSTejun Heo disk->driverfs_dev->driver->name); 265def4e38dSTejun Heo else 266def4e38dSTejun Heo printk(" (driver?)\n"); 267def4e38dSTejun Heo 268def4e38dSTejun Heo /* now show the partitions */ 269def4e38dSTejun Heo for (n = 0; n < disk->minors - 1; ++n) { 270def4e38dSTejun Heo if (disk->part[n] == NULL) 271def4e38dSTejun Heo continue; 272def4e38dSTejun Heo if (disk->part[n]->nr_sects == 0) 273def4e38dSTejun Heo continue; 274def4e38dSTejun Heo printk(" %02x%02x %10llu %s\n", 275def4e38dSTejun Heo disk->major, n + 1 + disk->first_minor, 276def4e38dSTejun Heo (unsigned long long)disk->part[n]->nr_sects >> 1, 277def4e38dSTejun Heo disk_name(disk, n + 1, buf)); 278def4e38dSTejun Heo } 279def4e38dSTejun Heo } 280def4e38dSTejun Heo class_dev_iter_exit(&iter); 281dd2a345fSDave Gilbert } 282dd2a345fSDave Gilbert 2831da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 2841da177e4SLinus Torvalds /* iterator */ 285def4e38dSTejun Heo static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) 28668c4d4a7SGreg Kroah-Hartman { 287def4e38dSTejun Heo loff_t skip = *pos; 288def4e38dSTejun Heo struct class_dev_iter *iter; 289def4e38dSTejun Heo struct device *dev; 29068c4d4a7SGreg Kroah-Hartman 291def4e38dSTejun Heo iter = kmalloc(GFP_KERNEL, sizeof(*iter)); 292def4e38dSTejun Heo if (!iter) 293def4e38dSTejun Heo return ERR_PTR(-ENOMEM); 294def4e38dSTejun Heo 295def4e38dSTejun Heo seqf->private = iter; 296def4e38dSTejun Heo class_dev_iter_init(iter, &block_class, NULL, &disk_type); 297def4e38dSTejun Heo do { 298def4e38dSTejun Heo dev = class_dev_iter_next(iter); 299def4e38dSTejun Heo if (!dev) 300def4e38dSTejun Heo return NULL; 301def4e38dSTejun Heo } while (skip--); 302def4e38dSTejun Heo 303def4e38dSTejun Heo return dev_to_disk(dev); 30468c4d4a7SGreg Kroah-Hartman } 30568c4d4a7SGreg Kroah-Hartman 306def4e38dSTejun Heo static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos) 3071da177e4SLinus Torvalds { 308edfaa7c3SKay Sievers struct device *dev; 30966c64afeSGreg Kroah-Hartman 310def4e38dSTejun Heo (*pos)++; 311def4e38dSTejun Heo dev = class_dev_iter_next(seqf->private); 3122ac3cee5STejun Heo if (dev) 313edfaa7c3SKay Sievers return dev_to_disk(dev); 3142ac3cee5STejun Heo 3151da177e4SLinus Torvalds return NULL; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318def4e38dSTejun Heo static void disk_seqf_stop(struct seq_file *seqf, void *v) 31927f30251SGreg Kroah-Hartman { 320def4e38dSTejun Heo struct class_dev_iter *iter = seqf->private; 321def4e38dSTejun Heo 322def4e38dSTejun Heo /* stop is called even after start failed :-( */ 323def4e38dSTejun Heo if (iter) { 324def4e38dSTejun Heo class_dev_iter_exit(iter); 325def4e38dSTejun Heo kfree(iter); 326def4e38dSTejun Heo } 32727f30251SGreg Kroah-Hartman } 32827f30251SGreg Kroah-Hartman 329def4e38dSTejun Heo static void *show_partition_start(struct seq_file *seqf, loff_t *pos) 3301da177e4SLinus Torvalds { 331def4e38dSTejun Heo static void *p; 3321da177e4SLinus Torvalds 333def4e38dSTejun Heo p = disk_seqf_start(seqf, pos); 334def4e38dSTejun Heo if (!IS_ERR(p) && p) 335def4e38dSTejun Heo seq_puts(seqf, "major minor #blocks name\n\n"); 336def4e38dSTejun Heo return p; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 339*cf771cb5STejun Heo static int show_partition(struct seq_file *seqf, void *v) 3401da177e4SLinus Torvalds { 3411da177e4SLinus Torvalds struct gendisk *sgp = v; 3421da177e4SLinus Torvalds int n; 3431da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* Don't show non-partitionable removeable devices or empty devices */ 3461da177e4SLinus Torvalds if (!get_capacity(sgp) || 3471da177e4SLinus Torvalds (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) 3481da177e4SLinus Torvalds return 0; 3491da177e4SLinus Torvalds if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) 3501da177e4SLinus Torvalds return 0; 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds /* show the full disk and all non-0 size partitions of it */ 353*cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %10llu %s\n", 3541da177e4SLinus Torvalds sgp->major, sgp->first_minor, 3551da177e4SLinus Torvalds (unsigned long long)get_capacity(sgp) >> 1, 3561da177e4SLinus Torvalds disk_name(sgp, 0, buf)); 3571da177e4SLinus Torvalds for (n = 0; n < sgp->minors - 1; n++) { 3581da177e4SLinus Torvalds if (!sgp->part[n]) 3591da177e4SLinus Torvalds continue; 3601da177e4SLinus Torvalds if (sgp->part[n]->nr_sects == 0) 3611da177e4SLinus Torvalds continue; 362*cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %10llu %s\n", 3631da177e4SLinus Torvalds sgp->major, n + 1 + sgp->first_minor, 3641da177e4SLinus Torvalds (unsigned long long)sgp->part[n]->nr_sects >> 1 , 3651da177e4SLinus Torvalds disk_name(sgp, n + 1, buf)); 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds return 0; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 37112f32bb3SJan Engelhardt const struct seq_operations partitions_op = { 372def4e38dSTejun Heo .start = show_partition_start, 373def4e38dSTejun Heo .next = disk_seqf_next, 374def4e38dSTejun Heo .stop = disk_seqf_stop, 3751da177e4SLinus Torvalds .show = show_partition 3761da177e4SLinus Torvalds }; 3771da177e4SLinus Torvalds #endif 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds 380*cf771cb5STejun Heo static struct kobject *base_probe(dev_t devt, int *partno, void *data) 3811da177e4SLinus Torvalds { 382edfaa7c3SKay Sievers if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 3831da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */ 384edfaa7c3SKay Sievers request_module("block-major-%d", MAJOR(devt)); 3851da177e4SLinus Torvalds return NULL; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds static int __init genhd_device_init(void) 3891da177e4SLinus Torvalds { 390e105b8bfSDan Williams int error; 391e105b8bfSDan Williams 392e105b8bfSDan Williams block_class.dev_kobj = sysfs_dev_block_kobj; 393e105b8bfSDan Williams error = class_register(&block_class); 394ee27a558SRoland McGrath if (unlikely(error)) 395ee27a558SRoland McGrath return error; 396edfaa7c3SKay Sievers bdev_map = kobj_map_init(base_probe, &block_class_lock); 3971da177e4SLinus Torvalds blk_dev_init(); 398edfaa7c3SKay Sievers 399edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 400edfaa7c3SKay Sievers /* create top-level block dir */ 401edfaa7c3SKay Sievers block_depr = kobject_create_and_add("block", NULL); 402edfaa7c3SKay Sievers #endif 403830d3cfbSGreg Kroah-Hartman return 0; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds subsys_initcall(genhd_device_init); 4071da177e4SLinus Torvalds 408edfaa7c3SKay Sievers static ssize_t disk_range_show(struct device *dev, 409edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4101da177e4SLinus Torvalds { 411edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4121da177e4SLinus Torvalds 413edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->minors); 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 416edfaa7c3SKay Sievers static ssize_t disk_removable_show(struct device *dev, 417edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 418a7fd6706SKay Sievers { 419edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 420a7fd6706SKay Sievers 421edfaa7c3SKay Sievers return sprintf(buf, "%d\n", 4221da177e4SLinus Torvalds (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 423edfaa7c3SKay Sievers } 4241da177e4SLinus Torvalds 4251c9ce527SKay Sievers static ssize_t disk_ro_show(struct device *dev, 4261c9ce527SKay Sievers struct device_attribute *attr, char *buf) 4271c9ce527SKay Sievers { 4281c9ce527SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4291c9ce527SKay Sievers 4301c9ce527SKay Sievers return sprintf(buf, "%d\n", disk->policy ? 1 : 0); 4311c9ce527SKay Sievers } 4321c9ce527SKay Sievers 433edfaa7c3SKay Sievers static ssize_t disk_size_show(struct device *dev, 434edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4351da177e4SLinus Torvalds { 436edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 437edfaa7c3SKay Sievers 438edfaa7c3SKay Sievers return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); 4391da177e4SLinus Torvalds } 440edfaa7c3SKay Sievers 441edfaa7c3SKay Sievers static ssize_t disk_capability_show(struct device *dev, 442edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 44386ce18d7SKristen Carlson Accardi { 444edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 445edfaa7c3SKay Sievers 446edfaa7c3SKay Sievers return sprintf(buf, "%x\n", disk->flags); 44786ce18d7SKristen Carlson Accardi } 448edfaa7c3SKay Sievers 449edfaa7c3SKay Sievers static ssize_t disk_stat_show(struct device *dev, 450edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4511da177e4SLinus Torvalds { 452edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 453edfaa7c3SKay Sievers 4541da177e4SLinus Torvalds preempt_disable(); 4551da177e4SLinus Torvalds disk_round_stats(disk); 4561da177e4SLinus Torvalds preempt_enable(); 457edfaa7c3SKay Sievers return sprintf(buf, 458837c7878SBen Woodard "%8lu %8lu %8llu %8u " 459837c7878SBen Woodard "%8lu %8lu %8llu %8u " 4601da177e4SLinus Torvalds "%8u %8u %8u" 4611da177e4SLinus Torvalds "\n", 46247a00410SJens Axboe disk_stat_read(disk, ios[READ]), 46347a00410SJens Axboe disk_stat_read(disk, merges[READ]), 46447a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[READ]), 46547a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), 46647a00410SJens Axboe disk_stat_read(disk, ios[WRITE]), 46747a00410SJens Axboe disk_stat_read(disk, merges[WRITE]), 46847a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[WRITE]), 46947a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), 4701da177e4SLinus Torvalds disk->in_flight, 4711da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, io_ticks)), 4721da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds 475c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 476edfaa7c3SKay Sievers static ssize_t disk_fail_show(struct device *dev, 477edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 478edfaa7c3SKay Sievers { 479edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 480c17bb495SAkinobu Mita 481edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); 482edfaa7c3SKay Sievers } 483edfaa7c3SKay Sievers 484edfaa7c3SKay Sievers static ssize_t disk_fail_store(struct device *dev, 485edfaa7c3SKay Sievers struct device_attribute *attr, 486c17bb495SAkinobu Mita const char *buf, size_t count) 487c17bb495SAkinobu Mita { 488edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 489c17bb495SAkinobu Mita int i; 490c17bb495SAkinobu Mita 491c17bb495SAkinobu Mita if (count > 0 && sscanf(buf, "%d", &i) > 0) { 492c17bb495SAkinobu Mita if (i == 0) 493c17bb495SAkinobu Mita disk->flags &= ~GENHD_FL_FAIL; 494c17bb495SAkinobu Mita else 495c17bb495SAkinobu Mita disk->flags |= GENHD_FL_FAIL; 496c17bb495SAkinobu Mita } 497c17bb495SAkinobu Mita 498c17bb495SAkinobu Mita return count; 499c17bb495SAkinobu Mita } 500c17bb495SAkinobu Mita 501c17bb495SAkinobu Mita #endif 502c17bb495SAkinobu Mita 503edfaa7c3SKay Sievers static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 504edfaa7c3SKay Sievers static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 5051c9ce527SKay Sievers static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 506edfaa7c3SKay Sievers static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 507edfaa7c3SKay Sievers static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 508edfaa7c3SKay Sievers static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 509c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 510edfaa7c3SKay Sievers static struct device_attribute dev_attr_fail = 511edfaa7c3SKay Sievers __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); 512c17bb495SAkinobu Mita #endif 513edfaa7c3SKay Sievers 514edfaa7c3SKay Sievers static struct attribute *disk_attrs[] = { 515edfaa7c3SKay Sievers &dev_attr_range.attr, 516edfaa7c3SKay Sievers &dev_attr_removable.attr, 5171c9ce527SKay Sievers &dev_attr_ro.attr, 518edfaa7c3SKay Sievers &dev_attr_size.attr, 519edfaa7c3SKay Sievers &dev_attr_capability.attr, 520edfaa7c3SKay Sievers &dev_attr_stat.attr, 521edfaa7c3SKay Sievers #ifdef CONFIG_FAIL_MAKE_REQUEST 522edfaa7c3SKay Sievers &dev_attr_fail.attr, 523edfaa7c3SKay Sievers #endif 524edfaa7c3SKay Sievers NULL 5251da177e4SLinus Torvalds }; 5261da177e4SLinus Torvalds 527edfaa7c3SKay Sievers static struct attribute_group disk_attr_group = { 528edfaa7c3SKay Sievers .attrs = disk_attrs, 529edfaa7c3SKay Sievers }; 530edfaa7c3SKay Sievers 531edfaa7c3SKay Sievers static struct attribute_group *disk_attr_groups[] = { 532edfaa7c3SKay Sievers &disk_attr_group, 533edfaa7c3SKay Sievers NULL 534edfaa7c3SKay Sievers }; 535edfaa7c3SKay Sievers 536edfaa7c3SKay Sievers static void disk_release(struct device *dev) 5371da177e4SLinus Torvalds { 538edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 539edfaa7c3SKay Sievers 5401da177e4SLinus Torvalds kfree(disk->random); 5411da177e4SLinus Torvalds kfree(disk->part); 5421da177e4SLinus Torvalds free_disk_stats(disk); 5431da177e4SLinus Torvalds kfree(disk); 5441da177e4SLinus Torvalds } 545edfaa7c3SKay Sievers struct class block_class = { 546edfaa7c3SKay Sievers .name = "block", 5471da177e4SLinus Torvalds }; 5481da177e4SLinus Torvalds 5491826eadfSAdrian Bunk static struct device_type disk_type = { 550edfaa7c3SKay Sievers .name = "disk", 551edfaa7c3SKay Sievers .groups = disk_attr_groups, 552edfaa7c3SKay Sievers .release = disk_release, 5531da177e4SLinus Torvalds }; 5541da177e4SLinus Torvalds 555a6e2ba88SRandy Dunlap #ifdef CONFIG_PROC_FS 556*cf771cb5STejun Heo /* 557*cf771cb5STejun Heo * aggregate disk stat collector. Uses the same stats that the sysfs 558*cf771cb5STejun Heo * entries do, above, but makes them available through one seq_file. 559*cf771cb5STejun Heo * 560*cf771cb5STejun Heo * The output looks suspiciously like /proc/partitions with a bunch of 561*cf771cb5STejun Heo * extra fields. 562*cf771cb5STejun Heo */ 563*cf771cb5STejun Heo static int diskstats_show(struct seq_file *seqf, void *v) 5641da177e4SLinus Torvalds { 5651da177e4SLinus Torvalds struct gendisk *gp = v; 5661da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 567310a2c10STejun Heo int n; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* 570edfaa7c3SKay Sievers if (&gp->dev.kobj.entry == block_class.devices.next) 571*cf771cb5STejun Heo seq_puts(seqf, "major minor name" 5721da177e4SLinus Torvalds " rio rmerge rsect ruse wio wmerge " 5731da177e4SLinus Torvalds "wsect wuse running use aveq" 5741da177e4SLinus Torvalds "\n\n"); 5751da177e4SLinus Torvalds */ 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds preempt_disable(); 5781da177e4SLinus Torvalds disk_round_stats(gp); 5791da177e4SLinus Torvalds preempt_enable(); 580*cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 581310a2c10STejun Heo gp->major, gp->first_minor, disk_name(gp, 0, buf), 582a362357bSJens Axboe disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), 583a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[0]), 584a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[0])), 585a362357bSJens Axboe disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), 586a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[1]), 587a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[1])), 5881da177e4SLinus Torvalds gp->in_flight, 5891da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, io_ticks)), 5901da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* now show all non-0 size partitions of it */ 5931da177e4SLinus Torvalds for (n = 0; n < gp->minors - 1; n++) { 5941da177e4SLinus Torvalds struct hd_struct *hd = gp->part[n]; 5951da177e4SLinus Torvalds 59628f39d55SJerome Marchand if (!hd || !hd->nr_sects) 59728f39d55SJerome Marchand continue; 59828f39d55SJerome Marchand 59928f39d55SJerome Marchand preempt_disable(); 60028f39d55SJerome Marchand part_round_stats(hd); 60128f39d55SJerome Marchand preempt_enable(); 602*cf771cb5STejun Heo seq_printf(seqf, "%4d %4d %s %lu %lu %llu " 60328f39d55SJerome Marchand "%u %lu %lu %llu %u %u %u %u\n", 6041da177e4SLinus Torvalds gp->major, n + gp->first_minor + 1, 6051da177e4SLinus Torvalds disk_name(gp, n + 1, buf), 60628f39d55SJerome Marchand part_stat_read(hd, ios[0]), 60728f39d55SJerome Marchand part_stat_read(hd, merges[0]), 60828f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[0]), 60928f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[0])), 61028f39d55SJerome Marchand part_stat_read(hd, ios[1]), 61128f39d55SJerome Marchand part_stat_read(hd, merges[1]), 61228f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[1]), 61328f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[1])), 61428f39d55SJerome Marchand hd->in_flight, 61528f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, io_ticks)), 61628f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, time_in_queue)) 61728f39d55SJerome Marchand ); 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds return 0; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 62312f32bb3SJan Engelhardt const struct seq_operations diskstats_op = { 624def4e38dSTejun Heo .start = disk_seqf_start, 625def4e38dSTejun Heo .next = disk_seqf_next, 626def4e38dSTejun Heo .stop = disk_seqf_stop, 6271da177e4SLinus Torvalds .show = diskstats_show 6281da177e4SLinus Torvalds }; 629a6e2ba88SRandy Dunlap #endif /* CONFIG_PROC_FS */ 6301da177e4SLinus Torvalds 6318ce7ad7bSKristen Carlson Accardi static void media_change_notify_thread(struct work_struct *work) 6328ce7ad7bSKristen Carlson Accardi { 6338ce7ad7bSKristen Carlson Accardi struct gendisk *gd = container_of(work, struct gendisk, async_notify); 6348ce7ad7bSKristen Carlson Accardi char event[] = "MEDIA_CHANGE=1"; 6358ce7ad7bSKristen Carlson Accardi char *envp[] = { event, NULL }; 6368ce7ad7bSKristen Carlson Accardi 6378ce7ad7bSKristen Carlson Accardi /* 6388ce7ad7bSKristen Carlson Accardi * set enviroment vars to indicate which event this is for 6398ce7ad7bSKristen Carlson Accardi * so that user space will know to go check the media status. 6408ce7ad7bSKristen Carlson Accardi */ 641edfaa7c3SKay Sievers kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); 6428ce7ad7bSKristen Carlson Accardi put_device(gd->driverfs_dev); 6438ce7ad7bSKristen Carlson Accardi } 6448ce7ad7bSKristen Carlson Accardi 6451826eadfSAdrian Bunk #if 0 6468ce7ad7bSKristen Carlson Accardi void genhd_media_change_notify(struct gendisk *disk) 6478ce7ad7bSKristen Carlson Accardi { 6488ce7ad7bSKristen Carlson Accardi get_device(disk->driverfs_dev); 6498ce7ad7bSKristen Carlson Accardi schedule_work(&disk->async_notify); 6508ce7ad7bSKristen Carlson Accardi } 6518ce7ad7bSKristen Carlson Accardi EXPORT_SYMBOL_GPL(genhd_media_change_notify); 6521826eadfSAdrian Bunk #endif /* 0 */ 6538ce7ad7bSKristen Carlson Accardi 654*cf771cb5STejun Heo dev_t blk_lookup_devt(const char *name, int partno) 655edfaa7c3SKay Sievers { 656edfaa7c3SKay Sievers dev_t devt = MKDEV(0, 0); 657def4e38dSTejun Heo struct class_dev_iter iter; 658def4e38dSTejun Heo struct device *dev; 659edfaa7c3SKay Sievers 660def4e38dSTejun Heo class_dev_iter_init(&iter, &block_class, NULL, &disk_type); 661def4e38dSTejun Heo while ((dev = class_dev_iter_next(&iter))) { 662def4e38dSTejun Heo struct gendisk *disk = dev_to_disk(dev); 663def4e38dSTejun Heo 664*cf771cb5STejun Heo if (!strcmp(dev->bus_id, name) && partno < disk->minors) { 66530f2f0ebSKay Sievers devt = MKDEV(MAJOR(dev->devt), 666*cf771cb5STejun Heo MINOR(dev->devt) + partno); 667def4e38dSTejun Heo break; 6685c0ef6d0SKay Sievers } 669def4e38dSTejun Heo } 670def4e38dSTejun Heo class_dev_iter_exit(&iter); 671edfaa7c3SKay Sievers return devt; 672edfaa7c3SKay Sievers } 673edfaa7c3SKay Sievers EXPORT_SYMBOL(blk_lookup_devt); 674edfaa7c3SKay Sievers 6751da177e4SLinus Torvalds struct gendisk *alloc_disk(int minors) 6761da177e4SLinus Torvalds { 6771946089aSChristoph Lameter return alloc_disk_node(minors, -1); 6781946089aSChristoph Lameter } 6791946089aSChristoph Lameter 6801946089aSChristoph Lameter struct gendisk *alloc_disk_node(int minors, int node_id) 6811946089aSChristoph Lameter { 6821946089aSChristoph Lameter struct gendisk *disk; 6831946089aSChristoph Lameter 68494f6030cSChristoph Lameter disk = kmalloc_node(sizeof(struct gendisk), 68594f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 6861da177e4SLinus Torvalds if (disk) { 6871da177e4SLinus Torvalds if (!init_disk_stats(disk)) { 6881da177e4SLinus Torvalds kfree(disk); 6891da177e4SLinus Torvalds return NULL; 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds if (minors > 1) { 6921da177e4SLinus Torvalds int size = (minors - 1) * sizeof(struct hd_struct *); 69394f6030cSChristoph Lameter disk->part = kmalloc_node(size, 69494f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 6951da177e4SLinus Torvalds if (!disk->part) { 696c7674030SJerome Marchand free_disk_stats(disk); 6971da177e4SLinus Torvalds kfree(disk); 6981da177e4SLinus Torvalds return NULL; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds disk->minors = minors; 7021da177e4SLinus Torvalds rand_initialize_disk(disk); 703edfaa7c3SKay Sievers disk->dev.class = &block_class; 704edfaa7c3SKay Sievers disk->dev.type = &disk_type; 705edfaa7c3SKay Sievers device_initialize(&disk->dev); 7068ce7ad7bSKristen Carlson Accardi INIT_WORK(&disk->async_notify, 7078ce7ad7bSKristen Carlson Accardi media_change_notify_thread); 7081da177e4SLinus Torvalds } 7091da177e4SLinus Torvalds return disk; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_disk); 7131946089aSChristoph Lameter EXPORT_SYMBOL(alloc_disk_node); 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds struct kobject *get_disk(struct gendisk *disk) 7161da177e4SLinus Torvalds { 7171da177e4SLinus Torvalds struct module *owner; 7181da177e4SLinus Torvalds struct kobject *kobj; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds if (!disk->fops) 7211da177e4SLinus Torvalds return NULL; 7221da177e4SLinus Torvalds owner = disk->fops->owner; 7231da177e4SLinus Torvalds if (owner && !try_module_get(owner)) 7241da177e4SLinus Torvalds return NULL; 725edfaa7c3SKay Sievers kobj = kobject_get(&disk->dev.kobj); 7261da177e4SLinus Torvalds if (kobj == NULL) { 7271da177e4SLinus Torvalds module_put(owner); 7281da177e4SLinus Torvalds return NULL; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds return kobj; 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds EXPORT_SYMBOL(get_disk); 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds void put_disk(struct gendisk *disk) 7371da177e4SLinus Torvalds { 7381da177e4SLinus Torvalds if (disk) 739edfaa7c3SKay Sievers kobject_put(&disk->dev.kobj); 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds EXPORT_SYMBOL(put_disk); 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds void set_device_ro(struct block_device *bdev, int flag) 7451da177e4SLinus Torvalds { 7461da177e4SLinus Torvalds if (bdev->bd_contains != bdev) 7471da177e4SLinus Torvalds bdev->bd_part->policy = flag; 7481da177e4SLinus Torvalds else 7491da177e4SLinus Torvalds bdev->bd_disk->policy = flag; 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds EXPORT_SYMBOL(set_device_ro); 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds void set_disk_ro(struct gendisk *disk, int flag) 7551da177e4SLinus Torvalds { 7561da177e4SLinus Torvalds int i; 7571da177e4SLinus Torvalds disk->policy = flag; 7581da177e4SLinus Torvalds for (i = 0; i < disk->minors - 1; i++) 7591da177e4SLinus Torvalds if (disk->part[i]) disk->part[i]->policy = flag; 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds EXPORT_SYMBOL(set_disk_ro); 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds int bdev_read_only(struct block_device *bdev) 7651da177e4SLinus Torvalds { 7661da177e4SLinus Torvalds if (!bdev) 7671da177e4SLinus Torvalds return 0; 7681da177e4SLinus Torvalds else if (bdev->bd_contains != bdev) 7691da177e4SLinus Torvalds return bdev->bd_part->policy; 7701da177e4SLinus Torvalds else 7711da177e4SLinus Torvalds return bdev->bd_disk->policy; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds EXPORT_SYMBOL(bdev_read_only); 7751da177e4SLinus Torvalds 776*cf771cb5STejun Heo int invalidate_partition(struct gendisk *disk, int partno) 7771da177e4SLinus Torvalds { 7781da177e4SLinus Torvalds int res = 0; 779*cf771cb5STejun Heo struct block_device *bdev = bdget_disk(disk, partno); 7801da177e4SLinus Torvalds if (bdev) { 7812ef41634SChristoph Hellwig fsync_bdev(bdev); 7822ef41634SChristoph Hellwig res = __invalidate_device(bdev); 7831da177e4SLinus Torvalds bdput(bdev); 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds return res; 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds EXPORT_SYMBOL(invalidate_partition); 789