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 */ 29468c4d4a7SGreg Kroah-Hartman static int find_start(struct device *dev, void *data) 29568c4d4a7SGreg Kroah-Hartman { 29668c4d4a7SGreg Kroah-Hartman loff_t k = *(loff_t *)data; 29768c4d4a7SGreg Kroah-Hartman 29868c4d4a7SGreg Kroah-Hartman if (dev->type != &disk_type) 29968c4d4a7SGreg Kroah-Hartman return 0; 30068c4d4a7SGreg Kroah-Hartman if (!k--) 30168c4d4a7SGreg Kroah-Hartman return 1; 30268c4d4a7SGreg Kroah-Hartman return 0; 30368c4d4a7SGreg Kroah-Hartman } 30468c4d4a7SGreg Kroah-Hartman 3051da177e4SLinus Torvalds static void *part_start(struct seq_file *part, loff_t *pos) 3061da177e4SLinus Torvalds { 307edfaa7c3SKay Sievers struct device *dev; 30866c64afeSGreg Kroah-Hartman loff_t n = *pos; 30966c64afeSGreg Kroah-Hartman 31066c64afeSGreg Kroah-Hartman if (!n) 31166c64afeSGreg Kroah-Hartman seq_puts(part, "major minor #blocks name\n\n"); 3121da177e4SLinus Torvalds 313edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 31468c4d4a7SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)pos, find_start); 31568c4d4a7SGreg Kroah-Hartman if (dev) 316edfaa7c3SKay Sievers return dev_to_disk(dev); 3171da177e4SLinus Torvalds return NULL; 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 320*27f30251SGreg Kroah-Hartman static int find_next(struct device *dev, void *data) 321*27f30251SGreg Kroah-Hartman { 322*27f30251SGreg Kroah-Hartman if (dev->type == &disk_type) 323*27f30251SGreg Kroah-Hartman return 1; 324*27f30251SGreg Kroah-Hartman return 0; 325*27f30251SGreg Kroah-Hartman } 326*27f30251SGreg Kroah-Hartman 3271da177e4SLinus Torvalds static void *part_next(struct seq_file *part, void *v, loff_t *pos) 3281da177e4SLinus Torvalds { 329edfaa7c3SKay Sievers struct gendisk *gp = v; 330edfaa7c3SKay Sievers struct device *dev; 3311da177e4SLinus Torvalds ++*pos; 332*27f30251SGreg Kroah-Hartman dev = class_find_device(&block_class, &gp->dev, NULL, find_next); 333*27f30251SGreg Kroah-Hartman if (dev) 334edfaa7c3SKay Sievers return dev_to_disk(dev); 335edfaa7c3SKay Sievers return NULL; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds static void part_stop(struct seq_file *part, void *v) 3391da177e4SLinus Torvalds { 340edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds static int show_partition(struct seq_file *part, void *v) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds struct gendisk *sgp = v; 3461da177e4SLinus Torvalds int n; 3471da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds /* Don't show non-partitionable removeable devices or empty devices */ 3501da177e4SLinus Torvalds if (!get_capacity(sgp) || 3511da177e4SLinus Torvalds (sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE))) 3521da177e4SLinus Torvalds return 0; 3531da177e4SLinus Torvalds if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) 3541da177e4SLinus Torvalds return 0; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /* show the full disk and all non-0 size partitions of it */ 3571da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3581da177e4SLinus Torvalds sgp->major, sgp->first_minor, 3591da177e4SLinus Torvalds (unsigned long long)get_capacity(sgp) >> 1, 3601da177e4SLinus Torvalds disk_name(sgp, 0, buf)); 3611da177e4SLinus Torvalds for (n = 0; n < sgp->minors - 1; n++) { 3621da177e4SLinus Torvalds if (!sgp->part[n]) 3631da177e4SLinus Torvalds continue; 3641da177e4SLinus Torvalds if (sgp->part[n]->nr_sects == 0) 3651da177e4SLinus Torvalds continue; 3661da177e4SLinus Torvalds seq_printf(part, "%4d %4d %10llu %s\n", 3671da177e4SLinus Torvalds sgp->major, n + 1 + sgp->first_minor, 3681da177e4SLinus Torvalds (unsigned long long)sgp->part[n]->nr_sects >> 1 , 3691da177e4SLinus Torvalds disk_name(sgp, n + 1, buf)); 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds return 0; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 37512f32bb3SJan Engelhardt const struct seq_operations partitions_op = { 3761da177e4SLinus Torvalds .start = part_start, 3771da177e4SLinus Torvalds .next = part_next, 3781da177e4SLinus Torvalds .stop = part_stop, 3791da177e4SLinus Torvalds .show = show_partition 3801da177e4SLinus Torvalds }; 3811da177e4SLinus Torvalds #endif 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds 384edfaa7c3SKay Sievers static struct kobject *base_probe(dev_t devt, int *part, void *data) 3851da177e4SLinus Torvalds { 386edfaa7c3SKay Sievers if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) 3871da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */ 388edfaa7c3SKay Sievers request_module("block-major-%d", MAJOR(devt)); 3891da177e4SLinus Torvalds return NULL; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds static int __init genhd_device_init(void) 3931da177e4SLinus Torvalds { 394e105b8bfSDan Williams int error; 395e105b8bfSDan Williams 396e105b8bfSDan Williams block_class.dev_kobj = sysfs_dev_block_kobj; 397e105b8bfSDan Williams error = class_register(&block_class); 398ee27a558SRoland McGrath if (unlikely(error)) 399ee27a558SRoland McGrath return error; 400edfaa7c3SKay Sievers bdev_map = kobj_map_init(base_probe, &block_class_lock); 4011da177e4SLinus Torvalds blk_dev_init(); 402edfaa7c3SKay Sievers 403edfaa7c3SKay Sievers #ifndef CONFIG_SYSFS_DEPRECATED 404edfaa7c3SKay Sievers /* create top-level block dir */ 405edfaa7c3SKay Sievers block_depr = kobject_create_and_add("block", NULL); 406edfaa7c3SKay Sievers #endif 407830d3cfbSGreg Kroah-Hartman return 0; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds subsys_initcall(genhd_device_init); 4111da177e4SLinus Torvalds 412edfaa7c3SKay Sievers static ssize_t disk_range_show(struct device *dev, 413edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4141da177e4SLinus Torvalds { 415edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4161da177e4SLinus Torvalds 417edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->minors); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420edfaa7c3SKay Sievers static ssize_t disk_removable_show(struct device *dev, 421edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 422a7fd6706SKay Sievers { 423edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 424a7fd6706SKay Sievers 425edfaa7c3SKay Sievers return sprintf(buf, "%d\n", 4261da177e4SLinus Torvalds (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); 427edfaa7c3SKay Sievers } 4281da177e4SLinus Torvalds 4291c9ce527SKay Sievers static ssize_t disk_ro_show(struct device *dev, 4301c9ce527SKay Sievers struct device_attribute *attr, char *buf) 4311c9ce527SKay Sievers { 4321c9ce527SKay Sievers struct gendisk *disk = dev_to_disk(dev); 4331c9ce527SKay Sievers 4341c9ce527SKay Sievers return sprintf(buf, "%d\n", disk->policy ? 1 : 0); 4351c9ce527SKay Sievers } 4361c9ce527SKay Sievers 437edfaa7c3SKay Sievers static ssize_t disk_size_show(struct device *dev, 438edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4391da177e4SLinus Torvalds { 440edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 441edfaa7c3SKay Sievers 442edfaa7c3SKay Sievers return sprintf(buf, "%llu\n", (unsigned long long)get_capacity(disk)); 4431da177e4SLinus Torvalds } 444edfaa7c3SKay Sievers 445edfaa7c3SKay Sievers static ssize_t disk_capability_show(struct device *dev, 446edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 44786ce18d7SKristen Carlson Accardi { 448edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 449edfaa7c3SKay Sievers 450edfaa7c3SKay Sievers return sprintf(buf, "%x\n", disk->flags); 45186ce18d7SKristen Carlson Accardi } 452edfaa7c3SKay Sievers 453edfaa7c3SKay Sievers static ssize_t disk_stat_show(struct device *dev, 454edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 4551da177e4SLinus Torvalds { 456edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 457edfaa7c3SKay Sievers 4581da177e4SLinus Torvalds preempt_disable(); 4591da177e4SLinus Torvalds disk_round_stats(disk); 4601da177e4SLinus Torvalds preempt_enable(); 461edfaa7c3SKay Sievers return sprintf(buf, 462837c7878SBen Woodard "%8lu %8lu %8llu %8u " 463837c7878SBen Woodard "%8lu %8lu %8llu %8u " 4641da177e4SLinus Torvalds "%8u %8u %8u" 4651da177e4SLinus Torvalds "\n", 46647a00410SJens Axboe disk_stat_read(disk, ios[READ]), 46747a00410SJens Axboe disk_stat_read(disk, merges[READ]), 46847a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[READ]), 46947a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[READ])), 47047a00410SJens Axboe disk_stat_read(disk, ios[WRITE]), 47147a00410SJens Axboe disk_stat_read(disk, merges[WRITE]), 47247a00410SJens Axboe (unsigned long long)disk_stat_read(disk, sectors[WRITE]), 47347a00410SJens Axboe jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])), 4741da177e4SLinus Torvalds disk->in_flight, 4751da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, io_ticks)), 4761da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 479c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 480edfaa7c3SKay Sievers static ssize_t disk_fail_show(struct device *dev, 481edfaa7c3SKay Sievers struct device_attribute *attr, char *buf) 482edfaa7c3SKay Sievers { 483edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 484c17bb495SAkinobu Mita 485edfaa7c3SKay Sievers return sprintf(buf, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); 486edfaa7c3SKay Sievers } 487edfaa7c3SKay Sievers 488edfaa7c3SKay Sievers static ssize_t disk_fail_store(struct device *dev, 489edfaa7c3SKay Sievers struct device_attribute *attr, 490c17bb495SAkinobu Mita const char *buf, size_t count) 491c17bb495SAkinobu Mita { 492edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 493c17bb495SAkinobu Mita int i; 494c17bb495SAkinobu Mita 495c17bb495SAkinobu Mita if (count > 0 && sscanf(buf, "%d", &i) > 0) { 496c17bb495SAkinobu Mita if (i == 0) 497c17bb495SAkinobu Mita disk->flags &= ~GENHD_FL_FAIL; 498c17bb495SAkinobu Mita else 499c17bb495SAkinobu Mita disk->flags |= GENHD_FL_FAIL; 500c17bb495SAkinobu Mita } 501c17bb495SAkinobu Mita 502c17bb495SAkinobu Mita return count; 503c17bb495SAkinobu Mita } 504c17bb495SAkinobu Mita 505c17bb495SAkinobu Mita #endif 506c17bb495SAkinobu Mita 507edfaa7c3SKay Sievers static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 508edfaa7c3SKay Sievers static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 5091c9ce527SKay Sievers static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 510edfaa7c3SKay Sievers static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); 511edfaa7c3SKay Sievers static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 512edfaa7c3SKay Sievers static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); 513c17bb495SAkinobu Mita #ifdef CONFIG_FAIL_MAKE_REQUEST 514edfaa7c3SKay Sievers static struct device_attribute dev_attr_fail = 515edfaa7c3SKay Sievers __ATTR(make-it-fail, S_IRUGO|S_IWUSR, disk_fail_show, disk_fail_store); 516c17bb495SAkinobu Mita #endif 517edfaa7c3SKay Sievers 518edfaa7c3SKay Sievers static struct attribute *disk_attrs[] = { 519edfaa7c3SKay Sievers &dev_attr_range.attr, 520edfaa7c3SKay Sievers &dev_attr_removable.attr, 5211c9ce527SKay Sievers &dev_attr_ro.attr, 522edfaa7c3SKay Sievers &dev_attr_size.attr, 523edfaa7c3SKay Sievers &dev_attr_capability.attr, 524edfaa7c3SKay Sievers &dev_attr_stat.attr, 525edfaa7c3SKay Sievers #ifdef CONFIG_FAIL_MAKE_REQUEST 526edfaa7c3SKay Sievers &dev_attr_fail.attr, 527edfaa7c3SKay Sievers #endif 528edfaa7c3SKay Sievers NULL 5291da177e4SLinus Torvalds }; 5301da177e4SLinus Torvalds 531edfaa7c3SKay Sievers static struct attribute_group disk_attr_group = { 532edfaa7c3SKay Sievers .attrs = disk_attrs, 533edfaa7c3SKay Sievers }; 534edfaa7c3SKay Sievers 535edfaa7c3SKay Sievers static struct attribute_group *disk_attr_groups[] = { 536edfaa7c3SKay Sievers &disk_attr_group, 537edfaa7c3SKay Sievers NULL 538edfaa7c3SKay Sievers }; 539edfaa7c3SKay Sievers 540edfaa7c3SKay Sievers static void disk_release(struct device *dev) 5411da177e4SLinus Torvalds { 542edfaa7c3SKay Sievers struct gendisk *disk = dev_to_disk(dev); 543edfaa7c3SKay Sievers 5441da177e4SLinus Torvalds kfree(disk->random); 5451da177e4SLinus Torvalds kfree(disk->part); 5461da177e4SLinus Torvalds free_disk_stats(disk); 5471da177e4SLinus Torvalds kfree(disk); 5481da177e4SLinus Torvalds } 549edfaa7c3SKay Sievers struct class block_class = { 550edfaa7c3SKay Sievers .name = "block", 5511da177e4SLinus Torvalds }; 5521da177e4SLinus Torvalds 5531826eadfSAdrian Bunk static struct device_type disk_type = { 554edfaa7c3SKay Sievers .name = "disk", 555edfaa7c3SKay Sievers .groups = disk_attr_groups, 556edfaa7c3SKay Sievers .release = disk_release, 5571da177e4SLinus Torvalds }; 5581da177e4SLinus Torvalds 559a6e2ba88SRandy Dunlap #ifdef CONFIG_PROC_FS 5601da177e4SLinus Torvalds /* 5611da177e4SLinus Torvalds * aggregate disk stat collector. Uses the same stats that the sysfs 5621da177e4SLinus Torvalds * entries do, above, but makes them available through one seq_file. 5631da177e4SLinus Torvalds * 5641da177e4SLinus Torvalds * The output looks suspiciously like /proc/partitions with a bunch of 5651da177e4SLinus Torvalds * extra fields. 5661da177e4SLinus Torvalds */ 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds static void *diskstats_start(struct seq_file *part, loff_t *pos) 5691da177e4SLinus Torvalds { 570edfaa7c3SKay Sievers struct device *dev; 5711da177e4SLinus Torvalds 572edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 57368c4d4a7SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)pos, find_start); 57468c4d4a7SGreg Kroah-Hartman if (dev) 575edfaa7c3SKay Sievers return dev_to_disk(dev); 5761da177e4SLinus Torvalds return NULL; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos) 5801da177e4SLinus Torvalds { 581edfaa7c3SKay Sievers struct gendisk *gp = v; 582edfaa7c3SKay Sievers struct device *dev; 583edfaa7c3SKay Sievers 5841da177e4SLinus Torvalds ++*pos; 585*27f30251SGreg Kroah-Hartman dev = class_find_device(&block_class, &gp->dev, NULL, find_next); 586*27f30251SGreg Kroah-Hartman if (dev) 587edfaa7c3SKay Sievers return dev_to_disk(dev); 588edfaa7c3SKay Sievers return NULL; 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds static void diskstats_stop(struct seq_file *part, void *v) 5921da177e4SLinus Torvalds { 593edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds static int diskstats_show(struct seq_file *s, void *v) 5971da177e4SLinus Torvalds { 5981da177e4SLinus Torvalds struct gendisk *gp = v; 5991da177e4SLinus Torvalds char buf[BDEVNAME_SIZE]; 6001da177e4SLinus Torvalds int n = 0; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* 603edfaa7c3SKay Sievers if (&gp->dev.kobj.entry == block_class.devices.next) 6041da177e4SLinus Torvalds seq_puts(s, "major minor name" 6051da177e4SLinus Torvalds " rio rmerge rsect ruse wio wmerge " 6061da177e4SLinus Torvalds "wsect wuse running use aveq" 6071da177e4SLinus Torvalds "\n\n"); 6081da177e4SLinus Torvalds */ 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds preempt_disable(); 6111da177e4SLinus Torvalds disk_round_stats(gp); 6121da177e4SLinus Torvalds preempt_enable(); 613837c7878SBen Woodard seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n", 6141da177e4SLinus Torvalds gp->major, n + gp->first_minor, disk_name(gp, n, buf), 615a362357bSJens Axboe disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), 616a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[0]), 617a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[0])), 618a362357bSJens Axboe disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]), 619a362357bSJens Axboe (unsigned long long)disk_stat_read(gp, sectors[1]), 620a362357bSJens Axboe jiffies_to_msecs(disk_stat_read(gp, ticks[1])), 6211da177e4SLinus Torvalds gp->in_flight, 6221da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, io_ticks)), 6231da177e4SLinus Torvalds jiffies_to_msecs(disk_stat_read(gp, time_in_queue))); 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds /* now show all non-0 size partitions of it */ 6261da177e4SLinus Torvalds for (n = 0; n < gp->minors - 1; n++) { 6271da177e4SLinus Torvalds struct hd_struct *hd = gp->part[n]; 6281da177e4SLinus Torvalds 62928f39d55SJerome Marchand if (!hd || !hd->nr_sects) 63028f39d55SJerome Marchand continue; 63128f39d55SJerome Marchand 63228f39d55SJerome Marchand preempt_disable(); 63328f39d55SJerome Marchand part_round_stats(hd); 63428f39d55SJerome Marchand preempt_enable(); 63528f39d55SJerome Marchand seq_printf(s, "%4d %4d %s %lu %lu %llu " 63628f39d55SJerome Marchand "%u %lu %lu %llu %u %u %u %u\n", 6371da177e4SLinus Torvalds gp->major, n + gp->first_minor + 1, 6381da177e4SLinus Torvalds disk_name(gp, n + 1, buf), 63928f39d55SJerome Marchand part_stat_read(hd, ios[0]), 64028f39d55SJerome Marchand part_stat_read(hd, merges[0]), 64128f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[0]), 64228f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[0])), 64328f39d55SJerome Marchand part_stat_read(hd, ios[1]), 64428f39d55SJerome Marchand part_stat_read(hd, merges[1]), 64528f39d55SJerome Marchand (unsigned long long)part_stat_read(hd, sectors[1]), 64628f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, ticks[1])), 64728f39d55SJerome Marchand hd->in_flight, 64828f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, io_ticks)), 64928f39d55SJerome Marchand jiffies_to_msecs(part_stat_read(hd, time_in_queue)) 65028f39d55SJerome Marchand ); 6511da177e4SLinus Torvalds } 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds return 0; 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 65612f32bb3SJan Engelhardt const struct seq_operations diskstats_op = { 6571da177e4SLinus Torvalds .start = diskstats_start, 6581da177e4SLinus Torvalds .next = diskstats_next, 6591da177e4SLinus Torvalds .stop = diskstats_stop, 6601da177e4SLinus Torvalds .show = diskstats_show 6611da177e4SLinus Torvalds }; 662a6e2ba88SRandy Dunlap #endif /* CONFIG_PROC_FS */ 6631da177e4SLinus Torvalds 6648ce7ad7bSKristen Carlson Accardi static void media_change_notify_thread(struct work_struct *work) 6658ce7ad7bSKristen Carlson Accardi { 6668ce7ad7bSKristen Carlson Accardi struct gendisk *gd = container_of(work, struct gendisk, async_notify); 6678ce7ad7bSKristen Carlson Accardi char event[] = "MEDIA_CHANGE=1"; 6688ce7ad7bSKristen Carlson Accardi char *envp[] = { event, NULL }; 6698ce7ad7bSKristen Carlson Accardi 6708ce7ad7bSKristen Carlson Accardi /* 6718ce7ad7bSKristen Carlson Accardi * set enviroment vars to indicate which event this is for 6728ce7ad7bSKristen Carlson Accardi * so that user space will know to go check the media status. 6738ce7ad7bSKristen Carlson Accardi */ 674edfaa7c3SKay Sievers kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); 6758ce7ad7bSKristen Carlson Accardi put_device(gd->driverfs_dev); 6768ce7ad7bSKristen Carlson Accardi } 6778ce7ad7bSKristen Carlson Accardi 6781826eadfSAdrian Bunk #if 0 6798ce7ad7bSKristen Carlson Accardi void genhd_media_change_notify(struct gendisk *disk) 6808ce7ad7bSKristen Carlson Accardi { 6818ce7ad7bSKristen Carlson Accardi get_device(disk->driverfs_dev); 6828ce7ad7bSKristen Carlson Accardi schedule_work(&disk->async_notify); 6838ce7ad7bSKristen Carlson Accardi } 6848ce7ad7bSKristen Carlson Accardi EXPORT_SYMBOL_GPL(genhd_media_change_notify); 6851826eadfSAdrian Bunk #endif /* 0 */ 6868ce7ad7bSKristen Carlson Accardi 687a142be85SGreg Kroah-Hartman struct find_block { 688a142be85SGreg Kroah-Hartman const char *name; 689a142be85SGreg Kroah-Hartman int part; 690a142be85SGreg Kroah-Hartman }; 691a142be85SGreg Kroah-Hartman 692a142be85SGreg Kroah-Hartman static int match_id(struct device *dev, void *data) 693a142be85SGreg Kroah-Hartman { 694a142be85SGreg Kroah-Hartman struct find_block *find = data; 695a142be85SGreg Kroah-Hartman 696a142be85SGreg Kroah-Hartman if (dev->type != &disk_type) 697a142be85SGreg Kroah-Hartman return 0; 698a142be85SGreg Kroah-Hartman if (strcmp(dev->bus_id, find->name) == 0) { 699a142be85SGreg Kroah-Hartman struct gendisk *disk = dev_to_disk(dev); 700a142be85SGreg Kroah-Hartman if (find->part < disk->minors) 701a142be85SGreg Kroah-Hartman return 1; 702a142be85SGreg Kroah-Hartman } 703a142be85SGreg Kroah-Hartman return 0; 704a142be85SGreg Kroah-Hartman } 705a142be85SGreg Kroah-Hartman 70630f2f0ebSKay Sievers dev_t blk_lookup_devt(const char *name, int part) 707edfaa7c3SKay Sievers { 708edfaa7c3SKay Sievers struct device *dev; 709edfaa7c3SKay Sievers dev_t devt = MKDEV(0, 0); 710a142be85SGreg Kroah-Hartman struct find_block find; 711edfaa7c3SKay Sievers 712edfaa7c3SKay Sievers mutex_lock(&block_class_lock); 713a142be85SGreg Kroah-Hartman find.name = name; 714a142be85SGreg Kroah-Hartman find.part = part; 715a142be85SGreg Kroah-Hartman dev = class_find_device(&block_class, NULL, (void *)&find, match_id); 716a142be85SGreg Kroah-Hartman if (dev) 71730f2f0ebSKay Sievers devt = MKDEV(MAJOR(dev->devt), 71830f2f0ebSKay Sievers MINOR(dev->devt) + part); 719edfaa7c3SKay Sievers mutex_unlock(&block_class_lock); 720edfaa7c3SKay Sievers 721edfaa7c3SKay Sievers return devt; 722edfaa7c3SKay Sievers } 723edfaa7c3SKay Sievers EXPORT_SYMBOL(blk_lookup_devt); 724edfaa7c3SKay Sievers 7251da177e4SLinus Torvalds struct gendisk *alloc_disk(int minors) 7261da177e4SLinus Torvalds { 7271946089aSChristoph Lameter return alloc_disk_node(minors, -1); 7281946089aSChristoph Lameter } 7291946089aSChristoph Lameter 7301946089aSChristoph Lameter struct gendisk *alloc_disk_node(int minors, int node_id) 7311946089aSChristoph Lameter { 7321946089aSChristoph Lameter struct gendisk *disk; 7331946089aSChristoph Lameter 73494f6030cSChristoph Lameter disk = kmalloc_node(sizeof(struct gendisk), 73594f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7361da177e4SLinus Torvalds if (disk) { 7371da177e4SLinus Torvalds if (!init_disk_stats(disk)) { 7381da177e4SLinus Torvalds kfree(disk); 7391da177e4SLinus Torvalds return NULL; 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds if (minors > 1) { 7421da177e4SLinus Torvalds int size = (minors - 1) * sizeof(struct hd_struct *); 74394f6030cSChristoph Lameter disk->part = kmalloc_node(size, 74494f6030cSChristoph Lameter GFP_KERNEL | __GFP_ZERO, node_id); 7451da177e4SLinus Torvalds if (!disk->part) { 746c7674030SJerome Marchand free_disk_stats(disk); 7471da177e4SLinus Torvalds kfree(disk); 7481da177e4SLinus Torvalds return NULL; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds disk->minors = minors; 7521da177e4SLinus Torvalds rand_initialize_disk(disk); 753edfaa7c3SKay Sievers disk->dev.class = &block_class; 754edfaa7c3SKay Sievers disk->dev.type = &disk_type; 755edfaa7c3SKay Sievers device_initialize(&disk->dev); 7568ce7ad7bSKristen Carlson Accardi INIT_WORK(&disk->async_notify, 7578ce7ad7bSKristen Carlson Accardi media_change_notify_thread); 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds return disk; 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_disk); 7631946089aSChristoph Lameter EXPORT_SYMBOL(alloc_disk_node); 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds struct kobject *get_disk(struct gendisk *disk) 7661da177e4SLinus Torvalds { 7671da177e4SLinus Torvalds struct module *owner; 7681da177e4SLinus Torvalds struct kobject *kobj; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds if (!disk->fops) 7711da177e4SLinus Torvalds return NULL; 7721da177e4SLinus Torvalds owner = disk->fops->owner; 7731da177e4SLinus Torvalds if (owner && !try_module_get(owner)) 7741da177e4SLinus Torvalds return NULL; 775edfaa7c3SKay Sievers kobj = kobject_get(&disk->dev.kobj); 7761da177e4SLinus Torvalds if (kobj == NULL) { 7771da177e4SLinus Torvalds module_put(owner); 7781da177e4SLinus Torvalds return NULL; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds return kobj; 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds EXPORT_SYMBOL(get_disk); 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds void put_disk(struct gendisk *disk) 7871da177e4SLinus Torvalds { 7881da177e4SLinus Torvalds if (disk) 789edfaa7c3SKay Sievers kobject_put(&disk->dev.kobj); 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds EXPORT_SYMBOL(put_disk); 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds void set_device_ro(struct block_device *bdev, int flag) 7951da177e4SLinus Torvalds { 7961da177e4SLinus Torvalds if (bdev->bd_contains != bdev) 7971da177e4SLinus Torvalds bdev->bd_part->policy = flag; 7981da177e4SLinus Torvalds else 7991da177e4SLinus Torvalds bdev->bd_disk->policy = flag; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds EXPORT_SYMBOL(set_device_ro); 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds void set_disk_ro(struct gendisk *disk, int flag) 8051da177e4SLinus Torvalds { 8061da177e4SLinus Torvalds int i; 8071da177e4SLinus Torvalds disk->policy = flag; 8081da177e4SLinus Torvalds for (i = 0; i < disk->minors - 1; i++) 8091da177e4SLinus Torvalds if (disk->part[i]) disk->part[i]->policy = flag; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds EXPORT_SYMBOL(set_disk_ro); 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds int bdev_read_only(struct block_device *bdev) 8151da177e4SLinus Torvalds { 8161da177e4SLinus Torvalds if (!bdev) 8171da177e4SLinus Torvalds return 0; 8181da177e4SLinus Torvalds else if (bdev->bd_contains != bdev) 8191da177e4SLinus Torvalds return bdev->bd_part->policy; 8201da177e4SLinus Torvalds else 8211da177e4SLinus Torvalds return bdev->bd_disk->policy; 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds EXPORT_SYMBOL(bdev_read_only); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds int invalidate_partition(struct gendisk *disk, int index) 8271da177e4SLinus Torvalds { 8281da177e4SLinus Torvalds int res = 0; 8291da177e4SLinus Torvalds struct block_device *bdev = bdget_disk(disk, index); 8301da177e4SLinus Torvalds if (bdev) { 8312ef41634SChristoph Hellwig fsync_bdev(bdev); 8322ef41634SChristoph Hellwig res = __invalidate_device(bdev); 8331da177e4SLinus Torvalds bdput(bdev); 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds return res; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds EXPORT_SYMBOL(invalidate_partition); 839