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 4668eef3b4SJoe Korty void blkdev_show(struct seq_file *f, 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) 5368eef3b4SJoe Korty seq_printf(f, "%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 160edfaa7c3SKay Sievers static struct kobject *exact_match(dev_t devt, int *part, 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); 1930b07de85SAdel Gadllah blk_register_filter(disk); 194cf0ca9feSPeter Zijlstra 195cf0ca9feSPeter Zijlstra bdi = &disk->queue->backing_dev_info; 196cf0ca9feSPeter Zijlstra bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); 1976ffeea77SGreg Kroah-Hartman retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi"); 1986ffeea77SGreg Kroah-Hartman WARN_ON(retval); 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds EXPORT_SYMBOL(add_disk); 2021da177e4SLinus Torvalds EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds void unlink_gendisk(struct gendisk *disk) 2051da177e4SLinus Torvalds { 2060b07de85SAdel Gadllah blk_unregister_filter(disk); 207cf0ca9feSPeter Zijlstra sysfs_remove_link(&disk->dev.kobj, "bdi"); 208cf0ca9feSPeter Zijlstra bdi_unregister(&disk->queue->backing_dev_info); 2091da177e4SLinus Torvalds blk_unregister_queue(disk); 2101da177e4SLinus Torvalds blk_unregister_region(MKDEV(disk->major, disk->first_minor), 2111da177e4SLinus Torvalds disk->minors); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /** 2151da177e4SLinus Torvalds * get_gendisk - get partitioning information for a given device 2161da177e4SLinus Torvalds * @dev: device to get partitioning information for 2171da177e4SLinus Torvalds * 2181da177e4SLinus Torvalds * This function gets the structure containing partitioning 2191da177e4SLinus Torvalds * information for the given device @dev. 2201da177e4SLinus Torvalds */ 221edfaa7c3SKay Sievers struct gendisk *get_gendisk(dev_t devt, int *part) 2221da177e4SLinus Torvalds { 223edfaa7c3SKay Sievers struct kobject *kobj = kobj_lookup(bdev_map, devt, part); 224edfaa7c3SKay Sievers struct device *dev = kobj_to_dev(kobj); 225edfaa7c3SKay Sievers 226edfaa7c3SKay Sievers return kobj ? dev_to_disk(dev) : NULL; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 229dd2a345fSDave Gilbert /* 230*5c6f35c5SGreg Kroah-Hartman * print a partitions - intended for places where the root filesystem can't be 231*5c6f35c5SGreg Kroah-Hartman * mounted and thus to give the victim some idea of what went wrong 232dd2a345fSDave Gilbert */ 233*5c6f35c5SGreg Kroah-Hartman static int printk_partition(struct device *dev, void *data) 234dd2a345fSDave Gilbert { 235dd2a345fSDave Gilbert struct gendisk *sgp; 236dd2a345fSDave Gilbert char buf[BDEVNAME_SIZE]; 237edfaa7c3SKay Sievers int n; 238edfaa7c3SKay Sievers 239edfaa7c3SKay Sievers if (dev->type != &disk_type) 240*5c6f35c5SGreg Kroah-Hartman goto exit; 241*5c6f35c5SGreg Kroah-Hartman 242edfaa7c3SKay Sievers sgp = dev_to_disk(dev); 243dd2a345fSDave Gilbert /* 244dd2a345fSDave Gilbert * Don't show empty devices or things that have been surpressed 245dd2a345fSDave Gilbert */ 246dd2a345fSDave Gilbert if (get_capacity(sgp) == 0 || 247dd2a345fSDave Gilbert (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) 248*5c6f35c5SGreg Kroah-Hartman goto exit; 249dd2a345fSDave Gilbert 250dd2a345fSDave Gilbert /* 251dd2a345fSDave Gilbert * Note, unlike /proc/partitions, I am showing the numbers in 252dd2a345fSDave Gilbert * hex - the same format as the root= option takes. 253dd2a345fSDave Gilbert */ 254dd2a345fSDave Gilbert printk("%02x%02x %10llu %s", 255dd2a345fSDave Gilbert sgp->major, sgp->first_minor, 256dd2a345fSDave Gilbert (unsigned long long)get_capacity(sgp) >> 1, 257dd2a345fSDave Gilbert disk_name(sgp, 0, buf)); 258dd2a345fSDave Gilbert if (sgp->driverfs_dev != NULL && 259dd2a345fSDave Gilbert sgp->driverfs_dev->driver != NULL) 260dd2a345fSDave Gilbert printk(" driver: %s\n", 261dd2a345fSDave Gilbert sgp->driverfs_dev->driver->name); 262dd2a345fSDave Gilbert else 263dd2a345fSDave Gilbert printk(" (driver?)\n"); 264dd2a345fSDave Gilbert 265dd2a345fSDave Gilbert /* now show the partitions */ 266dd2a345fSDave Gilbert for (n = 0; n < sgp->minors - 1; ++n) { 267dd2a345fSDave Gilbert if (sgp->part[n] == NULL) 268*5c6f35c5SGreg Kroah-Hartman goto exit; 269dd2a345fSDave Gilbert if (sgp->part[n]->nr_sects == 0) 270*5c6f35c5SGreg Kroah-Hartman goto exit; 271dd2a345fSDave Gilbert printk(" %02x%02x %10llu %s\n", 272dd2a345fSDave Gilbert sgp->major, n + 1 + sgp->first_minor, 273dd2a345fSDave Gilbert (unsigned long long)sgp->part[n]->nr_sects >> 1, 274dd2a345fSDave Gilbert disk_name(sgp, n + 1, buf)); 275edfaa7c3SKay Sievers } 276*5c6f35c5SGreg Kroah-Hartman exit: 277*5c6f35c5SGreg Kroah-Hartman return 0; 278edfaa7c3SKay Sievers } 279dd2a345fSDave Gilbert 280*5c6f35c5SGreg Kroah-Hartman /* 281*5c6f35c5SGreg Kroah-Hartman * print a full list of all partitions - intended for places where the root 282*5c6f35c5SGreg Kroah-Hartman * filesystem can't be mounted and thus to give the victim some idea of what 283*5c6f35c5SGreg Kroah-Hartman * went wrong 284*5c6f35c5SGreg Kroah-Hartman */ 285*5c6f35c5SGreg Kroah-Hartman void __init printk_all_partitions(void) 286*5c6f35c5SGreg Kroah-Hartman { 287*5c6f35c5SGreg Kroah-Hartman mutex_lock(&block_class_lock); 288*5c6f35c5SGreg Kroah-Hartman class_for_each_device(&block_class, NULL, NULL, printk_partition); 289edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 290dd2a345fSDave Gilbert } 291dd2a345fSDave Gilbert 2921da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 2931da177e4SLinus Torvalds /* iterator */ 2941da177e4SLinus Torvalds static void *part_start(struct seq_file *part, loff_t *pos) 2951da177e4SLinus Torvalds { 296edfaa7c3SKay Sievers loff_t k = *pos; 297edfaa7c3SKay Sievers struct device *dev; 2981da177e4SLinus Torvalds 299edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 300edfaa7c3SKay Sievers list_for_each_entry(dev, &block_class.devices, node) { 301edfaa7c3SKay Sievers if (dev->type != &disk_type) 302edfaa7c3SKay Sievers continue; 303edfaa7c3SKay Sievers if (!k--) 304edfaa7c3SKay Sievers return dev_to_disk(dev); 305edfaa7c3SKay Sievers } 3061da177e4SLinus Torvalds return NULL; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds static void *part_next(struct seq_file *part, void *v, loff_t *pos) 3101da177e4SLinus Torvalds { 311edfaa7c3SKay Sievers struct gendisk *gp = v; 312edfaa7c3SKay Sievers struct device *dev; 3131da177e4SLinus Torvalds ++*pos; 314edfaa7c3SKay Sievers list_for_each_entry(dev, &gp->dev.node, node) { 315edfaa7c3SKay Sievers if (&dev->node == &block_class.devices) 316edfaa7c3SKay Sievers return NULL; 317edfaa7c3SKay Sievers if (dev->type == &disk_type) 318edfaa7c3SKay Sievers return dev_to_disk(dev); 319edfaa7c3SKay Sievers } 320edfaa7c3SKay Sievers return NULL; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static void part_stop(struct seq_file *part, void *v) 3241da177e4SLinus Torvalds { 325edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static int show_partition(struct seq_file *part, void *v) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds struct gendisk *sgp = v; 3311da177e4SLinus Torvalds int n; 3321da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 3331da177e4SLinus Torvalds 334edfaa7c3SKay Sievers if (&sgp->dev.node == block_class.devices.next) 3351da177e4SLinus Torvalds seq_puts(part, "major minor #blocks name\n\n"); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds /* Don't show non-partitionable removeable devices or empty devices */ 3381da177e4SLinus Torvalds if (!get_capacity(sgp) || 3391da177e4SLinus Torvalds (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) 3401da177e4SLinus Torvalds return 0; 3411da177e4SLinus Torvalds if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) 3421da177e4SLinus Torvalds return 0; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* show the full disk and all non-0 size partitions of it */ 3451da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3461da177e4SLinus Torvalds sgp->major, sgp->first_minor, 3471da177e4SLinus Torvalds (unsigned long long)get_capacity(sgp) >> 1, 3481da177e4SLinus Torvalds disk_name(sgp, 0, buf)); 3491da177e4SLinus Torvalds for (n = 0; n < sgp->minors - 1; n++) { 3501da177e4SLinus Torvalds if (!sgp->part[n]) 3511da177e4SLinus Torvalds continue; 3521da177e4SLinus Torvalds if (sgp->part[n]->nr_sects == 0) 3531da177e4SLinus Torvalds continue; 3541da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3551da177e4SLinus Torvalds sgp->major, n + 1 + sgp->first_minor, 3561da177e4SLinus Torvalds (unsigned long long)sgp->part[n]->nr_sects >> 1 , 3571da177e4SLinus Torvalds disk_name(sgp, n + 1, buf)); 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds return 0; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds 36312f32bb3SJan Engelhardt const struct seq_operations partitions_op = { 3641da177e4SLinus Torvalds .start = part_start, 3651da177e4SLinus Torvalds .next = part_next, 3661da177e4SLinus Torvalds .stop = part_stop, 3671da177e4SLinus Torvalds .show = show_partition 3681da177e4SLinus Torvalds }; 3691da177e4SLinus Torvalds #endif 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds 372edfaa7c3SKay Sievers static struct kobject *base_probe(dev_t devt, int *part, void *data) 3731da177e4SLinus Torvalds { 374edfaa7c3SKay Sievers if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 3751da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */ 376edfaa7c3SKay Sievers request_module("block-major-%d", MAJOR(devt)); 3771da177e4SLinus Torvalds return NULL; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds static int __init genhd_device_init(void) 3811da177e4SLinus Torvalds { 382e105b8bfSDan Williams int error; 383e105b8bfSDan Williams 384e105b8bfSDan Williams block_class.dev_kobj = sysfs_dev_block_kobj; 385e105b8bfSDan Williams error = class_register(&block_class); 386ee27a558SRoland McGrath if (unlikely(error)) 387ee27a558SRoland McGrath return error; 388edfaa7c3SKay Sievers bdev_map = kobj_map_init(base_probe, &block_class_lock); 3891da177e4SLinus Torvalds blk_dev_init(); 390edfaa7c3SKay Sievers 391edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 392edfaa7c3SKay Sievers /* create top-level block dir */ 393edfaa7c3SKay Sievers block_depr = kobject_create_and_add("block", NULL); 394edfaa7c3SKay Sievers #endif 395830d3cfbSGreg Kroah-Hartman return 0; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds subsys_initcall(genhd_device_init); 3991da177e4SLinus Torvalds 400edfaa7c3SKay Sievers static ssize_t disk_range_show(struct device *dev, 401edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4021da177e4SLinus Torvalds { 403edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4041da177e4SLinus Torvalds 405edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->minors); 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds 408edfaa7c3SKay Sievers static ssize_t disk_removable_show(struct device *dev, 409edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 410a7fd6706SKay Sievers { 411edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 412a7fd6706SKay Sievers 413edfaa7c3SKay Sievers return sprintf(buf, "%d\n", 4141da177e4SLinus Torvalds (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 415edfaa7c3SKay Sievers } 4161da177e4SLinus Torvalds 4171c9ce527SKay Sievers static ssize_t disk_ro_show(struct device *dev, 4181c9ce527SKay Sievers struct device_attribute *attr, char *buf) 4191c9ce527SKay Sievers { 4201c9ce527SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4211c9ce527SKay Sievers 4221c9ce527SKay Sievers return sprintf(buf, "%d\n", disk->policy ? 1 : 0); 4231c9ce527SKay Sievers } 4241c9ce527SKay Sievers 425edfaa7c3SKay Sievers static ssize_t disk_size_show(struct device *dev, 426edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4271da177e4SLinus Torvalds { 428edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 429edfaa7c3SKay Sievers 430edfaa7c3SKay Sievers return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); 4311da177e4SLinus Torvalds } 432edfaa7c3SKay Sievers 433edfaa7c3SKay Sievers static ssize_t disk_capability_show(struct device *dev, 434edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 43586ce18d7SKristen Carlson Accardi { 436edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 437edfaa7c3SKay Sievers 438edfaa7c3SKay Sievers return sprintf(buf, "%x\n", disk->flags); 43986ce18d7SKristen Carlson Accardi } 440edfaa7c3SKay Sievers 441edfaa7c3SKay Sievers static ssize_t disk_stat_show(struct device *dev, 442edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4431da177e4SLinus Torvalds { 444edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 445edfaa7c3SKay Sievers 4461da177e4SLinus Torvalds preempt_disable(); 4471da177e4SLinus Torvalds disk_round_stats(disk); 4481da177e4SLinus Torvalds preempt_enable(); 449edfaa7c3SKay Sievers return sprintf(buf, 450837c7878SBen Woodard "%8lu %8lu %8llu %8u " 451837c7878SBen Woodard "%8lu %8lu %8llu %8u " 4521da177e4SLinus Torvalds "%8u %8u %8u" 4531da177e4SLinus Torvalds "\n", 45447a00410SJens Axboe disk_stat_read(disk, ios[READ]), 45547a00410SJens Axboe disk_stat_read(disk, merges[READ]), 45647a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[READ]), 45747a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), 45847a00410SJens Axboe disk_stat_read(disk, ios[WRITE]), 45947a00410SJens Axboe disk_stat_read(disk, merges[WRITE]), 46047a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[WRITE]), 46147a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), 4621da177e4SLinus Torvalds disk->in_flight, 4631da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, io_ticks)), 4641da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 467c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 468edfaa7c3SKay Sievers static ssize_t disk_fail_show(struct device *dev, 469edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 470edfaa7c3SKay Sievers { 471edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 472c17bb495SAkinobu Mita 473edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); 474edfaa7c3SKay Sievers } 475edfaa7c3SKay Sievers 476edfaa7c3SKay Sievers static ssize_t disk_fail_store(struct device *dev, 477edfaa7c3SKay Sievers struct device_attribute *attr, 478c17bb495SAkinobu Mita const char *buf, size_t count) 479c17bb495SAkinobu Mita { 480edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 481c17bb495SAkinobu Mita int i; 482c17bb495SAkinobu Mita 483c17bb495SAkinobu Mita if (count > 0 && sscanf(buf, "%d", &i) > 0) { 484c17bb495SAkinobu Mita if (i == 0) 485c17bb495SAkinobu Mita disk->flags &= ~GENHD_FL_FAIL; 486c17bb495SAkinobu Mita else 487c17bb495SAkinobu Mita disk->flags |= GENHD_FL_FAIL; 488c17bb495SAkinobu Mita } 489c17bb495SAkinobu Mita 490c17bb495SAkinobu Mita return count; 491c17bb495SAkinobu Mita } 492c17bb495SAkinobu Mita 493c17bb495SAkinobu Mita #endif 494c17bb495SAkinobu Mita 495edfaa7c3SKay Sievers static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 496edfaa7c3SKay Sievers static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 4971c9ce527SKay Sievers static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 498edfaa7c3SKay Sievers static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 499edfaa7c3SKay Sievers static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 500edfaa7c3SKay Sievers static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 501c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 502edfaa7c3SKay Sievers static struct device_attribute dev_attr_fail = 503edfaa7c3SKay Sievers __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); 504c17bb495SAkinobu Mita #endif 505edfaa7c3SKay Sievers 506edfaa7c3SKay Sievers static struct attribute *disk_attrs[] = { 507edfaa7c3SKay Sievers &dev_attr_range.attr, 508edfaa7c3SKay Sievers &dev_attr_removable.attr, 5091c9ce527SKay Sievers &dev_attr_ro.attr, 510edfaa7c3SKay Sievers &dev_attr_size.attr, 511edfaa7c3SKay Sievers &dev_attr_capability.attr, 512edfaa7c3SKay Sievers &dev_attr_stat.attr, 513edfaa7c3SKay Sievers #ifdef CONFIG_FAIL_MAKE_REQUEST 514edfaa7c3SKay Sievers &dev_attr_fail.attr, 515edfaa7c3SKay Sievers #endif 516edfaa7c3SKay Sievers NULL 5171da177e4SLinus Torvalds }; 5181da177e4SLinus Torvalds 519edfaa7c3SKay Sievers static struct attribute_group disk_attr_group = { 520edfaa7c3SKay Sievers .attrs = disk_attrs, 521edfaa7c3SKay Sievers }; 522edfaa7c3SKay Sievers 523edfaa7c3SKay Sievers static struct attribute_group *disk_attr_groups[] = { 524edfaa7c3SKay Sievers &disk_attr_group, 525edfaa7c3SKay Sievers NULL 526edfaa7c3SKay Sievers }; 527edfaa7c3SKay Sievers 528edfaa7c3SKay Sievers static void disk_release(struct device *dev) 5291da177e4SLinus Torvalds { 530edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 531edfaa7c3SKay Sievers 5321da177e4SLinus Torvalds kfree(disk->random); 5331da177e4SLinus Torvalds kfree(disk->part); 5341da177e4SLinus Torvalds free_disk_stats(disk); 5351da177e4SLinus Torvalds kfree(disk); 5361da177e4SLinus Torvalds } 537edfaa7c3SKay Sievers struct class block_class = { 538edfaa7c3SKay Sievers .name = "block", 5391da177e4SLinus Torvalds }; 5401da177e4SLinus Torvalds 5411826eadfSAdrian Bunk static struct device_type disk_type = { 542edfaa7c3SKay Sievers .name = "disk", 543edfaa7c3SKay Sievers .groups = disk_attr_groups, 544edfaa7c3SKay Sievers .release = disk_release, 5451da177e4SLinus Torvalds }; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds /* 5481da177e4SLinus Torvalds * aggregate disk stat collector. Uses the same stats that the sysfs 5491da177e4SLinus Torvalds * entries do, above, but makes them available through one seq_file. 5501da177e4SLinus Torvalds * 5511da177e4SLinus Torvalds * The output looks suspiciously like /proc/partitions with a bunch of 5521da177e4SLinus Torvalds * extra fields. 5531da177e4SLinus Torvalds */ 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds static void *diskstats_start(struct seq_file *part, loff_t *pos) 5561da177e4SLinus Torvalds { 5571da177e4SLinus Torvalds loff_t k = *pos; 558edfaa7c3SKay Sievers struct device *dev; 5591da177e4SLinus Torvalds 560edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 561edfaa7c3SKay Sievers list_for_each_entry(dev, &block_class.devices, node) { 562edfaa7c3SKay Sievers if (dev->type != &disk_type) 563edfaa7c3SKay Sievers continue; 5641da177e4SLinus Torvalds if (!k--) 565edfaa7c3SKay Sievers return dev_to_disk(dev); 566edfaa7c3SKay Sievers } 5671da177e4SLinus Torvalds return NULL; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) 5711da177e4SLinus Torvalds { 572edfaa7c3SKay Sievers struct gendisk *gp = v; 573edfaa7c3SKay Sievers struct device *dev; 574edfaa7c3SKay Sievers 5751da177e4SLinus Torvalds ++*pos; 576edfaa7c3SKay Sievers list_for_each_entry(dev, &gp->dev.node, node) { 577edfaa7c3SKay Sievers if (&dev->node == &block_class.devices) 578edfaa7c3SKay Sievers return NULL; 579edfaa7c3SKay Sievers if (dev->type == &disk_type) 580edfaa7c3SKay Sievers return dev_to_disk(dev); 581edfaa7c3SKay Sievers } 582edfaa7c3SKay Sievers return NULL; 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds static void diskstats_stop(struct seq_file *part, void *v) 5861da177e4SLinus Torvalds { 587edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds static int diskstats_show(struct seq_file *s, void *v) 5911da177e4SLinus Torvalds { 5921da177e4SLinus Torvalds struct gendisk *gp = v; 5931da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 5941da177e4SLinus Torvalds int n = 0; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* 597edfaa7c3SKay Sievers if (&gp->dev.kobj.entry == block_class.devices.next) 5981da177e4SLinus Torvalds seq_puts(s, "major minor name" 5991da177e4SLinus Torvalds " rio rmerge rsect ruse wio wmerge " 6001da177e4SLinus Torvalds "wsect wuse running use aveq" 6011da177e4SLinus Torvalds "\n\n"); 6021da177e4SLinus Torvalds */ 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds preempt_disable(); 6051da177e4SLinus Torvalds disk_round_stats(gp); 6061da177e4SLinus Torvalds preempt_enable(); 607837c7878SBen Woodard seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 6081da177e4SLinus Torvalds gp->major, n + gp->first_minor, disk_name(gp, n, buf), 609a362357bSJens Axboe disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), 610a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[0]), 611a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[0])), 612a362357bSJens Axboe disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), 613a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[1]), 614a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[1])), 6151da177e4SLinus Torvalds gp->in_flight, 6161da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, io_ticks)), 6171da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* now show all non-0 size partitions of it */ 6201da177e4SLinus Torvalds for (n = 0; n < gp->minors - 1; n++) { 6211da177e4SLinus Torvalds struct hd_struct *hd = gp->part[n]; 6221da177e4SLinus Torvalds 62328f39d55SJerome Marchand if (!hd || !hd->nr_sects) 62428f39d55SJerome Marchand continue; 62528f39d55SJerome Marchand 62628f39d55SJerome Marchand preempt_disable(); 62728f39d55SJerome Marchand part_round_stats(hd); 62828f39d55SJerome Marchand preempt_enable(); 62928f39d55SJerome Marchand seq_printf(s, "%4d %4d %s %lu %lu %llu " 63028f39d55SJerome Marchand "%u %lu %lu %llu %u %u %u %u\n", 6311da177e4SLinus Torvalds gp->major, n + gp->first_minor + 1, 6321da177e4SLinus Torvalds disk_name(gp, n + 1, buf), 63328f39d55SJerome Marchand part_stat_read(hd, ios[0]), 63428f39d55SJerome Marchand part_stat_read(hd, merges[0]), 63528f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[0]), 63628f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[0])), 63728f39d55SJerome Marchand part_stat_read(hd, ios[1]), 63828f39d55SJerome Marchand part_stat_read(hd, merges[1]), 63928f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[1]), 64028f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[1])), 64128f39d55SJerome Marchand hd->in_flight, 64228f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, io_ticks)), 64328f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, time_in_queue)) 64428f39d55SJerome Marchand ); 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds return 0; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds 65012f32bb3SJan Engelhardt const struct seq_operations diskstats_op = { 6511da177e4SLinus Torvalds .start = diskstats_start, 6521da177e4SLinus Torvalds .next = diskstats_next, 6531da177e4SLinus Torvalds .stop = diskstats_stop, 6541da177e4SLinus Torvalds .show = diskstats_show 6551da177e4SLinus Torvalds }; 6561da177e4SLinus Torvalds 6578ce7ad7bSKristen Carlson Accardi static void media_change_notify_thread(struct work_struct *work) 6588ce7ad7bSKristen Carlson Accardi { 6598ce7ad7bSKristen Carlson Accardi struct gendisk *gd = container_of(work, struct gendisk, async_notify); 6608ce7ad7bSKristen Carlson Accardi char event[] = "MEDIA_CHANGE=1"; 6618ce7ad7bSKristen Carlson Accardi char *envp[] = { event, NULL }; 6628ce7ad7bSKristen Carlson Accardi 6638ce7ad7bSKristen Carlson Accardi /* 6648ce7ad7bSKristen Carlson Accardi * set enviroment vars to indicate which event this is for 6658ce7ad7bSKristen Carlson Accardi * so that user space will know to go check the media status. 6668ce7ad7bSKristen Carlson Accardi */ 667edfaa7c3SKay Sievers kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); 6688ce7ad7bSKristen Carlson Accardi put_device(gd->driverfs_dev); 6698ce7ad7bSKristen Carlson Accardi } 6708ce7ad7bSKristen Carlson Accardi 6711826eadfSAdrian Bunk #if 0 6728ce7ad7bSKristen Carlson Accardi void genhd_media_change_notify(struct gendisk *disk) 6738ce7ad7bSKristen Carlson Accardi { 6748ce7ad7bSKristen Carlson Accardi get_device(disk->driverfs_dev); 6758ce7ad7bSKristen Carlson Accardi schedule_work(&disk->async_notify); 6768ce7ad7bSKristen Carlson Accardi } 6778ce7ad7bSKristen Carlson Accardi EXPORT_SYMBOL_GPL(genhd_media_change_notify); 6781826eadfSAdrian Bunk #endif /* 0 */ 6798ce7ad7bSKristen Carlson Accardi 68030f2f0ebSKay Sievers dev_t blk_lookup_devt(const char *name, int part) 681edfaa7c3SKay Sievers { 682edfaa7c3SKay Sievers struct device *dev; 683edfaa7c3SKay Sievers dev_t devt = MKDEV(0, 0); 684edfaa7c3SKay Sievers 685edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 686edfaa7c3SKay Sievers list_for_each_entry(dev, &block_class.devices, node) { 687d5791d13SLinus Torvalds if (dev->type != &disk_type) 688d5791d13SLinus Torvalds continue; 689edfaa7c3SKay Sievers if (strcmp(dev->bus_id, name) == 0) { 69030f2f0ebSKay Sievers struct gendisk *disk = dev_to_disk(dev); 69130f2f0ebSKay Sievers 69230f2f0ebSKay Sievers if (part < disk->minors) 69330f2f0ebSKay Sievers devt = MKDEV(MAJOR(dev->devt), 69430f2f0ebSKay Sievers MINOR(dev->devt) + part); 695edfaa7c3SKay Sievers break; 696edfaa7c3SKay Sievers } 697edfaa7c3SKay Sievers } 698edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 699edfaa7c3SKay Sievers 700edfaa7c3SKay Sievers return devt; 701edfaa7c3SKay Sievers } 702edfaa7c3SKay Sievers EXPORT_SYMBOL(blk_lookup_devt); 703edfaa7c3SKay Sievers 7041da177e4SLinus Torvalds struct gendisk *alloc_disk(int minors) 7051da177e4SLinus Torvalds { 7061946089aSChristoph Lameter return alloc_disk_node(minors, -1); 7071946089aSChristoph Lameter } 7081946089aSChristoph Lameter 7091946089aSChristoph Lameter struct gendisk *alloc_disk_node(int minors, int node_id) 7101946089aSChristoph Lameter { 7111946089aSChristoph Lameter struct gendisk *disk; 7121946089aSChristoph Lameter 71394f6030cSChristoph Lameter disk = kmalloc_node(sizeof(struct gendisk), 71494f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7151da177e4SLinus Torvalds if (disk) { 7161da177e4SLinus Torvalds if (!init_disk_stats(disk)) { 7171da177e4SLinus Torvalds kfree(disk); 7181da177e4SLinus Torvalds return NULL; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds if (minors > 1) { 7211da177e4SLinus Torvalds int size = (minors - 1) * sizeof(struct hd_struct *); 72294f6030cSChristoph Lameter disk->part = kmalloc_node(size, 72394f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7241da177e4SLinus Torvalds if (!disk->part) { 725c7674030SJerome Marchand free_disk_stats(disk); 7261da177e4SLinus Torvalds kfree(disk); 7271da177e4SLinus Torvalds return NULL; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds disk->minors = minors; 7311da177e4SLinus Torvalds rand_initialize_disk(disk); 732edfaa7c3SKay Sievers disk->dev.class = &block_class; 733edfaa7c3SKay Sievers disk->dev.type = &disk_type; 734edfaa7c3SKay Sievers device_initialize(&disk->dev); 7358ce7ad7bSKristen Carlson Accardi INIT_WORK(&disk->async_notify, 7368ce7ad7bSKristen Carlson Accardi media_change_notify_thread); 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds return disk; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_disk); 7421946089aSChristoph Lameter EXPORT_SYMBOL(alloc_disk_node); 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds struct kobject *get_disk(struct gendisk *disk) 7451da177e4SLinus Torvalds { 7461da177e4SLinus Torvalds struct module *owner; 7471da177e4SLinus Torvalds struct kobject *kobj; 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds if (!disk->fops) 7501da177e4SLinus Torvalds return NULL; 7511da177e4SLinus Torvalds owner = disk->fops->owner; 7521da177e4SLinus Torvalds if (owner && !try_module_get(owner)) 7531da177e4SLinus Torvalds return NULL; 754edfaa7c3SKay Sievers kobj = kobject_get(&disk->dev.kobj); 7551da177e4SLinus Torvalds if (kobj == NULL) { 7561da177e4SLinus Torvalds module_put(owner); 7571da177e4SLinus Torvalds return NULL; 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds return kobj; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds } 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds EXPORT_SYMBOL(get_disk); 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds void put_disk(struct gendisk *disk) 7661da177e4SLinus Torvalds { 7671da177e4SLinus Torvalds if (disk) 768edfaa7c3SKay Sievers kobject_put(&disk->dev.kobj); 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds EXPORT_SYMBOL(put_disk); 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds void set_device_ro(struct block_device *bdev, int flag) 7741da177e4SLinus Torvalds { 7751da177e4SLinus Torvalds if (bdev->bd_contains != bdev) 7761da177e4SLinus Torvalds bdev->bd_part->policy = flag; 7771da177e4SLinus Torvalds else 7781da177e4SLinus Torvalds bdev->bd_disk->policy = flag; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds EXPORT_SYMBOL(set_device_ro); 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds void set_disk_ro(struct gendisk *disk, int flag) 7841da177e4SLinus Torvalds { 7851da177e4SLinus Torvalds int i; 7861da177e4SLinus Torvalds disk->policy = flag; 7871da177e4SLinus Torvalds for (i = 0; i < disk->minors - 1; i++) 7881da177e4SLinus Torvalds if (disk->part[i]) disk->part[i]->policy = flag; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds EXPORT_SYMBOL(set_disk_ro); 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds int bdev_read_only(struct block_device *bdev) 7941da177e4SLinus Torvalds { 7951da177e4SLinus Torvalds if (!bdev) 7961da177e4SLinus Torvalds return 0; 7971da177e4SLinus Torvalds else if (bdev->bd_contains != bdev) 7981da177e4SLinus Torvalds return bdev->bd_part->policy; 7991da177e4SLinus Torvalds else 8001da177e4SLinus Torvalds return bdev->bd_disk->policy; 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds EXPORT_SYMBOL(bdev_read_only); 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds int invalidate_partition(struct gendisk *disk, int index) 8061da177e4SLinus Torvalds { 8071da177e4SLinus Torvalds int res = 0; 8081da177e4SLinus Torvalds struct block_device *bdev = bdget_disk(disk, index); 8091da177e4SLinus Torvalds if (bdev) { 8102ef41634SChristoph Hellwig fsync_bdev(bdev); 8112ef41634SChristoph Hellwig res = __invalidate_device(bdev); 8121da177e4SLinus Torvalds bdput(bdev); 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds return res; 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds EXPORT_SYMBOL(invalidate_partition); 818