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 /* 2305c6f35c5SGreg Kroah-Hartman * print a partitions - intended for places where the root filesystem can't be 2315c6f35c5SGreg Kroah-Hartman * mounted and thus to give the victim some idea of what went wrong 232dd2a345fSDave Gilbert */ 2335c6f35c5SGreg 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) 2405c6f35c5SGreg Kroah-Hartman goto exit; 2415c6f35c5SGreg 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)) 2485c6f35c5SGreg 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) 2685c6f35c5SGreg Kroah-Hartman goto exit; 269dd2a345fSDave Gilbert if (sgp->part[n]->nr_sects == 0) 2705c6f35c5SGreg 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 } 2765c6f35c5SGreg Kroah-Hartman exit: 2775c6f35c5SGreg Kroah-Hartman return 0; 278edfaa7c3SKay Sievers } 279dd2a345fSDave Gilbert 2805c6f35c5SGreg Kroah-Hartman /* 2815c6f35c5SGreg Kroah-Hartman * print a full list of all partitions - intended for places where the root 2825c6f35c5SGreg Kroah-Hartman * filesystem can't be mounted and thus to give the victim some idea of what 2835c6f35c5SGreg Kroah-Hartman * went wrong 2845c6f35c5SGreg Kroah-Hartman */ 2855c6f35c5SGreg Kroah-Hartman void __init printk_all_partitions(void) 2865c6f35c5SGreg Kroah-Hartman { 2875c6f35c5SGreg Kroah-Hartman mutex_lock(&block_class_lock); 2885c6f35c5SGreg 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 */ 294*68c4d4a7SGreg Kroah-Hartman static int find_start(struct device *dev, void *data) 295*68c4d4a7SGreg Kroah-Hartman { 296*68c4d4a7SGreg Kroah-Hartman loff_t k = *(loff_t *)data; 297*68c4d4a7SGreg Kroah-Hartman 298*68c4d4a7SGreg Kroah-Hartman if (dev->type != &disk_type) 299*68c4d4a7SGreg Kroah-Hartman return 0; 300*68c4d4a7SGreg Kroah-Hartman if (!k--) 301*68c4d4a7SGreg Kroah-Hartman return 1; 302*68c4d4a7SGreg Kroah-Hartman return 0; 303*68c4d4a7SGreg Kroah-Hartman } 304*68c4d4a7SGreg Kroah-Hartman 3051da177e4SLinus Torvalds static void *part_start(struct seq_file *part, loff_t *pos) 3061da177e4SLinus Torvalds { 307edfaa7c3SKay Sievers struct device *dev; 3081da177e4SLinus Torvalds 309edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 310*68c4d4a7SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)pos, find_start); 311*68c4d4a7SGreg Kroah-Hartman if (dev) 312edfaa7c3SKay Sievers return dev_to_disk(dev); 3131da177e4SLinus Torvalds return NULL; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds static void *part_next(struct seq_file *part, void *v, loff_t *pos) 3171da177e4SLinus Torvalds { 318edfaa7c3SKay Sievers struct gendisk *gp = v; 319edfaa7c3SKay Sievers struct device *dev; 3201da177e4SLinus Torvalds ++*pos; 321edfaa7c3SKay Sievers list_for_each_entry(dev, &gp->dev.node, node) { 322edfaa7c3SKay Sievers if (&dev->node == &block_class.devices) 323edfaa7c3SKay Sievers return NULL; 324edfaa7c3SKay Sievers if (dev->type == &disk_type) 325edfaa7c3SKay Sievers return dev_to_disk(dev); 326edfaa7c3SKay Sievers } 327edfaa7c3SKay Sievers return NULL; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds static void part_stop(struct seq_file *part, void *v) 3311da177e4SLinus Torvalds { 332edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds static int show_partition(struct seq_file *part, void *v) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds struct gendisk *sgp = v; 3381da177e4SLinus Torvalds int n; 3391da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 3401da177e4SLinus Torvalds 341edfaa7c3SKay Sievers if (&sgp->dev.node == block_class.devices.next) 3421da177e4SLinus Torvalds seq_puts(part, "major minor #blocks name\n\n"); 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* Don't show non-partitionable removeable devices or empty devices */ 3451da177e4SLinus Torvalds if (!get_capacity(sgp) || 3461da177e4SLinus Torvalds (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) 3471da177e4SLinus Torvalds return 0; 3481da177e4SLinus Torvalds if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) 3491da177e4SLinus Torvalds return 0; 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* show the full disk and all non-0 size partitions of it */ 3521da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3531da177e4SLinus Torvalds sgp->major, sgp->first_minor, 3541da177e4SLinus Torvalds (unsigned long long)get_capacity(sgp) >> 1, 3551da177e4SLinus Torvalds disk_name(sgp, 0, buf)); 3561da177e4SLinus Torvalds for (n = 0; n < sgp->minors - 1; n++) { 3571da177e4SLinus Torvalds if (!sgp->part[n]) 3581da177e4SLinus Torvalds continue; 3591da177e4SLinus Torvalds if (sgp->part[n]->nr_sects == 0) 3601da177e4SLinus Torvalds continue; 3611da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3621da177e4SLinus Torvalds sgp->major, n + 1 + sgp->first_minor, 3631da177e4SLinus Torvalds (unsigned long long)sgp->part[n]->nr_sects >> 1 , 3641da177e4SLinus Torvalds disk_name(sgp, n + 1, buf)); 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds return 0; 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds 37012f32bb3SJan Engelhardt const struct seq_operations partitions_op = { 3711da177e4SLinus Torvalds .start = part_start, 3721da177e4SLinus Torvalds .next = part_next, 3731da177e4SLinus Torvalds .stop = part_stop, 3741da177e4SLinus Torvalds .show = show_partition 3751da177e4SLinus Torvalds }; 3761da177e4SLinus Torvalds #endif 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds 379edfaa7c3SKay Sievers static struct kobject *base_probe(dev_t devt, int *part, void *data) 3801da177e4SLinus Torvalds { 381edfaa7c3SKay Sievers if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 3821da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */ 383edfaa7c3SKay Sievers request_module("block-major-%d", MAJOR(devt)); 3841da177e4SLinus Torvalds return NULL; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds static int __init genhd_device_init(void) 3881da177e4SLinus Torvalds { 389e105b8bfSDan Williams int error; 390e105b8bfSDan Williams 391e105b8bfSDan Williams block_class.dev_kobj = sysfs_dev_block_kobj; 392e105b8bfSDan Williams error = class_register(&block_class); 393ee27a558SRoland McGrath if (unlikely(error)) 394ee27a558SRoland McGrath return error; 395edfaa7c3SKay Sievers bdev_map = kobj_map_init(base_probe, &block_class_lock); 3961da177e4SLinus Torvalds blk_dev_init(); 397edfaa7c3SKay Sievers 398edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 399edfaa7c3SKay Sievers /* create top-level block dir */ 400edfaa7c3SKay Sievers block_depr = kobject_create_and_add("block", NULL); 401edfaa7c3SKay Sievers #endif 402830d3cfbSGreg Kroah-Hartman return 0; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds subsys_initcall(genhd_device_init); 4061da177e4SLinus Torvalds 407edfaa7c3SKay Sievers static ssize_t disk_range_show(struct device *dev, 408edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4091da177e4SLinus Torvalds { 410edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4111da177e4SLinus Torvalds 412edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->minors); 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 415edfaa7c3SKay Sievers static ssize_t disk_removable_show(struct device *dev, 416edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 417a7fd6706SKay Sievers { 418edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 419a7fd6706SKay Sievers 420edfaa7c3SKay Sievers return sprintf(buf, "%d\n", 4211da177e4SLinus Torvalds (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 422edfaa7c3SKay Sievers } 4231da177e4SLinus Torvalds 4241c9ce527SKay Sievers static ssize_t disk_ro_show(struct device *dev, 4251c9ce527SKay Sievers struct device_attribute *attr, char *buf) 4261c9ce527SKay Sievers { 4271c9ce527SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4281c9ce527SKay Sievers 4291c9ce527SKay Sievers return sprintf(buf, "%d\n", disk->policy ? 1 : 0); 4301c9ce527SKay Sievers } 4311c9ce527SKay Sievers 432edfaa7c3SKay Sievers static ssize_t disk_size_show(struct device *dev, 433edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4341da177e4SLinus Torvalds { 435edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 436edfaa7c3SKay Sievers 437edfaa7c3SKay Sievers return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); 4381da177e4SLinus Torvalds } 439edfaa7c3SKay Sievers 440edfaa7c3SKay Sievers static ssize_t disk_capability_show(struct device *dev, 441edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 44286ce18d7SKristen Carlson Accardi { 443edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 444edfaa7c3SKay Sievers 445edfaa7c3SKay Sievers return sprintf(buf, "%x\n", disk->flags); 44686ce18d7SKristen Carlson Accardi } 447edfaa7c3SKay Sievers 448edfaa7c3SKay Sievers static ssize_t disk_stat_show(struct device *dev, 449edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4501da177e4SLinus Torvalds { 451edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 452edfaa7c3SKay Sievers 4531da177e4SLinus Torvalds preempt_disable(); 4541da177e4SLinus Torvalds disk_round_stats(disk); 4551da177e4SLinus Torvalds preempt_enable(); 456edfaa7c3SKay Sievers return sprintf(buf, 457837c7878SBen Woodard "%8lu %8lu %8llu %8u " 458837c7878SBen Woodard "%8lu %8lu %8llu %8u " 4591da177e4SLinus Torvalds "%8u %8u %8u" 4601da177e4SLinus Torvalds "\n", 46147a00410SJens Axboe disk_stat_read(disk, ios[READ]), 46247a00410SJens Axboe disk_stat_read(disk, merges[READ]), 46347a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[READ]), 46447a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), 46547a00410SJens Axboe disk_stat_read(disk, ios[WRITE]), 46647a00410SJens Axboe disk_stat_read(disk, merges[WRITE]), 46747a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[WRITE]), 46847a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), 4691da177e4SLinus Torvalds disk->in_flight, 4701da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, io_ticks)), 4711da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 474c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 475edfaa7c3SKay Sievers static ssize_t disk_fail_show(struct device *dev, 476edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 477edfaa7c3SKay Sievers { 478edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 479c17bb495SAkinobu Mita 480edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); 481edfaa7c3SKay Sievers } 482edfaa7c3SKay Sievers 483edfaa7c3SKay Sievers static ssize_t disk_fail_store(struct device *dev, 484edfaa7c3SKay Sievers struct device_attribute *attr, 485c17bb495SAkinobu Mita const char *buf, size_t count) 486c17bb495SAkinobu Mita { 487edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 488c17bb495SAkinobu Mita int i; 489c17bb495SAkinobu Mita 490c17bb495SAkinobu Mita if (count > 0 && sscanf(buf, "%d", &i) > 0) { 491c17bb495SAkinobu Mita if (i == 0) 492c17bb495SAkinobu Mita disk->flags &= ~GENHD_FL_FAIL; 493c17bb495SAkinobu Mita else 494c17bb495SAkinobu Mita disk->flags |= GENHD_FL_FAIL; 495c17bb495SAkinobu Mita } 496c17bb495SAkinobu Mita 497c17bb495SAkinobu Mita return count; 498c17bb495SAkinobu Mita } 499c17bb495SAkinobu Mita 500c17bb495SAkinobu Mita #endif 501c17bb495SAkinobu Mita 502edfaa7c3SKay Sievers static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 503edfaa7c3SKay Sievers static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 5041c9ce527SKay Sievers static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 505edfaa7c3SKay Sievers static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 506edfaa7c3SKay Sievers static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 507edfaa7c3SKay Sievers static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 508c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 509edfaa7c3SKay Sievers static struct device_attribute dev_attr_fail = 510edfaa7c3SKay Sievers __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); 511c17bb495SAkinobu Mita #endif 512edfaa7c3SKay Sievers 513edfaa7c3SKay Sievers static struct attribute *disk_attrs[] = { 514edfaa7c3SKay Sievers &dev_attr_range.attr, 515edfaa7c3SKay Sievers &dev_attr_removable.attr, 5161c9ce527SKay Sievers &dev_attr_ro.attr, 517edfaa7c3SKay Sievers &dev_attr_size.attr, 518edfaa7c3SKay Sievers &dev_attr_capability.attr, 519edfaa7c3SKay Sievers &dev_attr_stat.attr, 520edfaa7c3SKay Sievers #ifdef CONFIG_FAIL_MAKE_REQUEST 521edfaa7c3SKay Sievers &dev_attr_fail.attr, 522edfaa7c3SKay Sievers #endif 523edfaa7c3SKay Sievers NULL 5241da177e4SLinus Torvalds }; 5251da177e4SLinus Torvalds 526edfaa7c3SKay Sievers static struct attribute_group disk_attr_group = { 527edfaa7c3SKay Sievers .attrs = disk_attrs, 528edfaa7c3SKay Sievers }; 529edfaa7c3SKay Sievers 530edfaa7c3SKay Sievers static struct attribute_group *disk_attr_groups[] = { 531edfaa7c3SKay Sievers &disk_attr_group, 532edfaa7c3SKay Sievers NULL 533edfaa7c3SKay Sievers }; 534edfaa7c3SKay Sievers 535edfaa7c3SKay Sievers static void disk_release(struct device *dev) 5361da177e4SLinus Torvalds { 537edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 538edfaa7c3SKay Sievers 5391da177e4SLinus Torvalds kfree(disk->random); 5401da177e4SLinus Torvalds kfree(disk->part); 5411da177e4SLinus Torvalds free_disk_stats(disk); 5421da177e4SLinus Torvalds kfree(disk); 5431da177e4SLinus Torvalds } 544edfaa7c3SKay Sievers struct class block_class = { 545edfaa7c3SKay Sievers .name = "block", 5461da177e4SLinus Torvalds }; 5471da177e4SLinus Torvalds 5481826eadfSAdrian Bunk static struct device_type disk_type = { 549edfaa7c3SKay Sievers .name = "disk", 550edfaa7c3SKay Sievers .groups = disk_attr_groups, 551edfaa7c3SKay Sievers .release = disk_release, 5521da177e4SLinus Torvalds }; 5531da177e4SLinus Torvalds 554a6e2ba88SRandy Dunlap #ifdef CONFIG_PROC_FS 5551da177e4SLinus Torvalds /* 5561da177e4SLinus Torvalds * aggregate disk stat collector. Uses the same stats that the sysfs 5571da177e4SLinus Torvalds * entries do, above, but makes them available through one seq_file. 5581da177e4SLinus Torvalds * 5591da177e4SLinus Torvalds * The output looks suspiciously like /proc/partitions with a bunch of 5601da177e4SLinus Torvalds * extra fields. 5611da177e4SLinus Torvalds */ 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds static void *diskstats_start(struct seq_file *part, loff_t *pos) 5641da177e4SLinus Torvalds { 565edfaa7c3SKay Sievers struct device *dev; 5661da177e4SLinus Torvalds 567edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 568*68c4d4a7SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)pos, find_start); 569*68c4d4a7SGreg Kroah-Hartman if (dev) 570edfaa7c3SKay Sievers return dev_to_disk(dev); 5711da177e4SLinus Torvalds return NULL; 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) 5751da177e4SLinus Torvalds { 576edfaa7c3SKay Sievers struct gendisk *gp = v; 577edfaa7c3SKay Sievers struct device *dev; 578edfaa7c3SKay Sievers 5791da177e4SLinus Torvalds ++*pos; 580edfaa7c3SKay Sievers list_for_each_entry(dev, &gp->dev.node, node) { 581edfaa7c3SKay Sievers if (&dev->node == &block_class.devices) 582edfaa7c3SKay Sievers return NULL; 583edfaa7c3SKay Sievers if (dev->type == &disk_type) 584edfaa7c3SKay Sievers return dev_to_disk(dev); 585edfaa7c3SKay Sievers } 586edfaa7c3SKay Sievers return NULL; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds static void diskstats_stop(struct seq_file *part, void *v) 5901da177e4SLinus Torvalds { 591edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds static int diskstats_show(struct seq_file *s, void *v) 5951da177e4SLinus Torvalds { 5961da177e4SLinus Torvalds struct gendisk *gp = v; 5971da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 5981da177e4SLinus Torvalds int n = 0; 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds /* 601edfaa7c3SKay Sievers if (&gp->dev.kobj.entry == block_class.devices.next) 6021da177e4SLinus Torvalds seq_puts(s, "major minor name" 6031da177e4SLinus Torvalds " rio rmerge rsect ruse wio wmerge " 6041da177e4SLinus Torvalds "wsect wuse running use aveq" 6051da177e4SLinus Torvalds "\n\n"); 6061da177e4SLinus Torvalds */ 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds preempt_disable(); 6091da177e4SLinus Torvalds disk_round_stats(gp); 6101da177e4SLinus Torvalds preempt_enable(); 611837c7878SBen Woodard seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 6121da177e4SLinus Torvalds gp->major, n + gp->first_minor, disk_name(gp, n, buf), 613a362357bSJens Axboe disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), 614a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[0]), 615a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[0])), 616a362357bSJens Axboe disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), 617a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[1]), 618a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[1])), 6191da177e4SLinus Torvalds gp->in_flight, 6201da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, io_ticks)), 6211da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* now show all non-0 size partitions of it */ 6241da177e4SLinus Torvalds for (n = 0; n < gp->minors - 1; n++) { 6251da177e4SLinus Torvalds struct hd_struct *hd = gp->part[n]; 6261da177e4SLinus Torvalds 62728f39d55SJerome Marchand if (!hd || !hd->nr_sects) 62828f39d55SJerome Marchand continue; 62928f39d55SJerome Marchand 63028f39d55SJerome Marchand preempt_disable(); 63128f39d55SJerome Marchand part_round_stats(hd); 63228f39d55SJerome Marchand preempt_enable(); 63328f39d55SJerome Marchand seq_printf(s, "%4d %4d %s %lu %lu %llu " 63428f39d55SJerome Marchand "%u %lu %lu %llu %u %u %u %u\n", 6351da177e4SLinus Torvalds gp->major, n + gp->first_minor + 1, 6361da177e4SLinus Torvalds disk_name(gp, n + 1, buf), 63728f39d55SJerome Marchand part_stat_read(hd, ios[0]), 63828f39d55SJerome Marchand part_stat_read(hd, merges[0]), 63928f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[0]), 64028f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[0])), 64128f39d55SJerome Marchand part_stat_read(hd, ios[1]), 64228f39d55SJerome Marchand part_stat_read(hd, merges[1]), 64328f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[1]), 64428f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[1])), 64528f39d55SJerome Marchand hd->in_flight, 64628f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, io_ticks)), 64728f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, time_in_queue)) 64828f39d55SJerome Marchand ); 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds return 0; 6521da177e4SLinus Torvalds } 6531da177e4SLinus Torvalds 65412f32bb3SJan Engelhardt const struct seq_operations diskstats_op = { 6551da177e4SLinus Torvalds .start = diskstats_start, 6561da177e4SLinus Torvalds .next = diskstats_next, 6571da177e4SLinus Torvalds .stop = diskstats_stop, 6581da177e4SLinus Torvalds .show = diskstats_show 6591da177e4SLinus Torvalds }; 660a6e2ba88SRandy Dunlap #endif /* CONFIG_PROC_FS */ 6611da177e4SLinus Torvalds 6628ce7ad7bSKristen Carlson Accardi static void media_change_notify_thread(struct work_struct *work) 6638ce7ad7bSKristen Carlson Accardi { 6648ce7ad7bSKristen Carlson Accardi struct gendisk *gd = container_of(work, struct gendisk, async_notify); 6658ce7ad7bSKristen Carlson Accardi char event[] = "MEDIA_CHANGE=1"; 6668ce7ad7bSKristen Carlson Accardi char *envp[] = { event, NULL }; 6678ce7ad7bSKristen Carlson Accardi 6688ce7ad7bSKristen Carlson Accardi /* 6698ce7ad7bSKristen Carlson Accardi * set enviroment vars to indicate which event this is for 6708ce7ad7bSKristen Carlson Accardi * so that user space will know to go check the media status. 6718ce7ad7bSKristen Carlson Accardi */ 672edfaa7c3SKay Sievers kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); 6738ce7ad7bSKristen Carlson Accardi put_device(gd->driverfs_dev); 6748ce7ad7bSKristen Carlson Accardi } 6758ce7ad7bSKristen Carlson Accardi 6761826eadfSAdrian Bunk #if 0 6778ce7ad7bSKristen Carlson Accardi void genhd_media_change_notify(struct gendisk *disk) 6788ce7ad7bSKristen Carlson Accardi { 6798ce7ad7bSKristen Carlson Accardi get_device(disk->driverfs_dev); 6808ce7ad7bSKristen Carlson Accardi schedule_work(&disk->async_notify); 6818ce7ad7bSKristen Carlson Accardi } 6828ce7ad7bSKristen Carlson Accardi EXPORT_SYMBOL_GPL(genhd_media_change_notify); 6831826eadfSAdrian Bunk #endif /* 0 */ 6848ce7ad7bSKristen Carlson Accardi 685a142be85SGreg Kroah-Hartman struct find_block { 686a142be85SGreg Kroah-Hartman const char *name; 687a142be85SGreg Kroah-Hartman int part; 688a142be85SGreg Kroah-Hartman }; 689a142be85SGreg Kroah-Hartman 690a142be85SGreg Kroah-Hartman static int match_id(struct device *dev, void *data) 691a142be85SGreg Kroah-Hartman { 692a142be85SGreg Kroah-Hartman struct find_block *find = data; 693a142be85SGreg Kroah-Hartman 694a142be85SGreg Kroah-Hartman if (dev->type != &disk_type) 695a142be85SGreg Kroah-Hartman return 0; 696a142be85SGreg Kroah-Hartman if (strcmp(dev->bus_id, find->name) == 0) { 697a142be85SGreg Kroah-Hartman struct gendisk *disk = dev_to_disk(dev); 698a142be85SGreg Kroah-Hartman if (find->part < disk->minors) 699a142be85SGreg Kroah-Hartman return 1; 700a142be85SGreg Kroah-Hartman } 701a142be85SGreg Kroah-Hartman return 0; 702a142be85SGreg Kroah-Hartman } 703a142be85SGreg Kroah-Hartman 70430f2f0ebSKay Sievers dev_t blk_lookup_devt(const char *name, int part) 705edfaa7c3SKay Sievers { 706edfaa7c3SKay Sievers struct device *dev; 707edfaa7c3SKay Sievers dev_t devt = MKDEV(0, 0); 708a142be85SGreg Kroah-Hartman struct find_block find; 709edfaa7c3SKay Sievers 710edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 711a142be85SGreg Kroah-Hartman find.name = name; 712a142be85SGreg Kroah-Hartman find.part = part; 713a142be85SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)&find, match_id); 714a142be85SGreg Kroah-Hartman if (dev) 71530f2f0ebSKay Sievers devt = MKDEV(MAJOR(dev->devt), 71630f2f0ebSKay Sievers MINOR(dev->devt) + part); 717edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 718edfaa7c3SKay Sievers 719edfaa7c3SKay Sievers return devt; 720edfaa7c3SKay Sievers } 721edfaa7c3SKay Sievers EXPORT_SYMBOL(blk_lookup_devt); 722edfaa7c3SKay Sievers 7231da177e4SLinus Torvalds struct gendisk *alloc_disk(int minors) 7241da177e4SLinus Torvalds { 7251946089aSChristoph Lameter return alloc_disk_node(minors, -1); 7261946089aSChristoph Lameter } 7271946089aSChristoph Lameter 7281946089aSChristoph Lameter struct gendisk *alloc_disk_node(int minors, int node_id) 7291946089aSChristoph Lameter { 7301946089aSChristoph Lameter struct gendisk *disk; 7311946089aSChristoph Lameter 73294f6030cSChristoph Lameter disk = kmalloc_node(sizeof(struct gendisk), 73394f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7341da177e4SLinus Torvalds if (disk) { 7351da177e4SLinus Torvalds if (!init_disk_stats(disk)) { 7361da177e4SLinus Torvalds kfree(disk); 7371da177e4SLinus Torvalds return NULL; 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds if (minors > 1) { 7401da177e4SLinus Torvalds int size = (minors - 1) * sizeof(struct hd_struct *); 74194f6030cSChristoph Lameter disk->part = kmalloc_node(size, 74294f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7431da177e4SLinus Torvalds if (!disk->part) { 744c7674030SJerome Marchand free_disk_stats(disk); 7451da177e4SLinus Torvalds kfree(disk); 7461da177e4SLinus Torvalds return NULL; 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds disk->minors = minors; 7501da177e4SLinus Torvalds rand_initialize_disk(disk); 751edfaa7c3SKay Sievers disk->dev.class = &block_class; 752edfaa7c3SKay Sievers disk->dev.type = &disk_type; 753edfaa7c3SKay Sievers device_initialize(&disk->dev); 7548ce7ad7bSKristen Carlson Accardi INIT_WORK(&disk->async_notify, 7558ce7ad7bSKristen Carlson Accardi media_change_notify_thread); 7561da177e4SLinus Torvalds } 7571da177e4SLinus Torvalds return disk; 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_disk); 7611946089aSChristoph Lameter EXPORT_SYMBOL(alloc_disk_node); 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds struct kobject *get_disk(struct gendisk *disk) 7641da177e4SLinus Torvalds { 7651da177e4SLinus Torvalds struct module *owner; 7661da177e4SLinus Torvalds struct kobject *kobj; 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds if (!disk->fops) 7691da177e4SLinus Torvalds return NULL; 7701da177e4SLinus Torvalds owner = disk->fops->owner; 7711da177e4SLinus Torvalds if (owner && !try_module_get(owner)) 7721da177e4SLinus Torvalds return NULL; 773edfaa7c3SKay Sievers kobj = kobject_get(&disk->dev.kobj); 7741da177e4SLinus Torvalds if (kobj == NULL) { 7751da177e4SLinus Torvalds module_put(owner); 7761da177e4SLinus Torvalds return NULL; 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds return kobj; 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds EXPORT_SYMBOL(get_disk); 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds void put_disk(struct gendisk *disk) 7851da177e4SLinus Torvalds { 7861da177e4SLinus Torvalds if (disk) 787edfaa7c3SKay Sievers kobject_put(&disk->dev.kobj); 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds EXPORT_SYMBOL(put_disk); 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds void set_device_ro(struct block_device *bdev, int flag) 7931da177e4SLinus Torvalds { 7941da177e4SLinus Torvalds if (bdev->bd_contains != bdev) 7951da177e4SLinus Torvalds bdev->bd_part->policy = flag; 7961da177e4SLinus Torvalds else 7971da177e4SLinus Torvalds bdev->bd_disk->policy = flag; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds EXPORT_SYMBOL(set_device_ro); 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds void set_disk_ro(struct gendisk *disk, int flag) 8031da177e4SLinus Torvalds { 8041da177e4SLinus Torvalds int i; 8051da177e4SLinus Torvalds disk->policy = flag; 8061da177e4SLinus Torvalds for (i = 0; i < disk->minors - 1; i++) 8071da177e4SLinus Torvalds if (disk->part[i]) disk->part[i]->policy = flag; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds EXPORT_SYMBOL(set_disk_ro); 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds int bdev_read_only(struct block_device *bdev) 8131da177e4SLinus Torvalds { 8141da177e4SLinus Torvalds if (!bdev) 8151da177e4SLinus Torvalds return 0; 8161da177e4SLinus Torvalds else if (bdev->bd_contains != bdev) 8171da177e4SLinus Torvalds return bdev->bd_part->policy; 8181da177e4SLinus Torvalds else 8191da177e4SLinus Torvalds return bdev->bd_disk->policy; 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds EXPORT_SYMBOL(bdev_read_only); 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds int invalidate_partition(struct gendisk *disk, int index) 8251da177e4SLinus Torvalds { 8261da177e4SLinus Torvalds int res = 0; 8271da177e4SLinus Torvalds struct block_device *bdev = bdget_disk(disk, index); 8281da177e4SLinus Torvalds if (bdev) { 8292ef41634SChristoph Hellwig fsync_bdev(bdev); 8302ef41634SChristoph Hellwig res = __invalidate_device(bdev); 8311da177e4SLinus Torvalds bdput(bdev); 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds return res; 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds EXPORT_SYMBOL(invalidate_partition); 837