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