Blame view

block/genhd.c 29.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *  gendisk handling
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
  #include <linux/module.h>
  #include <linux/fs.h>
  #include <linux/genhd.h>
b446b60e4   Andrew Morton   [PATCH] rework re...
7
  #include <linux/kdev_t.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
  #include <linux/kernel.h>
  #include <linux/blkdev.h>
  #include <linux/init.h>
  #include <linux/spinlock.h>
f500975a3   Alexey Dobriyan   proc: move rest o...
12
  #include <linux/proc_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
  #include <linux/seq_file.h>
  #include <linux/slab.h>
  #include <linux/kmod.h>
  #include <linux/kobj_map.h>
2ef41634d   Christoph Hellwig   [PATCH] remove do...
17
  #include <linux/buffer_head.h>
58383af62   Jes Sorensen   [PATCH] kobj_map ...
18
  #include <linux/mutex.h>
bcce3de1b   Tejun Heo   block: implement ...
19
  #include <linux/idr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

ff88972c8   Adrian Bunk   proper prototype ...
21
  #include "blk.h"
edfaa7c36   Kay Sievers   Driver core: conv...
22
23
24
25
  static DEFINE_MUTEX(block_class_lock);
  #ifndef CONFIG_SYSFS_DEPRECATED
  struct kobject *block_depr;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

bcce3de1b   Tejun Heo   block: implement ...
27
28
29
30
31
32
33
34
  /* for extended dynamic devt allocation, currently only one major is used */
  #define MAX_EXT_DEVT		(1 << MINORBITS)
  
  /* For extended devt allocation.  ext_devt_mutex prevents look up
   * results from going away underneath its user.
   */
  static DEFINE_MUTEX(ext_devt_mutex);
  static DEFINE_IDR(ext_devt_idr);
1826eadfc   Adrian Bunk   block/genhd.c: cl...
35
  static struct device_type disk_type;
e71bf0d0e   Tejun Heo   block: fix disk->...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  /**
   * disk_get_part - get partition
   * @disk: disk to look partition from
   * @partno: partition number
   *
   * Look for partition @partno from @disk.  If found, increment
   * reference count and return it.
   *
   * CONTEXT:
   * Don't care.
   *
   * RETURNS:
   * Pointer to the found partition on success, NULL if not found.
   */
  struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
  {
540eed563   Tejun Heo   block: make parti...
52
53
  	struct hd_struct *part = NULL;
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
54

540eed563   Tejun Heo   block: make parti...
55
  	if (unlikely(partno < 0))
e71bf0d0e   Tejun Heo   block: fix disk->...
56
  		return NULL;
540eed563   Tejun Heo   block: make parti...
57

e71bf0d0e   Tejun Heo   block: fix disk->...
58
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
59
60
61
62
63
64
65
  
  	ptbl = rcu_dereference(disk->part_tbl);
  	if (likely(partno < ptbl->len)) {
  		part = rcu_dereference(ptbl->part[partno]);
  		if (part)
  			get_device(part_to_dev(part));
  	}
e71bf0d0e   Tejun Heo   block: fix disk->...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  	rcu_read_unlock();
  
  	return part;
  }
  EXPORT_SYMBOL_GPL(disk_get_part);
  
  /**
   * disk_part_iter_init - initialize partition iterator
   * @piter: iterator to initialize
   * @disk: disk to iterate over
   * @flags: DISK_PITER_* flags
   *
   * Initialize @piter so that it iterates over partitions of @disk.
   *
   * CONTEXT:
   * Don't care.
   */
  void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk,
  			  unsigned int flags)
  {
540eed563   Tejun Heo   block: make parti...
86
87
88
89
  	struct disk_part_tbl *ptbl;
  
  	rcu_read_lock();
  	ptbl = rcu_dereference(disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
90
91
92
93
  	piter->disk = disk;
  	piter->part = NULL;
  
  	if (flags & DISK_PITER_REVERSE)
540eed563   Tejun Heo   block: make parti...
94
  		piter->idx = ptbl->len - 1;
71982a409   Tejun Heo   block: include em...
95
  	else if (flags & (DISK_PITER_INCL_PART0 | DISK_PITER_INCL_EMPTY_PART0))
e71bf0d0e   Tejun Heo   block: fix disk->...
96
  		piter->idx = 0;
b5d0b9df0   Tejun Heo   block: introduce ...
97
98
  	else
  		piter->idx = 1;
e71bf0d0e   Tejun Heo   block: fix disk->...
99
100
  
  	piter->flags = flags;
540eed563   Tejun Heo   block: make parti...
101
102
  
  	rcu_read_unlock();
e71bf0d0e   Tejun Heo   block: fix disk->...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  }
  EXPORT_SYMBOL_GPL(disk_part_iter_init);
  
  /**
   * disk_part_iter_next - proceed iterator to the next partition and return it
   * @piter: iterator of interest
   *
   * Proceed @piter to the next partition and return it.
   *
   * CONTEXT:
   * Don't care.
   */
  struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
  {
540eed563   Tejun Heo   block: make parti...
117
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
118
119
120
121
122
  	int inc, end;
  
  	/* put the last partition */
  	disk_put_part(piter->part);
  	piter->part = NULL;
540eed563   Tejun Heo   block: make parti...
123
  	/* get part_tbl */
e71bf0d0e   Tejun Heo   block: fix disk->...
124
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
125
  	ptbl = rcu_dereference(piter->disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
126
127
128
129
  
  	/* determine iteration parameters */
  	if (piter->flags & DISK_PITER_REVERSE) {
  		inc = -1;
71982a409   Tejun Heo   block: include em...
130
131
  		if (piter->flags & (DISK_PITER_INCL_PART0 |
  				    DISK_PITER_INCL_EMPTY_PART0))
b5d0b9df0   Tejun Heo   block: introduce ...
132
133
134
  			end = -1;
  		else
  			end = 0;
e71bf0d0e   Tejun Heo   block: fix disk->...
135
136
  	} else {
  		inc = 1;
540eed563   Tejun Heo   block: make parti...
137
  		end = ptbl->len;
e71bf0d0e   Tejun Heo   block: fix disk->...
138
139
140
141
142
  	}
  
  	/* iterate to the next partition */
  	for (; piter->idx != end; piter->idx += inc) {
  		struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
143
  		part = rcu_dereference(ptbl->part[piter->idx]);
e71bf0d0e   Tejun Heo   block: fix disk->...
144
145
  		if (!part)
  			continue;
71982a409   Tejun Heo   block: include em...
146
147
148
149
  		if (!part->nr_sects &&
  		    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
  		    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
  		      piter->idx == 0))
e71bf0d0e   Tejun Heo   block: fix disk->...
150
  			continue;
ed9e19823   Tejun Heo   block: implement ...
151
  		get_device(part_to_dev(part));
e71bf0d0e   Tejun Heo   block: fix disk->...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  		piter->part = part;
  		piter->idx += inc;
  		break;
  	}
  
  	rcu_read_unlock();
  
  	return piter->part;
  }
  EXPORT_SYMBOL_GPL(disk_part_iter_next);
  
  /**
   * disk_part_iter_exit - finish up partition iteration
   * @piter: iter of interest
   *
   * Called when iteration is over.  Cleans up @piter.
   *
   * CONTEXT:
   * Don't care.
   */
  void disk_part_iter_exit(struct disk_part_iter *piter)
  {
  	disk_put_part(piter->part);
  	piter->part = NULL;
  }
  EXPORT_SYMBOL_GPL(disk_part_iter_exit);
a6f23657d   Jens Axboe   block: add one-hi...
178
179
180
181
182
  static inline int sector_in_part(struct hd_struct *part, sector_t sector)
  {
  	return part->start_sect <= sector &&
  		sector < part->start_sect + part->nr_sects;
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
183
184
185
186
187
188
189
190
191
192
193
194
195
  /**
   * disk_map_sector_rcu - map sector to partition
   * @disk: gendisk of interest
   * @sector: sector to map
   *
   * Find out which partition @sector maps to on @disk.  This is
   * primarily used for stats accounting.
   *
   * CONTEXT:
   * RCU read locked.  The returned partition pointer is valid only
   * while preemption is disabled.
   *
   * RETURNS:
074a7aca7   Tejun Heo   block: move stats...
196
   * Found partition on success, part0 is returned if no partition matches
e71bf0d0e   Tejun Heo   block: fix disk->...
197
198
199
   */
  struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
  {
540eed563   Tejun Heo   block: make parti...
200
  	struct disk_part_tbl *ptbl;
a6f23657d   Jens Axboe   block: add one-hi...
201
  	struct hd_struct *part;
e71bf0d0e   Tejun Heo   block: fix disk->...
202
  	int i;
540eed563   Tejun Heo   block: make parti...
203
  	ptbl = rcu_dereference(disk->part_tbl);
a6f23657d   Jens Axboe   block: add one-hi...
204
205
206
  	part = rcu_dereference(ptbl->last_lookup);
  	if (part && sector_in_part(part, sector))
  		return part;
540eed563   Tejun Heo   block: make parti...
207
  	for (i = 1; i < ptbl->len; i++) {
a6f23657d   Jens Axboe   block: add one-hi...
208
  		part = rcu_dereference(ptbl->part[i]);
e71bf0d0e   Tejun Heo   block: fix disk->...
209

a6f23657d   Jens Axboe   block: add one-hi...
210
211
  		if (part && sector_in_part(part, sector)) {
  			rcu_assign_pointer(ptbl->last_lookup, part);
e71bf0d0e   Tejun Heo   block: fix disk->...
212
  			return part;
a6f23657d   Jens Axboe   block: add one-hi...
213
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
214
  	}
074a7aca7   Tejun Heo   block: move stats...
215
  	return &disk->part0;
e71bf0d0e   Tejun Heo   block: fix disk->...
216
217
  }
  EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
  /*
   * Can be deleted altogether. Later.
   *
   */
  static struct blk_major_name {
  	struct blk_major_name *next;
  	int major;
  	char name[16];
68eef3b47   Joe Korty   [PATCH] Simplify ...
226
  } *major_names[BLKDEV_MAJOR_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  
  /* index in the above - for now: assume no multimajor ranges */
  static inline int major_to_index(int major)
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
231
  	return major % BLKDEV_MAJOR_HASH_SIZE;
7170be5f5   Neil Horman   [PATCH] convert /...
232
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
233
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
234
  void blkdev_show(struct seq_file *seqf, off_t offset)
7170be5f5   Neil Horman   [PATCH] convert /...
235
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
236
  	struct blk_major_name *dp;
7170be5f5   Neil Horman   [PATCH] convert /...
237

68eef3b47   Joe Korty   [PATCH] Simplify ...
238
  	if (offset < BLKDEV_MAJOR_HASH_SIZE) {
edfaa7c36   Kay Sievers   Driver core: conv...
239
  		mutex_lock(&block_class_lock);
68eef3b47   Joe Korty   [PATCH] Simplify ...
240
  		for (dp = major_names[offset]; dp; dp = dp->next)
cf771cb5a   Tejun Heo   block: make varia...
241
242
  			seq_printf(seqf, "%3d %s
  ", dp->major, dp->name);
edfaa7c36   Kay Sievers   Driver core: conv...
243
  		mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
246
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

9e8c0bccd   Márton Németh   block: add docume...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  /**
   * register_blkdev - register a new block device
   *
   * @major: the requested major device number [1..255]. If @major=0, try to
   *         allocate any unused major number.
   * @name: the name of the new block device as a zero terminated string
   *
   * The @name must be unique within the system.
   *
   * The return value depends on the @major input parameter.
   *  - if a major device number was requested in range [1..255] then the
   *    function returns zero on success, or a negative error code
   *  - if any unused major number was requested with @major=0 parameter
   *    then the return value is the allocated major number in range
   *    [1..255] or a negative error code otherwise
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
  int register_blkdev(unsigned int major, const char *name)
  {
  	struct blk_major_name **n, *p;
  	int index, ret = 0;
edfaa7c36   Kay Sievers   Driver core: conv...
268
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  
  	/* temporary */
  	if (major == 0) {
  		for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
  			if (major_names[index] == NULL)
  				break;
  		}
  
  		if (index == 0) {
  			printk("register_blkdev: failed to get major for %s
  ",
  			       name);
  			ret = -EBUSY;
  			goto out;
  		}
  		major = index;
  		ret = major;
  	}
  
  	p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
  	if (p == NULL) {
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	p->major = major;
  	strlcpy(p->name, name, sizeof(p->name));
  	p->next = NULL;
  	index = major_to_index(major);
  
  	for (n = &major_names[index]; *n; n = &(*n)->next) {
  		if ((*n)->major == major)
  			break;
  	}
  	if (!*n)
  		*n = p;
  	else
  		ret = -EBUSY;
  
  	if (ret < 0) {
  		printk("register_blkdev: cannot get major %d for %s
  ",
  		       major, name);
  		kfree(p);
  	}
  out:
edfaa7c36   Kay Sievers   Driver core: conv...
315
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
  	return ret;
  }
  
  EXPORT_SYMBOL(register_blkdev);
f4480240f   Akinobu Mita   unregister_blkdev...
320
  void unregister_blkdev(unsigned int major, const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
  {
  	struct blk_major_name **n;
  	struct blk_major_name *p = NULL;
  	int index = major_to_index(major);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

edfaa7c36   Kay Sievers   Driver core: conv...
326
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
  	for (n = &major_names[index]; *n; n = &(*n)->next)
  		if ((*n)->major == major)
  			break;
294462a5c   Akinobu Mita   unregister_blkdev...
330
331
  	if (!*n || strcmp((*n)->name, name)) {
  		WARN_ON(1);
294462a5c   Akinobu Mita   unregister_blkdev...
332
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
  		p = *n;
  		*n = p->next;
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
336
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	kfree(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
342
  }
  
  EXPORT_SYMBOL(unregister_blkdev);
  
  static struct kobj_map *bdev_map;
bcce3de1b   Tejun Heo   block: implement ...
343
  /**
870d66561   Tejun Heo   block: implement ...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
   * blk_mangle_minor - scatter minor numbers apart
   * @minor: minor number to mangle
   *
   * Scatter consecutively allocated @minor number apart if MANGLE_DEVT
   * is enabled.  Mangling twice gives the original value.
   *
   * RETURNS:
   * Mangled value.
   *
   * CONTEXT:
   * Don't care.
   */
  static int blk_mangle_minor(int minor)
  {
  #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
  	int i;
  
  	for (i = 0; i < MINORBITS / 2; i++) {
  		int low = minor & (1 << i);
  		int high = minor & (1 << (MINORBITS - 1 - i));
  		int distance = MINORBITS - 1 - 2 * i;
  
  		minor ^= low | high;	/* clear both bits */
  		low <<= distance;	/* swap the positions */
  		high >>= distance;
  		minor |= low | high;	/* and set */
  	}
  #endif
  	return minor;
  }
  
  /**
bcce3de1b   Tejun Heo   block: implement ...
376
377
   * blk_alloc_devt - allocate a dev_t for a partition
   * @part: partition to allocate dev_t for
bcce3de1b   Tejun Heo   block: implement ...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
   * @devt: out parameter for resulting dev_t
   *
   * Allocate a dev_t for block device.
   *
   * RETURNS:
   * 0 on success, allocated dev_t is returned in *@devt.  -errno on
   * failure.
   *
   * CONTEXT:
   * Might sleep.
   */
  int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
  {
  	struct gendisk *disk = part_to_disk(part);
  	int idx, rc;
  
  	/* in consecutive minor range? */
  	if (part->partno < disk->minors) {
  		*devt = MKDEV(disk->major, disk->first_minor + part->partno);
  		return 0;
  	}
  
  	/* allocate ext devt */
  	do {
  		if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
  			return -ENOMEM;
  		rc = idr_get_new(&ext_devt_idr, part, &idx);
  	} while (rc == -EAGAIN);
  
  	if (rc)
  		return rc;
  
  	if (idx > MAX_EXT_DEVT) {
  		idr_remove(&ext_devt_idr, idx);
  		return -EBUSY;
  	}
870d66561   Tejun Heo   block: implement ...
414
  	*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
bcce3de1b   Tejun Heo   block: implement ...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  	return 0;
  }
  
  /**
   * blk_free_devt - free a dev_t
   * @devt: dev_t to free
   *
   * Free @devt which was allocated using blk_alloc_devt().
   *
   * CONTEXT:
   * Might sleep.
   */
  void blk_free_devt(dev_t devt)
  {
  	might_sleep();
  
  	if (devt == MKDEV(0, 0))
  		return;
  
  	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
  		mutex_lock(&ext_devt_mutex);
870d66561   Tejun Heo   block: implement ...
436
  		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
bcce3de1b   Tejun Heo   block: implement ...
437
438
439
  		mutex_unlock(&ext_devt_mutex);
  	}
  }
1f0142905   Tejun Heo   block: adjust for...
440
441
442
443
444
445
446
447
448
449
450
  static char *bdevt_str(dev_t devt, char *buf)
  {
  	if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
  		char tbuf[BDEVT_SIZE];
  		snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt));
  		snprintf(buf, BDEVT_SIZE, "%-9s", tbuf);
  	} else
  		snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt));
  
  	return buf;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
  /*
   * Register device numbers dev..(dev+range-1)
   * range must be nonzero
   * The hash chain is sorted on range, so that subranges can override.
   */
edfaa7c36   Kay Sievers   Driver core: conv...
456
  void blk_register_region(dev_t devt, unsigned long range, struct module *module,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
  			 struct kobject *(*probe)(dev_t, int *, void *),
  			 int (*lock)(dev_t, void *), void *data)
  {
edfaa7c36   Kay Sievers   Driver core: conv...
460
  	kobj_map(bdev_map, devt, range, module, probe, lock, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
  }
  
  EXPORT_SYMBOL(blk_register_region);
edfaa7c36   Kay Sievers   Driver core: conv...
464
  void blk_unregister_region(dev_t devt, unsigned long range)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  {
edfaa7c36   Kay Sievers   Driver core: conv...
466
  	kobj_unmap(bdev_map, devt, range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
  }
  
  EXPORT_SYMBOL(blk_unregister_region);
cf771cb5a   Tejun Heo   block: make varia...
470
  static struct kobject *exact_match(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
  {
  	struct gendisk *p = data;
edfaa7c36   Kay Sievers   Driver core: conv...
473

ed9e19823   Tejun Heo   block: implement ...
474
  	return &disk_to_dev(p)->kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  }
edfaa7c36   Kay Sievers   Driver core: conv...
476
  static int exact_lock(dev_t devt, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  {
  	struct gendisk *p = data;
  
  	if (!get_disk(p))
  		return -1;
  	return 0;
  }
  
  /**
   * add_disk - add partitioning information to kernel list
   * @disk: per-device partitioning information
   *
   * This function registers the partitioning information in @disk
   * with the kernel.
3e1a7ff8a   Tejun Heo   block: allow disk...
491
492
   *
   * FIXME: error handling
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
   */
  void add_disk(struct gendisk *disk)
  {
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
496
  	struct backing_dev_info *bdi;
3e1a7ff8a   Tejun Heo   block: allow disk...
497
  	dev_t devt;
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
498
  	int retval;
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
499

3e1a7ff8a   Tejun Heo   block: allow disk...
500
501
502
503
504
505
  	/* minors == 0 indicates to use ext devt from part0 and should
  	 * be accompanied with EXT_DEVT flag.  Make sure all
  	 * parameters make sense.
  	 */
  	WARN_ON(disk->minors && !(disk->major || disk->first_minor));
  	WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	disk->flags |= GENHD_FL_UP;
3e1a7ff8a   Tejun Heo   block: allow disk...
507
508
509
510
511
512
513
514
515
516
517
518
519
  
  	retval = blk_alloc_devt(&disk->part0, &devt);
  	if (retval) {
  		WARN_ON(1);
  		return;
  	}
  	disk_to_dev(disk)->devt = devt;
  
  	/* ->major and ->first_minor aren't supposed to be
  	 * dereferenced from here on, but set them just in case.
  	 */
  	disk->major = MAJOR(devt);
  	disk->first_minor = MINOR(devt);
f331c0296   Tejun Heo   block: don't depe...
520
521
  	blk_register_region(disk_devt(disk), disk->minors, NULL,
  			    exact_match, exact_lock, disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
  	register_disk(disk);
  	blk_register_queue(disk);
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
524
525
  
  	bdi = &disk->queue->backing_dev_info;
f331c0296   Tejun Heo   block: don't depe...
526
  	bdi_register_dev(bdi, disk_devt(disk));
ed9e19823   Tejun Heo   block: implement ...
527
528
  	retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
  				   "bdi");
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
529
  	WARN_ON(retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
532
533
534
535
536
  }
  
  EXPORT_SYMBOL(add_disk);
  EXPORT_SYMBOL(del_gendisk);	/* in partitions/check.c */
  
  void unlink_gendisk(struct gendisk *disk)
  {
ed9e19823   Tejun Heo   block: implement ...
537
  	sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
538
  	bdi_unregister(&disk->queue->backing_dev_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	blk_unregister_queue(disk);
f331c0296   Tejun Heo   block: don't depe...
540
  	blk_unregister_region(disk_devt(disk), disk->minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  /**
   * get_gendisk - get partitioning information for a given device
710027a48   Randy Dunlap   Add some block/ s...
544
   * @devt: device to get partitioning information for
496aa8a98   Randy Dunlap   block: fix curren...
545
   * @partno: returned partition index
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
   *
   * This function gets the structure containing partitioning
710027a48   Randy Dunlap   Add some block/ s...
548
   * information for the given device @devt.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
   */
cf771cb5a   Tejun Heo   block: make varia...
550
  struct gendisk *get_gendisk(dev_t devt, int *partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  {
bcce3de1b   Tejun Heo   block: implement ...
552
553
554
555
556
557
558
559
560
561
562
563
  	struct gendisk *disk = NULL;
  
  	if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
  		struct kobject *kobj;
  
  		kobj = kobj_lookup(bdev_map, devt, partno);
  		if (kobj)
  			disk = dev_to_disk(kobj_to_dev(kobj));
  	} else {
  		struct hd_struct *part;
  
  		mutex_lock(&ext_devt_mutex);
870d66561   Tejun Heo   block: implement ...
564
  		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
bcce3de1b   Tejun Heo   block: implement ...
565
566
567
568
569
570
  		if (part && get_disk(part_to_disk(part))) {
  			*partno = part->partno;
  			disk = part_to_disk(part);
  		}
  		mutex_unlock(&ext_devt_mutex);
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
571

bcce3de1b   Tejun Heo   block: implement ...
572
  	return disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  }
f331c0296   Tejun Heo   block: don't depe...
574
575
576
577
578
579
580
581
582
583
584
585
586
  /**
   * bdget_disk - do bdget() by gendisk and partition number
   * @disk: gendisk of interest
   * @partno: partition number
   *
   * Find partition @partno from @disk, do bdget() on it.
   *
   * CONTEXT:
   * Don't care.
   *
   * RETURNS:
   * Resulting block_device on success, NULL on failure.
   */
aeb3d3a81   Harvey Harrison   block: kmalloc ar...
587
  struct block_device *bdget_disk(struct gendisk *disk, int partno)
f331c0296   Tejun Heo   block: don't depe...
588
  {
548b10eb2   Tejun Heo   block: move __dev...
589
590
  	struct hd_struct *part;
  	struct block_device *bdev = NULL;
f331c0296   Tejun Heo   block: don't depe...
591

548b10eb2   Tejun Heo   block: move __dev...
592
  	part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
593
  	if (part)
548b10eb2   Tejun Heo   block: move __dev...
594
595
  		bdev = bdget(part_devt(part));
  	disk_put_part(part);
f331c0296   Tejun Heo   block: don't depe...
596

548b10eb2   Tejun Heo   block: move __dev...
597
  	return bdev;
f331c0296   Tejun Heo   block: don't depe...
598
599
  }
  EXPORT_SYMBOL(bdget_disk);
dd2a345f8   Dave Gilbert   Display all possi...
600
  /*
5c6f35c5e   Greg Kroah-Hartman   block: make print...
601
602
603
604
605
606
   * print a full list of all partitions - intended for places where the root
   * filesystem can't be mounted and thus to give the victim some idea of what
   * went wrong
   */
  void __init printk_all_partitions(void)
  {
def4e38dd   Tejun Heo   block: use class_...
607
608
609
610
611
612
  	struct class_dev_iter iter;
  	struct device *dev;
  
  	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
  	while ((dev = class_dev_iter_next(&iter))) {
  		struct gendisk *disk = dev_to_disk(dev);
e71bf0d0e   Tejun Heo   block: fix disk->...
613
614
  		struct disk_part_iter piter;
  		struct hd_struct *part;
1f0142905   Tejun Heo   block: adjust for...
615
616
  		char name_buf[BDEVNAME_SIZE];
  		char devt_buf[BDEVT_SIZE];
def4e38dd   Tejun Heo   block: use class_...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  
  		/*
  		 * Don't show empty devices or things that have been
  		 * surpressed
  		 */
  		if (get_capacity(disk) == 0 ||
  		    (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
  			continue;
  
  		/*
  		 * Note, unlike /proc/partitions, I am showing the
  		 * numbers in hex - the same format as the root=
  		 * option takes.
  		 */
074a7aca7   Tejun Heo   block: move stats...
631
632
633
  		disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
  		while ((part = disk_part_iter_next(&piter))) {
  			bool is_part0 = part == &disk->part0;
def4e38dd   Tejun Heo   block: use class_...
634

074a7aca7   Tejun Heo   block: move stats...
635
  			printk("%s%s %10llu %s", is_part0 ? "" : "  ",
1f0142905   Tejun Heo   block: adjust for...
636
  			       bdevt_str(part_devt(part), devt_buf),
f331c0296   Tejun Heo   block: don't depe...
637
  			       (unsigned long long)part->nr_sects >> 1,
1f0142905   Tejun Heo   block: adjust for...
638
  			       disk_name(disk, part->partno, name_buf));
074a7aca7   Tejun Heo   block: move stats...
639
640
641
642
643
644
645
646
647
648
649
650
651
  			if (is_part0) {
  				if (disk->driverfs_dev != NULL &&
  				    disk->driverfs_dev->driver != NULL)
  					printk(" driver: %s
  ",
  					      disk->driverfs_dev->driver->name);
  				else
  					printk(" (driver?)
  ");
  			} else
  				printk("
  ");
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
652
  		disk_part_iter_exit(&piter);
def4e38dd   Tejun Heo   block: use class_...
653
654
  	}
  	class_dev_iter_exit(&iter);
dd2a345f8   Dave Gilbert   Display all possi...
655
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  #ifdef CONFIG_PROC_FS
  /* iterator */
def4e38dd   Tejun Heo   block: use class_...
658
  static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
659
  {
def4e38dd   Tejun Heo   block: use class_...
660
661
662
  	loff_t skip = *pos;
  	struct class_dev_iter *iter;
  	struct device *dev;
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
663

aeb3d3a81   Harvey Harrison   block: kmalloc ar...
664
  	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
def4e38dd   Tejun Heo   block: use class_...
665
666
667
668
669
670
671
672
673
674
675
676
  	if (!iter)
  		return ERR_PTR(-ENOMEM);
  
  	seqf->private = iter;
  	class_dev_iter_init(iter, &block_class, NULL, &disk_type);
  	do {
  		dev = class_dev_iter_next(iter);
  		if (!dev)
  			return NULL;
  	} while (skip--);
  
  	return dev_to_disk(dev);
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
677
  }
def4e38dd   Tejun Heo   block: use class_...
678
  static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  {
edfaa7c36   Kay Sievers   Driver core: conv...
680
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681

def4e38dd   Tejun Heo   block: use class_...
682
683
  	(*pos)++;
  	dev = class_dev_iter_next(seqf->private);
2ac3cee52   Tejun Heo   block: don't grab...
684
  	if (dev)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
685
  		return dev_to_disk(dev);
2ac3cee52   Tejun Heo   block: don't grab...
686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
  	return NULL;
  }
def4e38dd   Tejun Heo   block: use class_...
689
  static void disk_seqf_stop(struct seq_file *seqf, void *v)
27f302519   Greg Kroah-Hartman   block: make /proc...
690
  {
def4e38dd   Tejun Heo   block: use class_...
691
  	struct class_dev_iter *iter = seqf->private;
27f302519   Greg Kroah-Hartman   block: make /proc...
692

def4e38dd   Tejun Heo   block: use class_...
693
694
695
696
  	/* stop is called even after start failed :-( */
  	if (iter) {
  		class_dev_iter_exit(iter);
  		kfree(iter);
5c0ef6d02   Kay Sievers   block: drop refer...
697
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  }
def4e38dd   Tejun Heo   block: use class_...
699
  static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  {
def4e38dd   Tejun Heo   block: use class_...
701
702
703
  	static void *p;
  
  	p = disk_seqf_start(seqf, pos);
243294dae   Tejun Heo   block: fix duplic...
704
  	if (!IS_ERR(p) && p && !*pos)
def4e38dd   Tejun Heo   block: use class_...
705
706
707
708
  		seq_puts(seqf, "major minor  #blocks  name
  
  ");
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  }
cf771cb5a   Tejun Heo   block: make varia...
710
  static int show_partition(struct seq_file *seqf, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
  {
  	struct gendisk *sgp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
713
714
  	struct disk_part_iter piter;
  	struct hd_struct *part;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
  	char buf[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
  	/* Don't show non-partitionable removeable devices or empty devices */
b5d0b9df0   Tejun Heo   block: introduce ...
717
  	if (!get_capacity(sgp) || (!disk_partitionable(sgp) &&
f331c0296   Tejun Heo   block: don't depe...
718
  				   (sgp->flags & GENHD_FL_REMOVABLE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
  		return 0;
  	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
  		return 0;
  
  	/* show the full disk and all non-0 size partitions of it */
074a7aca7   Tejun Heo   block: move stats...
724
  	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
725
  	while ((part = disk_part_iter_next(&piter)))
1f0142905   Tejun Heo   block: adjust for...
726
727
  		seq_printf(seqf, "%4d  %7d %10llu %s
  ",
f331c0296   Tejun Heo   block: don't depe...
728
729
730
  			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
  			   (unsigned long long)part->nr_sects >> 1,
  			   disk_name(sgp, part->partno, buf));
e71bf0d0e   Tejun Heo   block: fix disk->...
731
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
  
  	return 0;
  }
f500975a3   Alexey Dobriyan   proc: move rest o...
735
  static const struct seq_operations partitions_op = {
def4e38dd   Tejun Heo   block: use class_...
736
737
738
  	.start	= show_partition_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
edfaa7c36   Kay Sievers   Driver core: conv...
739
  	.show	= show_partition
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
741
742
743
744
745
746
747
748
749
750
751
752
  
  static int partitions_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &partitions_op);
  }
  
  static const struct file_operations proc_partitions_operations = {
  	.open		= partitions_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  #endif
cf771cb5a   Tejun Heo   block: make varia...
754
  static struct kobject *base_probe(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  {
edfaa7c36   Kay Sievers   Driver core: conv...
756
  	if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  		/* Make old-style 2.4 aliases work */
edfaa7c36   Kay Sievers   Driver core: conv...
758
  		request_module("block-major-%d", MAJOR(devt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
763
  	return NULL;
  }
  
  static int __init genhd_device_init(void)
  {
e105b8bfc   Dan Williams   sysfs: add /sys/d...
764
765
766
767
  	int error;
  
  	block_class.dev_kobj = sysfs_dev_block_kobj;
  	error = class_register(&block_class);
ee27a558a   Roland McGrath   genhd must_check ...
768
769
  	if (unlikely(error))
  		return error;
edfaa7c36   Kay Sievers   Driver core: conv...
770
  	bdev_map = kobj_map_init(base_probe, &block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	blk_dev_init();
edfaa7c36   Kay Sievers   Driver core: conv...
772

561ec68e4   Zhang, Yanmin   block: fix boot f...
773
  	register_blkdev(BLOCK_EXT_MAJOR, "blkext");
edfaa7c36   Kay Sievers   Driver core: conv...
774
775
776
777
  #ifndef CONFIG_SYSFS_DEPRECATED
  	/* create top-level block dir */
  	block_depr = kobject_create_and_add("block", NULL);
  #endif
830d3cfb1   Greg Kroah-Hartman   kset: convert blo...
778
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
  }
  
  subsys_initcall(genhd_device_init);
edfaa7c36   Kay Sievers   Driver core: conv...
782
783
  static ssize_t disk_range_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  {
edfaa7c36   Kay Sievers   Driver core: conv...
785
  	struct gendisk *disk = dev_to_disk(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786

edfaa7c36   Kay Sievers   Driver core: conv...
787
788
  	return sprintf(buf, "%d
  ", disk->minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  }
1f0142905   Tejun Heo   block: adjust for...
790
791
792
793
  static ssize_t disk_ext_range_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
b5d0b9df0   Tejun Heo   block: introduce ...
794
795
  	return sprintf(buf, "%d
  ", disk_max_parts(disk));
1f0142905   Tejun Heo   block: adjust for...
796
  }
edfaa7c36   Kay Sievers   Driver core: conv...
797
798
  static ssize_t disk_removable_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
a7fd67062   Kay Sievers   [PATCH] add sysfs...
799
  {
edfaa7c36   Kay Sievers   Driver core: conv...
800
  	struct gendisk *disk = dev_to_disk(dev);
a7fd67062   Kay Sievers   [PATCH] add sysfs...
801

edfaa7c36   Kay Sievers   Driver core: conv...
802
803
804
  	return sprintf(buf, "%d
  ",
  		       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
a7fd67062   Kay Sievers   [PATCH] add sysfs...
805
  }
1c9ce5276   Kay Sievers   block: export "ro...
806
807
808
809
  static ssize_t disk_ro_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
b7db9956e   Tejun Heo   block: move polic...
810
811
  	return sprintf(buf, "%d
  ", get_disk_ro(disk) ? 1 : 0);
1c9ce5276   Kay Sievers   block: export "ro...
812
  }
edfaa7c36   Kay Sievers   Driver core: conv...
813
814
  static ssize_t disk_capability_show(struct device *dev,
  				    struct device_attribute *attr, char *buf)
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
815
  {
edfaa7c36   Kay Sievers   Driver core: conv...
816
817
818
819
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%x
  ", disk->flags);
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
820
  }
edfaa7c36   Kay Sievers   Driver core: conv...
821

c72758f33   Martin K. Petersen   block: Export I/O...
822
823
824
825
826
827
828
829
830
  static ssize_t disk_alignment_offset_show(struct device *dev,
  					  struct device_attribute *attr,
  					  char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%d
  ", queue_alignment_offset(disk->queue));
  }
86b372814   Martin K. Petersen   block: Expose dis...
831
832
833
834
835
836
837
838
839
  static ssize_t disk_discard_alignment_show(struct device *dev,
  					   struct device_attribute *attr,
  					   char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%u
  ", queue_discard_alignment(disk->queue));
  }
edfaa7c36   Kay Sievers   Driver core: conv...
840
  static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
1f0142905   Tejun Heo   block: adjust for...
841
  static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
edfaa7c36   Kay Sievers   Driver core: conv...
842
  static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
1c9ce5276   Kay Sievers   block: export "ro...
843
  static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
e56105214   Tejun Heo   block: unify sysf...
844
  static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
c72758f33   Martin K. Petersen   block: Export I/O...
845
  static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
86b372814   Martin K. Petersen   block: Expose dis...
846
847
  static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show,
  		   NULL);
edfaa7c36   Kay Sievers   Driver core: conv...
848
  static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
074a7aca7   Tejun Heo   block: move stats...
849
  static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
316d315bf   Nikanth Karthikesan   block: Seperate r...
850
  static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
851
  #ifdef CONFIG_FAIL_MAKE_REQUEST
edfaa7c36   Kay Sievers   Driver core: conv...
852
  static struct device_attribute dev_attr_fail =
eddb2e26b   Tejun Heo   block: kill GENHD...
853
  	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
854
  #endif
581d4e28d   Jens Axboe   block: add fault ...
855
856
857
858
859
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  static struct device_attribute dev_attr_fail_timeout =
  	__ATTR(io-timeout-fail,  S_IRUGO|S_IWUSR, part_timeout_show,
  		part_timeout_store);
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
860
861
862
  
  static struct attribute *disk_attrs[] = {
  	&dev_attr_range.attr,
1f0142905   Tejun Heo   block: adjust for...
863
  	&dev_attr_ext_range.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
864
  	&dev_attr_removable.attr,
1c9ce5276   Kay Sievers   block: export "ro...
865
  	&dev_attr_ro.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
866
  	&dev_attr_size.attr,
c72758f33   Martin K. Petersen   block: Export I/O...
867
  	&dev_attr_alignment_offset.attr,
86b372814   Martin K. Petersen   block: Expose dis...
868
  	&dev_attr_discard_alignment.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
869
870
  	&dev_attr_capability.attr,
  	&dev_attr_stat.attr,
316d315bf   Nikanth Karthikesan   block: Seperate r...
871
  	&dev_attr_inflight.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
872
873
874
  #ifdef CONFIG_FAIL_MAKE_REQUEST
  	&dev_attr_fail.attr,
  #endif
581d4e28d   Jens Axboe   block: add fault ...
875
876
877
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  	&dev_attr_fail_timeout.attr,
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
878
879
880
881
882
883
  	NULL
  };
  
  static struct attribute_group disk_attr_group = {
  	.attrs = disk_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
884
  static const struct attribute_group *disk_attr_groups[] = {
edfaa7c36   Kay Sievers   Driver core: conv...
885
886
  	&disk_attr_group,
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  };
540eed563   Tejun Heo   block: make parti...
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  static void disk_free_ptbl_rcu_cb(struct rcu_head *head)
  {
  	struct disk_part_tbl *ptbl =
  		container_of(head, struct disk_part_tbl, rcu_head);
  
  	kfree(ptbl);
  }
  
  /**
   * disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way
   * @disk: disk to replace part_tbl for
   * @new_ptbl: new part_tbl to install
   *
   * Replace disk->part_tbl with @new_ptbl in RCU-safe way.  The
   * original ptbl is freed using RCU callback.
   *
   * LOCKING:
   * Matching bd_mutx locked.
   */
  static void disk_replace_part_tbl(struct gendisk *disk,
  				  struct disk_part_tbl *new_ptbl)
  {
  	struct disk_part_tbl *old_ptbl = disk->part_tbl;
  
  	rcu_assign_pointer(disk->part_tbl, new_ptbl);
a6f23657d   Jens Axboe   block: add one-hi...
913
914
915
  
  	if (old_ptbl) {
  		rcu_assign_pointer(old_ptbl->last_lookup, NULL);
540eed563   Tejun Heo   block: make parti...
916
  		call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
a6f23657d   Jens Axboe   block: add one-hi...
917
  	}
540eed563   Tejun Heo   block: make parti...
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
  }
  
  /**
   * disk_expand_part_tbl - expand disk->part_tbl
   * @disk: disk to expand part_tbl for
   * @partno: expand such that this partno can fit in
   *
   * Expand disk->part_tbl such that @partno can fit in.  disk->part_tbl
   * uses RCU to allow unlocked dereferencing for stats and other stuff.
   *
   * LOCKING:
   * Matching bd_mutex locked, might sleep.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  int disk_expand_part_tbl(struct gendisk *disk, int partno)
  {
  	struct disk_part_tbl *old_ptbl = disk->part_tbl;
  	struct disk_part_tbl *new_ptbl;
  	int len = old_ptbl ? old_ptbl->len : 0;
  	int target = partno + 1;
  	size_t size;
  	int i;
  
  	/* disk_max_parts() is zero during initialization, ignore if so */
  	if (disk_max_parts(disk) && target > disk_max_parts(disk))
  		return -EINVAL;
  
  	if (target <= len)
  		return 0;
  
  	size = sizeof(*new_ptbl) + target * sizeof(new_ptbl->part[0]);
  	new_ptbl = kzalloc_node(size, GFP_KERNEL, disk->node_id);
  	if (!new_ptbl)
  		return -ENOMEM;
  
  	INIT_RCU_HEAD(&new_ptbl->rcu_head);
  	new_ptbl->len = target;
  
  	for (i = 0; i < len; i++)
  		rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]);
  
  	disk_replace_part_tbl(disk, new_ptbl);
  	return 0;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
964
  static void disk_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  {
edfaa7c36   Kay Sievers   Driver core: conv...
966
  	struct gendisk *disk = dev_to_disk(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  	kfree(disk->random);
540eed563   Tejun Heo   block: make parti...
968
  	disk_replace_part_tbl(disk, NULL);
074a7aca7   Tejun Heo   block: move stats...
969
  	free_part_stats(&disk->part0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
  	kfree(disk);
  }
edfaa7c36   Kay Sievers   Driver core: conv...
972
973
  struct class block_class = {
  	.name		= "block",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  };
e454cea20   Kay Sievers   Driver-Core: exte...
975
  static char *block_devnode(struct device *dev, mode_t *mode)
b03f38b68   Kay Sievers   Driver Core: bloc...
976
977
  {
  	struct gendisk *disk = dev_to_disk(dev);
e454cea20   Kay Sievers   Driver-Core: exte...
978
979
  	if (disk->devnode)
  		return disk->devnode(disk, mode);
b03f38b68   Kay Sievers   Driver Core: bloc...
980
981
  	return NULL;
  }
1826eadfc   Adrian Bunk   block/genhd.c: cl...
982
  static struct device_type disk_type = {
edfaa7c36   Kay Sievers   Driver core: conv...
983
984
985
  	.name		= "disk",
  	.groups		= disk_attr_groups,
  	.release	= disk_release,
e454cea20   Kay Sievers   Driver-Core: exte...
986
  	.devnode	= block_devnode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  };
a6e2ba887   Randy Dunlap   block: make /proc...
988
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
989
990
991
992
993
994
995
996
  /*
   * aggregate disk stat collector.  Uses the same stats that the sysfs
   * entries do, above, but makes them available through one seq_file.
   *
   * The output looks suspiciously like /proc/partitions with a bunch of
   * extra fields.
   */
  static int diskstats_show(struct seq_file *seqf, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
  {
  	struct gendisk *gp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
999
1000
  	struct disk_part_iter piter;
  	struct hd_struct *hd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  	char buf[BDEVNAME_SIZE];
c99590591   Tejun Heo   block: fix diskst...
1002
  	int cpu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
  
  	/*
ed9e19823   Tejun Heo   block: implement ...
1005
  	if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
cf771cb5a   Tejun Heo   block: make varia...
1006
  		seq_puts(seqf,	"major minor name"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
1012
1013
  				"     rio rmerge rsect ruse wio wmerge "
  				"wsect wuse running use aveq"
  				"
  
  ");
  	*/
   
71982a409   Tejun Heo   block: include em...
1014
  	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1015
  	while ((hd = disk_part_iter_next(&piter))) {
074a7aca7   Tejun Heo   block: move stats...
1016
  		cpu = part_stat_lock();
c99590591   Tejun Heo   block: fix diskst...
1017
  		part_round_stats(cpu, hd);
074a7aca7   Tejun Heo   block: move stats...
1018
  		part_stat_unlock();
1f0142905   Tejun Heo   block: adjust for...
1019
  		seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
28f39d553   Jerome Marchand   Enhanced partitio...
1020
1021
  			   "%u %lu %lu %llu %u %u %u %u
  ",
f331c0296   Tejun Heo   block: don't depe...
1022
1023
  			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
  			   disk_name(gp, hd->partno, buf),
28f39d553   Jerome Marchand   Enhanced partitio...
1024
1025
1026
1027
1028
1029
1030
1031
  			   part_stat_read(hd, ios[0]),
  			   part_stat_read(hd, merges[0]),
  			   (unsigned long long)part_stat_read(hd, sectors[0]),
  			   jiffies_to_msecs(part_stat_read(hd, ticks[0])),
  			   part_stat_read(hd, ios[1]),
  			   part_stat_read(hd, merges[1]),
  			   (unsigned long long)part_stat_read(hd, sectors[1]),
  			   jiffies_to_msecs(part_stat_read(hd, ticks[1])),
316d315bf   Nikanth Karthikesan   block: Seperate r...
1032
  			   part_in_flight(hd),
28f39d553   Jerome Marchand   Enhanced partitio...
1033
1034
1035
  			   jiffies_to_msecs(part_stat_read(hd, io_ticks)),
  			   jiffies_to_msecs(part_stat_read(hd, time_in_queue))
  			);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
  	}
e71bf0d0e   Tejun Heo   block: fix disk->...
1037
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
   
  	return 0;
  }
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1041
  static const struct seq_operations diskstats_op = {
def4e38dd   Tejun Heo   block: use class_...
1042
1043
1044
  	.start	= disk_seqf_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  	.show	= diskstats_show
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
1047

31d85ab28   Alexey Dobriyan   proc: move /proc/...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  static int diskstats_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &diskstats_op);
  }
  
  static const struct file_operations proc_diskstats_operations = {
  	.open		= diskstats_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
1059
1060
  static int __init proc_genhd_init(void)
  {
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1061
  	proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
f500975a3   Alexey Dobriyan   proc: move rest o...
1062
1063
1064
1065
  	proc_create("partitions", 0, NULL, &proc_partitions_operations);
  	return 0;
  }
  module_init(proc_genhd_init);
a6e2ba887   Randy Dunlap   block: make /proc...
1066
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067

8ce7ad7b2   Kristen Carlson Accardi   genhd: send async...
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  static void media_change_notify_thread(struct work_struct *work)
  {
  	struct gendisk *gd = container_of(work, struct gendisk, async_notify);
  	char event[] = "MEDIA_CHANGE=1";
  	char *envp[] = { event, NULL };
  
  	/*
  	 * set enviroment vars to indicate which event this is for
  	 * so that user space will know to go check the media status.
  	 */
ed9e19823   Tejun Heo   block: implement ...
1078
  	kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
8ce7ad7b2   Kristen Carlson Accardi   genhd: send async...
1079
1080
  	put_device(gd->driverfs_dev);
  }
1826eadfc   Adrian Bunk   block/genhd.c: cl...
1081
  #if 0
8ce7ad7b2   Kristen Carlson Accardi   genhd: send async...
1082
1083
1084
1085
1086
1087
  void genhd_media_change_notify(struct gendisk *disk)
  {
  	get_device(disk->driverfs_dev);
  	schedule_work(&disk->async_notify);
  }
  EXPORT_SYMBOL_GPL(genhd_media_change_notify);
1826eadfc   Adrian Bunk   block/genhd.c: cl...
1088
  #endif  /*  0  */
8ce7ad7b2   Kristen Carlson Accardi   genhd: send async...
1089

cf771cb5a   Tejun Heo   block: make varia...
1090
  dev_t blk_lookup_devt(const char *name, int partno)
a142be856   Greg Kroah-Hartman   block: make blk_l...
1091
  {
def4e38dd   Tejun Heo   block: use class_...
1092
1093
1094
  	dev_t devt = MKDEV(0, 0);
  	struct class_dev_iter iter;
  	struct device *dev;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1095

def4e38dd   Tejun Heo   block: use class_...
1096
1097
  	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
  	while ((dev = class_dev_iter_next(&iter))) {
a142be856   Greg Kroah-Hartman   block: make blk_l...
1098
  		struct gendisk *disk = dev_to_disk(dev);
548b10eb2   Tejun Heo   block: move __dev...
1099
  		struct hd_struct *part;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1100

3ada8b7e9   Kay Sievers   block: struct dev...
1101
  		if (strcmp(dev_name(dev), name))
f331c0296   Tejun Heo   block: don't depe...
1102
  			continue;
f331c0296   Tejun Heo   block: don't depe...
1103

41b8c853a   Neil Brown   block: fix bootin...
1104
1105
1106
1107
1108
1109
1110
1111
  		if (partno < disk->minors) {
  			/* We need to return the right devno, even
  			 * if the partition doesn't exist yet.
  			 */
  			devt = MKDEV(MAJOR(dev->devt),
  				     MINOR(dev->devt) + partno);
  			break;
  		}
548b10eb2   Tejun Heo   block: move __dev...
1112
  		part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
1113
  		if (part) {
f331c0296   Tejun Heo   block: don't depe...
1114
  			devt = part_devt(part);
e71bf0d0e   Tejun Heo   block: fix disk->...
1115
  			disk_put_part(part);
548b10eb2   Tejun Heo   block: move __dev...
1116
  			break;
def4e38dd   Tejun Heo   block: use class_...
1117
  		}
548b10eb2   Tejun Heo   block: move __dev...
1118
  		disk_put_part(part);
5c0ef6d02   Kay Sievers   block: drop refer...
1119
  	}
def4e38dd   Tejun Heo   block: use class_...
1120
  	class_dev_iter_exit(&iter);
edfaa7c36   Kay Sievers   Driver core: conv...
1121
1122
  	return devt;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1123
  EXPORT_SYMBOL(blk_lookup_devt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
  struct gendisk *alloc_disk(int minors)
  {
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1126
1127
  	return alloc_disk_node(minors, -1);
  }
689d6fac4   Tejun Heo   block: replace @e...
1128
  EXPORT_SYMBOL(alloc_disk);
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1129
1130
1131
1132
  
  struct gendisk *alloc_disk_node(int minors, int node_id)
  {
  	struct gendisk *disk;
94f6030ca   Christoph Lameter   Slab allocators: ...
1133
1134
  	disk = kmalloc_node(sizeof(struct gendisk),
  				GFP_KERNEL | __GFP_ZERO, node_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  	if (disk) {
074a7aca7   Tejun Heo   block: move stats...
1136
  		if (!init_part_stats(&disk->part0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
  			kfree(disk);
  			return NULL;
  		}
bf91db18a   Cheng Renquan   block: set disk->...
1140
  		disk->node_id = node_id;
540eed563   Tejun Heo   block: make parti...
1141
1142
  		if (disk_expand_part_tbl(disk, 0)) {
  			free_part_stats(&disk->part0);
b5d0b9df0   Tejun Heo   block: introduce ...
1143
1144
  			kfree(disk);
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  		}
540eed563   Tejun Heo   block: make parti...
1146
  		disk->part_tbl->part[0] = &disk->part0;
b5d0b9df0   Tejun Heo   block: introduce ...
1147

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
  		disk->minors = minors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
  		rand_initialize_disk(disk);
ed9e19823   Tejun Heo   block: implement ...
1150
1151
1152
  		disk_to_dev(disk)->class = &block_class;
  		disk_to_dev(disk)->type = &disk_type;
  		device_initialize(disk_to_dev(disk));
8ce7ad7b2   Kristen Carlson Accardi   genhd: send async...
1153
1154
  		INIT_WORK(&disk->async_notify,
  			media_change_notify_thread);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
  	}
  	return disk;
  }
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1158
  EXPORT_SYMBOL(alloc_disk_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  
  struct kobject *get_disk(struct gendisk *disk)
  {
  	struct module *owner;
  	struct kobject *kobj;
  
  	if (!disk->fops)
  		return NULL;
  	owner = disk->fops->owner;
  	if (owner && !try_module_get(owner))
  		return NULL;
ed9e19823   Tejun Heo   block: implement ...
1170
  	kobj = kobject_get(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  	if (kobj == NULL) {
  		module_put(owner);
  		return NULL;
  	}
  	return kobj;
  
  }
  
  EXPORT_SYMBOL(get_disk);
  
  void put_disk(struct gendisk *disk)
  {
  	if (disk)
ed9e19823   Tejun Heo   block: implement ...
1184
  		kobject_put(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
  }
  
  EXPORT_SYMBOL(put_disk);
e3264a4d7   Hannes Reinecke   Send uevents for ...
1188
1189
1190
1191
1192
1193
1194
1195
1196
  static void set_disk_ro_uevent(struct gendisk *gd, int ro)
  {
  	char event[] = "DISK_RO=1";
  	char *envp[] = { event, NULL };
  
  	if (!ro)
  		event[8] = '0';
  	kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
  void set_device_ro(struct block_device *bdev, int flag)
  {
b7db9956e   Tejun Heo   block: move polic...
1199
  	bdev->bd_part->policy = flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
1203
1204
1205
  }
  
  EXPORT_SYMBOL(set_device_ro);
  
  void set_disk_ro(struct gendisk *disk, int flag)
  {
e71bf0d0e   Tejun Heo   block: fix disk->...
1206
1207
  	struct disk_part_iter piter;
  	struct hd_struct *part;
e3264a4d7   Hannes Reinecke   Send uevents for ...
1208
1209
1210
1211
1212
1213
  	if (disk->part0.policy != flag) {
  		set_disk_ro_uevent(disk, flag);
  		disk->part0.policy = flag;
  	}
  
  	disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
e71bf0d0e   Tejun Heo   block: fix disk->...
1214
1215
1216
  	while ((part = disk_part_iter_next(&piter)))
  		part->policy = flag;
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
1220
1221
1222
1223
1224
  }
  
  EXPORT_SYMBOL(set_disk_ro);
  
  int bdev_read_only(struct block_device *bdev)
  {
  	if (!bdev)
  		return 0;
b7db9956e   Tejun Heo   block: move polic...
1225
  	return bdev->bd_part->policy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
1227
1228
  }
  
  EXPORT_SYMBOL(bdev_read_only);
cf771cb5a   Tejun Heo   block: make varia...
1229
  int invalidate_partition(struct gendisk *disk, int partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
  {
  	int res = 0;
cf771cb5a   Tejun Heo   block: make varia...
1232
  	struct block_device *bdev = bdget_disk(disk, partno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  	if (bdev) {
2ef41634d   Christoph Hellwig   [PATCH] remove do...
1234
1235
  		fsync_bdev(bdev);
  		res = __invalidate_device(bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
1238
1239
1240
1241
  		bdput(bdev);
  	}
  	return res;
  }
  
  EXPORT_SYMBOL(invalidate_partition);