Blame view

block/genhd.c 45 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
  #include <linux/kernel.h>
  #include <linux/blkdev.h>
66114cad6   Tejun Heo   writeback: separa...
10
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #include <linux/init.h>
  #include <linux/spinlock.h>
f500975a3   Alexey Dobriyan   proc: move rest o...
13
  #include <linux/proc_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
  #include <linux/seq_file.h>
  #include <linux/slab.h>
  #include <linux/kmod.h>
  #include <linux/kobj_map.h>
58383af62   Jes Sorensen   [PATCH] kobj_map ...
18
  #include <linux/mutex.h>
bcce3de1b   Tejun Heo   block: implement ...
19
  #include <linux/idr.h>
77ea887e4   Tejun Heo   implement in-kern...
20
  #include <linux/log2.h>
25e823c8c   Ming Lei   block/genhd.c: ap...
21
  #include <linux/pm_runtime.h>
99e6608c9   Vishal Verma   block: Add badblo...
22
  #include <linux/badblocks.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

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

bcce3de1b   Tejun Heo   block: implement ...
28
  /* for extended dynamic devt allocation, currently only one major is used */
ce23bba84   Tejun Heo   block: fix synchr...
29
  #define NR_EXT_DEVT		(1 << MINORBITS)
bcce3de1b   Tejun Heo   block: implement ...
30

2da78092d   Keith Busch   block: Fix dev_t ...
31
  /* For extended devt allocation.  ext_devt_lock prevents look up
bcce3de1b   Tejun Heo   block: implement ...
32
33
   * results from going away underneath its user.
   */
2da78092d   Keith Busch   block: Fix dev_t ...
34
  static DEFINE_SPINLOCK(ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
35
  static DEFINE_IDR(ext_devt_idr);
1826eadfc   Adrian Bunk   block/genhd.c: cl...
36
  static struct device_type disk_type;
12c2bdb23   Derek Basehore   block: prevent ra...
37
38
  static void disk_check_events(struct disk_events *ev,
  			      unsigned int *clearing_ptr);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
39
  static void disk_alloc_events(struct gendisk *disk);
77ea887e4   Tejun Heo   implement in-kern...
40
41
42
  static void disk_add_events(struct gendisk *disk);
  static void disk_del_events(struct gendisk *disk);
  static void disk_release_events(struct gendisk *disk);
e71bf0d0e   Tejun Heo   block: fix disk->...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  /**
   * 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...
59
60
  	struct hd_struct *part = NULL;
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
61

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

e71bf0d0e   Tejun Heo   block: fix disk->...
65
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
66
67
68
69
70
71
72
  
  	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->...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  	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...
93
94
95
96
  	struct disk_part_tbl *ptbl;
  
  	rcu_read_lock();
  	ptbl = rcu_dereference(disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
97
98
99
100
  	piter->disk = disk;
  	piter->part = NULL;
  
  	if (flags & DISK_PITER_REVERSE)
540eed563   Tejun Heo   block: make parti...
101
  		piter->idx = ptbl->len - 1;
71982a409   Tejun Heo   block: include em...
102
  	else if (flags & (DISK_PITER_INCL_PART0 | DISK_PITER_INCL_EMPTY_PART0))
e71bf0d0e   Tejun Heo   block: fix disk->...
103
  		piter->idx = 0;
b5d0b9df0   Tejun Heo   block: introduce ...
104
105
  	else
  		piter->idx = 1;
e71bf0d0e   Tejun Heo   block: fix disk->...
106
107
  
  	piter->flags = flags;
540eed563   Tejun Heo   block: make parti...
108
109
  
  	rcu_read_unlock();
e71bf0d0e   Tejun Heo   block: fix disk->...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  }
  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...
124
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
125
126
127
128
129
  	int inc, end;
  
  	/* put the last partition */
  	disk_put_part(piter->part);
  	piter->part = NULL;
540eed563   Tejun Heo   block: make parti...
130
  	/* get part_tbl */
e71bf0d0e   Tejun Heo   block: fix disk->...
131
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
132
  	ptbl = rcu_dereference(piter->disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
133
134
135
136
  
  	/* determine iteration parameters */
  	if (piter->flags & DISK_PITER_REVERSE) {
  		inc = -1;
71982a409   Tejun Heo   block: include em...
137
138
  		if (piter->flags & (DISK_PITER_INCL_PART0 |
  				    DISK_PITER_INCL_EMPTY_PART0))
b5d0b9df0   Tejun Heo   block: introduce ...
139
140
141
  			end = -1;
  		else
  			end = 0;
e71bf0d0e   Tejun Heo   block: fix disk->...
142
143
  	} else {
  		inc = 1;
540eed563   Tejun Heo   block: make parti...
144
  		end = ptbl->len;
e71bf0d0e   Tejun Heo   block: fix disk->...
145
146
147
148
149
  	}
  
  	/* iterate to the next partition */
  	for (; piter->idx != end; piter->idx += inc) {
  		struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
150
  		part = rcu_dereference(ptbl->part[piter->idx]);
e71bf0d0e   Tejun Heo   block: fix disk->...
151
152
  		if (!part)
  			continue;
c83f6bf98   Vivek Goyal   block: add partit...
153
  		if (!part_nr_sects_read(part) &&
71982a409   Tejun Heo   block: include em...
154
155
156
  		    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
  		    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
  		      piter->idx == 0))
e71bf0d0e   Tejun Heo   block: fix disk->...
157
  			continue;
ed9e19823   Tejun Heo   block: implement ...
158
  		get_device(part_to_dev(part));
e71bf0d0e   Tejun Heo   block: fix disk->...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  		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...
185
186
187
  static inline int sector_in_part(struct hd_struct *part, sector_t sector)
  {
  	return part->start_sect <= sector &&
c83f6bf98   Vivek Goyal   block: add partit...
188
  		sector < part->start_sect + part_nr_sects_read(part);
a6f23657d   Jens Axboe   block: add one-hi...
189
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
190
191
192
193
194
195
196
197
198
199
200
201
202
  /**
   * 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...
203
   * Found partition on success, part0 is returned if no partition matches
e71bf0d0e   Tejun Heo   block: fix disk->...
204
205
206
   */
  struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
  {
540eed563   Tejun Heo   block: make parti...
207
  	struct disk_part_tbl *ptbl;
a6f23657d   Jens Axboe   block: add one-hi...
208
  	struct hd_struct *part;
e71bf0d0e   Tejun Heo   block: fix disk->...
209
  	int i;
540eed563   Tejun Heo   block: make parti...
210
  	ptbl = rcu_dereference(disk->part_tbl);
a6f23657d   Jens Axboe   block: add one-hi...
211
212
213
  	part = rcu_dereference(ptbl->last_lookup);
  	if (part && sector_in_part(part, sector))
  		return part;
540eed563   Tejun Heo   block: make parti...
214
  	for (i = 1; i < ptbl->len; i++) {
a6f23657d   Jens Axboe   block: add one-hi...
215
  		part = rcu_dereference(ptbl->part[i]);
e71bf0d0e   Tejun Heo   block: fix disk->...
216

a6f23657d   Jens Axboe   block: add one-hi...
217
218
  		if (part && sector_in_part(part, sector)) {
  			rcu_assign_pointer(ptbl->last_lookup, part);
e71bf0d0e   Tejun Heo   block: fix disk->...
219
  			return part;
a6f23657d   Jens Axboe   block: add one-hi...
220
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
221
  	}
074a7aca7   Tejun Heo   block: move stats...
222
  	return &disk->part0;
e71bf0d0e   Tejun Heo   block: fix disk->...
223
224
  }
  EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
231
232
  /*
   * 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 ...
233
  } *major_names[BLKDEV_MAJOR_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  
  /* index in the above - for now: assume no multimajor ranges */
e61eb2e93   Yang Zhang   fs/block: type si...
236
  static inline int major_to_index(unsigned major)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
238
  	return major % BLKDEV_MAJOR_HASH_SIZE;
7170be5f5   Neil Horman   [PATCH] convert /...
239
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
240
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
241
  void blkdev_show(struct seq_file *seqf, off_t offset)
7170be5f5   Neil Horman   [PATCH] convert /...
242
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
243
  	struct blk_major_name *dp;
7170be5f5   Neil Horman   [PATCH] convert /...
244

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

9e8c0bccd   Márton Németh   block: add docume...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  /**
   * 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
271
272
273
274
  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...
275
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
315
316
317
318
319
320
321
  
  	/* 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...
322
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
  	return ret;
  }
  
  EXPORT_SYMBOL(register_blkdev);
f4480240f   Akinobu Mita   unregister_blkdev...
327
  void unregister_blkdev(unsigned int major, const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
  {
  	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
332

edfaa7c36   Kay Sievers   Driver core: conv...
333
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
  	for (n = &major_names[index]; *n; n = &(*n)->next)
  		if ((*n)->major == major)
  			break;
294462a5c   Akinobu Mita   unregister_blkdev...
337
338
  	if (!*n || strcmp((*n)->name, name)) {
  		WARN_ON(1);
294462a5c   Akinobu Mita   unregister_blkdev...
339
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
  		p = *n;
  		*n = p->next;
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
343
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  	kfree(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
  }
  
  EXPORT_SYMBOL(unregister_blkdev);
  
  static struct kobj_map *bdev_map;
bcce3de1b   Tejun Heo   block: implement ...
350
  /**
870d66561   Tejun Heo   block: implement ...
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
376
377
378
379
380
381
382
   * 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 ...
383
384
   * blk_alloc_devt - allocate a dev_t for a partition
   * @part: partition to allocate dev_t for
bcce3de1b   Tejun Heo   block: implement ...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
   * @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);
bab998d62   Tejun Heo   block: convert to...
399
  	int idx;
bcce3de1b   Tejun Heo   block: implement ...
400
401
402
403
404
405
406
407
  
  	/* in consecutive minor range? */
  	if (part->partno < disk->minors) {
  		*devt = MKDEV(disk->major, disk->first_minor + part->partno);
  		return 0;
  	}
  
  	/* allocate ext devt */
2da78092d   Keith Busch   block: Fix dev_t ...
408
  	idr_preload(GFP_KERNEL);
4d66e5e9b   Dan Williams   block: fix ext_de...
409
  	spin_lock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
410
  	idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
4d66e5e9b   Dan Williams   block: fix ext_de...
411
  	spin_unlock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
412
413
  
  	idr_preload_end();
bab998d62   Tejun Heo   block: convert to...
414
415
  	if (idx < 0)
  		return idx == -ENOSPC ? -EBUSY : idx;
bcce3de1b   Tejun Heo   block: implement ...
416

870d66561   Tejun Heo   block: implement ...
417
  	*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
bcce3de1b   Tejun Heo   block: implement ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  	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)
  {
bcce3de1b   Tejun Heo   block: implement ...
432
433
434
435
  	if (devt == MKDEV(0, 0))
  		return;
  
  	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
4d66e5e9b   Dan Williams   block: fix ext_de...
436
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
437
  		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
4d66e5e9b   Dan Williams   block: fix ext_de...
438
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
439
440
  	}
  }
1f0142905   Tejun Heo   block: adjust for...
441
442
443
444
445
446
447
448
449
450
451
  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
452
453
454
455
456
  /*
   * 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...
457
  void blk_register_region(dev_t devt, unsigned long range, struct module *module,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
  			 struct kobject *(*probe)(dev_t, int *, void *),
  			 int (*lock)(dev_t, void *), void *data)
  {
edfaa7c36   Kay Sievers   Driver core: conv...
461
  	kobj_map(bdev_map, devt, range, module, probe, lock, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
  }
  
  EXPORT_SYMBOL(blk_register_region);
edfaa7c36   Kay Sievers   Driver core: conv...
465
  void blk_unregister_region(dev_t devt, unsigned long range)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  {
edfaa7c36   Kay Sievers   Driver core: conv...
467
  	kobj_unmap(bdev_map, devt, range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
  }
  
  EXPORT_SYMBOL(blk_unregister_region);
cf771cb5a   Tejun Heo   block: make varia...
471
  static struct kobject *exact_match(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  {
  	struct gendisk *p = data;
edfaa7c36   Kay Sievers   Driver core: conv...
474

ed9e19823   Tejun Heo   block: implement ...
475
  	return &disk_to_dev(p)->kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  }
edfaa7c36   Kay Sievers   Driver core: conv...
477
  static int exact_lock(dev_t devt, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
482
483
484
  {
  	struct gendisk *p = data;
  
  	if (!get_disk(p))
  		return -1;
  	return 0;
  }
e63a46bef   Dan Williams   block: introduce ...
485
  static void register_disk(struct device *parent, struct gendisk *disk)
d2bf1b672   Tejun Heo   block: move regis...
486
487
488
489
490
491
  {
  	struct device *ddev = disk_to_dev(disk);
  	struct block_device *bdev;
  	struct disk_part_iter piter;
  	struct hd_struct *part;
  	int err;
e63a46bef   Dan Williams   block: introduce ...
492
  	ddev->parent = parent;
d2bf1b672   Tejun Heo   block: move regis...
493

ffc8b3086   Kees Cook   block: do not pas...
494
  	dev_set_name(ddev, "%s", disk->disk_name);
d2bf1b672   Tejun Heo   block: move regis...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  
  	/* delay uevents, until we scanned partition table */
  	dev_set_uevent_suppress(ddev, 1);
  
  	if (device_add(ddev))
  		return;
  	if (!sysfs_deprecated) {
  		err = sysfs_create_link(block_depr, &ddev->kobj,
  					kobject_name(&ddev->kobj));
  		if (err) {
  			device_del(ddev);
  			return;
  		}
  	}
25e823c8c   Ming Lei   block/genhd.c: ap...
509
510
511
512
513
514
515
  
  	/*
  	 * avoid probable deadlock caused by allocating memory with
  	 * GFP_KERNEL in runtime_resume callback of its all ancestor
  	 * devices
  	 */
  	pm_runtime_set_memalloc_noio(ddev, true);
d2bf1b672   Tejun Heo   block: move regis...
516
517
518
519
  	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
  	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
  
  	/* No minors to use for partitions */
d27769ec3   Tejun Heo   block: add GENHD_...
520
  	if (!disk_part_scan_enabled(disk))
d2bf1b672   Tejun Heo   block: move regis...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  		goto exit;
  
  	/* No such device (e.g., media were just removed) */
  	if (!get_capacity(disk))
  		goto exit;
  
  	bdev = bdget_disk(disk, 0);
  	if (!bdev)
  		goto exit;
  
  	bdev->bd_invalidated = 1;
  	err = blkdev_get(bdev, FMODE_READ, NULL);
  	if (err < 0)
  		goto exit;
  	blkdev_put(bdev, FMODE_READ);
  
  exit:
  	/* announce disk after possible partitions are created */
  	dev_set_uevent_suppress(ddev, 0);
  	kobject_uevent(&ddev->kobj, KOBJ_ADD);
  
  	/* announce possible partitions */
  	disk_part_iter_init(&piter, disk, 0);
  	while ((part = disk_part_iter_next(&piter)))
  		kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
  	disk_part_iter_exit(&piter);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  /**
e63a46bef   Dan Williams   block: introduce ...
549
550
   * device_add_disk - add partitioning information to kernel list
   * @parent: parent device for the disk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
   * @disk: per-device partitioning information
   *
   * This function registers the partitioning information in @disk
   * with the kernel.
3e1a7ff8a   Tejun Heo   block: allow disk...
555
556
   *
   * FIXME: error handling
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
   */
e63a46bef   Dan Williams   block: introduce ...
558
  void device_add_disk(struct device *parent, struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  {
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
560
  	struct backing_dev_info *bdi;
3e1a7ff8a   Tejun Heo   block: allow disk...
561
  	dev_t devt;
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
562
  	int retval;
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
563

3e1a7ff8a   Tejun Heo   block: allow disk...
564
565
566
567
568
569
  	/* 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
570
  	disk->flags |= GENHD_FL_UP;
3e1a7ff8a   Tejun Heo   block: allow disk...
571
572
573
574
575
576
577
578
579
580
581
582
583
  
  	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);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
584
  	disk_alloc_events(disk);
9f5e48655   Wanlong Gao   block:remove some...
585
  	/* Register BDI before referencing it from bdev */
01ea50638   Signed-off-by: Jan Kara   block: Fix race d...
586
  	bdi = &disk->queue->backing_dev_info;
df08c32ce   Dan Williams   block: fix bdi vs...
587
  	bdi_register_owner(bdi, disk_to_dev(disk));
01ea50638   Signed-off-by: Jan Kara   block: Fix race d...
588

f331c0296   Tejun Heo   block: don't depe...
589
590
  	blk_register_region(disk_devt(disk), disk->minors, NULL,
  			    exact_match, exact_lock, disk);
e63a46bef   Dan Williams   block: introduce ...
591
  	register_disk(parent, disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  	blk_register_queue(disk);
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
593

523e1d399   Tejun Heo   block: make gendi...
594
595
596
597
  	/*
  	 * Take an extra ref on queue which will be put on disk_release()
  	 * so that it sticks around as long as @disk is there.
  	 */
09ac46c42   Tejun Heo   block: misc updat...
598
  	WARN_ON_ONCE(!blk_get_queue(disk->queue));
523e1d399   Tejun Heo   block: make gendi...
599

ed9e19823   Tejun Heo   block: implement ...
600
601
  	retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
  				   "bdi");
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
602
  	WARN_ON(retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603

77ea887e4   Tejun Heo   implement in-kern...
604
  	disk_add_events(disk);
25520d55c   Martin K. Petersen   block: Inline blk...
605
  	blk_integrity_add(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  }
e63a46bef   Dan Williams   block: introduce ...
607
  EXPORT_SYMBOL(device_add_disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608

d2bf1b672   Tejun Heo   block: move regis...
609
  void del_gendisk(struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  {
d2bf1b672   Tejun Heo   block: move regis...
611
612
  	struct disk_part_iter piter;
  	struct hd_struct *part;
25520d55c   Martin K. Petersen   block: Inline blk...
613
  	blk_integrity_del(disk);
77ea887e4   Tejun Heo   implement in-kern...
614
  	disk_del_events(disk);
d2bf1b672   Tejun Heo   block: move regis...
615
616
617
618
619
620
621
622
623
624
  	/* invalidate stuff */
  	disk_part_iter_init(&piter, disk,
  			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
  	while ((part = disk_part_iter_next(&piter))) {
  		invalidate_partition(disk, part->partno);
  		delete_partition(disk, part->partno);
  	}
  	disk_part_iter_exit(&piter);
  
  	invalidate_partition(disk, 0);
d2bf1b672   Tejun Heo   block: move regis...
625
626
  	set_capacity(disk, 0);
  	disk->flags &= ~GENHD_FL_UP;
ed9e19823   Tejun Heo   block: implement ...
627
  	sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  	blk_unregister_queue(disk);
f331c0296   Tejun Heo   block: don't depe...
629
  	blk_unregister_region(disk_devt(disk), disk->minors);
d2bf1b672   Tejun Heo   block: move regis...
630
631
632
633
634
635
  
  	part_stat_set_all(&disk->part0, 0);
  	disk->part0.stamp = 0;
  
  	kobject_put(disk->part0.holder_dir);
  	kobject_put(disk->slave_dir);
d2bf1b672   Tejun Heo   block: move regis...
636
637
  	if (!sysfs_deprecated)
  		sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
25e823c8c   Ming Lei   block/genhd.c: ap...
638
  	pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
d2bf1b672   Tejun Heo   block: move regis...
639
  	device_del(disk_to_dev(disk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  }
d2bf1b672   Tejun Heo   block: move regis...
641
  EXPORT_SYMBOL(del_gendisk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642

99e6608c9   Vishal Verma   block: Add badblo...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  /* sysfs access to bad-blocks list. */
  static ssize_t disk_badblocks_show(struct device *dev,
  					struct device_attribute *attr,
  					char *page)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	if (!disk->bb)
  		return sprintf(page, "
  ");
  
  	return badblocks_show(disk->bb, page, 0);
  }
  
  static ssize_t disk_badblocks_store(struct device *dev,
  					struct device_attribute *attr,
  					const char *page, size_t len)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	if (!disk->bb)
  		return -ENXIO;
  
  	return badblocks_store(disk->bb, page, len, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  /**
   * get_gendisk - get partitioning information for a given device
710027a48   Randy Dunlap   Add some block/ s...
670
   * @devt: device to get partitioning information for
496aa8a98   Randy Dunlap   block: fix curren...
671
   * @partno: returned partition index
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
   *
   * This function gets the structure containing partitioning
710027a48   Randy Dunlap   Add some block/ s...
674
   * information for the given device @devt.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
   */
cf771cb5a   Tejun Heo   block: make varia...
676
  struct gendisk *get_gendisk(dev_t devt, int *partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  {
bcce3de1b   Tejun Heo   block: implement ...
678
679
680
681
682
683
684
685
686
687
  	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;
4d66e5e9b   Dan Williams   block: fix ext_de...
688
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
689
  		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
bcce3de1b   Tejun Heo   block: implement ...
690
691
692
693
  		if (part && get_disk(part_to_disk(part))) {
  			*partno = part->partno;
  			disk = part_to_disk(part);
  		}
4d66e5e9b   Dan Williams   block: fix ext_de...
694
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
695
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
696

bcce3de1b   Tejun Heo   block: implement ...
697
  	return disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  }
b6ac23af2   Divyesh Shah   blkio: fix for mo...
699
  EXPORT_SYMBOL(get_gendisk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

f331c0296   Tejun Heo   block: don't depe...
701
702
703
704
705
706
707
708
709
710
711
712
713
  /**
   * 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...
714
  struct block_device *bdget_disk(struct gendisk *disk, int partno)
f331c0296   Tejun Heo   block: don't depe...
715
  {
548b10eb2   Tejun Heo   block: move __dev...
716
717
  	struct hd_struct *part;
  	struct block_device *bdev = NULL;
f331c0296   Tejun Heo   block: don't depe...
718

548b10eb2   Tejun Heo   block: move __dev...
719
  	part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
720
  	if (part)
548b10eb2   Tejun Heo   block: move __dev...
721
722
  		bdev = bdget(part_devt(part));
  	disk_put_part(part);
f331c0296   Tejun Heo   block: don't depe...
723

548b10eb2   Tejun Heo   block: move __dev...
724
  	return bdev;
f331c0296   Tejun Heo   block: don't depe...
725
726
  }
  EXPORT_SYMBOL(bdget_disk);
dd2a345f8   Dave Gilbert   Display all possi...
727
  /*
5c6f35c5e   Greg Kroah-Hartman   block: make print...
728
729
730
731
732
733
   * 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_...
734
735
736
737
738
739
  	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->...
740
741
  		struct disk_part_iter piter;
  		struct hd_struct *part;
1f0142905   Tejun Heo   block: adjust for...
742
743
  		char name_buf[BDEVNAME_SIZE];
  		char devt_buf[BDEVT_SIZE];
def4e38dd   Tejun Heo   block: use class_...
744
745
746
  
  		/*
  		 * Don't show empty devices or things that have been
25985edce   Lucas De Marchi   Fix common misspe...
747
  		 * suppressed
def4e38dd   Tejun Heo   block: use class_...
748
749
750
751
752
753
754
755
756
757
  		 */
  		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...
758
759
760
  		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_...
761

b5af921ec   Will Drewry   init: add support...
762
  			printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
1f0142905   Tejun Heo   block: adjust for...
763
  			       bdevt_str(part_devt(part), devt_buf),
c83f6bf98   Vivek Goyal   block: add partit...
764
765
  			       (unsigned long long)part_nr_sects_read(part) >> 1
  			       , disk_name(disk, part->partno, name_buf),
1ad7e8994   Stephen Warren   block: store part...
766
  			       part->info ? part->info->uuid : "");
074a7aca7   Tejun Heo   block: move stats...
767
  			if (is_part0) {
52c44d93c   Dan Williams   block: remove ->d...
768
  				if (dev->parent && dev->parent->driver)
074a7aca7   Tejun Heo   block: move stats...
769
770
  					printk(" driver: %s
  ",
52c44d93c   Dan Williams   block: remove ->d...
771
  					      dev->parent->driver->name);
074a7aca7   Tejun Heo   block: move stats...
772
773
774
775
776
777
778
  				else
  					printk(" (driver?)
  ");
  			} else
  				printk("
  ");
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
779
  		disk_part_iter_exit(&piter);
def4e38dd   Tejun Heo   block: use class_...
780
781
  	}
  	class_dev_iter_exit(&iter);
dd2a345f8   Dave Gilbert   Display all possi...
782
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  #ifdef CONFIG_PROC_FS
  /* iterator */
def4e38dd   Tejun Heo   block: use class_...
785
  static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
786
  {
def4e38dd   Tejun Heo   block: use class_...
787
788
789
  	loff_t skip = *pos;
  	struct class_dev_iter *iter;
  	struct device *dev;
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
790

aeb3d3a81   Harvey Harrison   block: kmalloc ar...
791
  	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
def4e38dd   Tejun Heo   block: use class_...
792
793
794
795
796
797
798
799
800
801
802
803
  	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 ...
804
  }
def4e38dd   Tejun Heo   block: use class_...
805
  static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
  {
edfaa7c36   Kay Sievers   Driver core: conv...
807
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808

def4e38dd   Tejun Heo   block: use class_...
809
810
  	(*pos)++;
  	dev = class_dev_iter_next(seqf->private);
2ac3cee52   Tejun Heo   block: don't grab...
811
  	if (dev)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
812
  		return dev_to_disk(dev);
2ac3cee52   Tejun Heo   block: don't grab...
813

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  	return NULL;
  }
def4e38dd   Tejun Heo   block: use class_...
816
  static void disk_seqf_stop(struct seq_file *seqf, void *v)
27f302519   Greg Kroah-Hartman   block: make /proc...
817
  {
def4e38dd   Tejun Heo   block: use class_...
818
  	struct class_dev_iter *iter = seqf->private;
27f302519   Greg Kroah-Hartman   block: make /proc...
819

def4e38dd   Tejun Heo   block: use class_...
820
821
822
823
  	/* stop is called even after start failed :-( */
  	if (iter) {
  		class_dev_iter_exit(iter);
  		kfree(iter);
77da16053   Vegard Nossum   block: fix use-af...
824
  		seqf->private = NULL;
5c0ef6d02   Kay Sievers   block: drop refer...
825
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  }
def4e38dd   Tejun Heo   block: use class_...
827
  static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  {
067680670   Jianpeng Ma   block: Don't use ...
829
  	void *p;
def4e38dd   Tejun Heo   block: use class_...
830
831
  
  	p = disk_seqf_start(seqf, pos);
b9f985b6e   Yang Zhang   block: convert !I...
832
  	if (!IS_ERR_OR_NULL(p) && !*pos)
def4e38dd   Tejun Heo   block: use class_...
833
834
835
836
  		seq_puts(seqf, "major minor  #blocks  name
  
  ");
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  }
cf771cb5a   Tejun Heo   block: make varia...
838
  static int show_partition(struct seq_file *seqf, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
  {
  	struct gendisk *sgp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
841
842
  	struct disk_part_iter piter;
  	struct hd_struct *part;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  	char buf[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  	/* Don't show non-partitionable removeable devices or empty devices */
d27769ec3   Tejun Heo   block: add GENHD_...
845
  	if (!get_capacity(sgp) || (!disk_max_parts(sgp) &&
f331c0296   Tejun Heo   block: don't depe...
846
  				   (sgp->flags & GENHD_FL_REMOVABLE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
850
851
  		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...
852
  	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
853
  	while ((part = disk_part_iter_next(&piter)))
1f0142905   Tejun Heo   block: adjust for...
854
855
  		seq_printf(seqf, "%4d  %7d %10llu %s
  ",
f331c0296   Tejun Heo   block: don't depe...
856
  			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
c83f6bf98   Vivek Goyal   block: add partit...
857
  			   (unsigned long long)part_nr_sects_read(part) >> 1,
f331c0296   Tejun Heo   block: don't depe...
858
  			   disk_name(sgp, part->partno, buf));
e71bf0d0e   Tejun Heo   block: fix disk->...
859
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
  
  	return 0;
  }
f500975a3   Alexey Dobriyan   proc: move rest o...
863
  static const struct seq_operations partitions_op = {
def4e38dd   Tejun Heo   block: use class_...
864
865
866
  	.start	= show_partition_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
edfaa7c36   Kay Sievers   Driver core: conv...
867
  	.show	= show_partition
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
869
870
871
872
873
874
875
876
877
878
879
880
  
  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
881
  #endif
cf771cb5a   Tejun Heo   block: make varia...
882
  static struct kobject *base_probe(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  {
edfaa7c36   Kay Sievers   Driver core: conv...
884
  	if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
  		/* Make old-style 2.4 aliases work */
edfaa7c36   Kay Sievers   Driver core: conv...
886
  		request_module("block-major-%d", MAJOR(devt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
889
890
891
  	return NULL;
  }
  
  static int __init genhd_device_init(void)
  {
e105b8bfc   Dan Williams   sysfs: add /sys/d...
892
893
894
895
  	int error;
  
  	block_class.dev_kobj = sysfs_dev_block_kobj;
  	error = class_register(&block_class);
ee27a558a   Roland McGrath   genhd must_check ...
896
897
  	if (unlikely(error))
  		return error;
edfaa7c36   Kay Sievers   Driver core: conv...
898
  	bdev_map = kobj_map_init(base_probe, &block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
  	blk_dev_init();
edfaa7c36   Kay Sievers   Driver core: conv...
900

561ec68e4   Zhang, Yanmin   block: fix boot f...
901
  	register_blkdev(BLOCK_EXT_MAJOR, "blkext");
edfaa7c36   Kay Sievers   Driver core: conv...
902
  	/* create top-level block dir */
e52eec13c   Andi Kleen   SYSFS: Allow boot...
903
904
  	if (!sysfs_deprecated)
  		block_depr = kobject_create_and_add("block", NULL);
830d3cfb1   Greg Kroah-Hartman   kset: convert blo...
905
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
  }
  
  subsys_initcall(genhd_device_init);
edfaa7c36   Kay Sievers   Driver core: conv...
909
910
  static ssize_t disk_range_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  {
edfaa7c36   Kay Sievers   Driver core: conv...
912
  	struct gendisk *disk = dev_to_disk(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913

edfaa7c36   Kay Sievers   Driver core: conv...
914
915
  	return sprintf(buf, "%d
  ", disk->minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  }
1f0142905   Tejun Heo   block: adjust for...
917
918
919
920
  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 ...
921
922
  	return sprintf(buf, "%d
  ", disk_max_parts(disk));
1f0142905   Tejun Heo   block: adjust for...
923
  }
edfaa7c36   Kay Sievers   Driver core: conv...
924
925
  static ssize_t disk_removable_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
a7fd67062   Kay Sievers   [PATCH] add sysfs...
926
  {
edfaa7c36   Kay Sievers   Driver core: conv...
927
  	struct gendisk *disk = dev_to_disk(dev);
a7fd67062   Kay Sievers   [PATCH] add sysfs...
928

edfaa7c36   Kay Sievers   Driver core: conv...
929
930
931
  	return sprintf(buf, "%d
  ",
  		       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
a7fd67062   Kay Sievers   [PATCH] add sysfs...
932
  }
1c9ce5276   Kay Sievers   block: export "ro...
933
934
935
936
  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...
937
938
  	return sprintf(buf, "%d
  ", get_disk_ro(disk) ? 1 : 0);
1c9ce5276   Kay Sievers   block: export "ro...
939
  }
edfaa7c36   Kay Sievers   Driver core: conv...
940
941
  static ssize_t disk_capability_show(struct device *dev,
  				    struct device_attribute *attr, char *buf)
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
942
  {
edfaa7c36   Kay Sievers   Driver core: conv...
943
944
945
946
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%x
  ", disk->flags);
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
947
  }
edfaa7c36   Kay Sievers   Driver core: conv...
948

c72758f33   Martin K. Petersen   block: Export I/O...
949
950
951
952
953
954
955
956
957
  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...
958
959
960
961
962
  static ssize_t disk_discard_alignment_show(struct device *dev,
  					   struct device_attribute *attr,
  					   char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
dd3d145d4   Martin K. Petersen   block: Fix discar...
963
964
  	return sprintf(buf, "%d
  ", queue_discard_alignment(disk->queue));
86b372814   Martin K. Petersen   block: Expose dis...
965
  }
edfaa7c36   Kay Sievers   Driver core: conv...
966
  static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
1f0142905   Tejun Heo   block: adjust for...
967
  static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
edfaa7c36   Kay Sievers   Driver core: conv...
968
  static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
1c9ce5276   Kay Sievers   block: export "ro...
969
  static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
e56105214   Tejun Heo   block: unify sysf...
970
  static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
c72758f33   Martin K. Petersen   block: Export I/O...
971
  static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
86b372814   Martin K. Petersen   block: Expose dis...
972
973
  static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show,
  		   NULL);
edfaa7c36   Kay Sievers   Driver core: conv...
974
  static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
074a7aca7   Tejun Heo   block: move stats...
975
  static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
316d315bf   Nikanth Karthikesan   block: Seperate r...
976
  static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
99e6608c9   Vishal Verma   block: Add badblo...
977
978
  static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show,
  		disk_badblocks_store);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
979
  #ifdef CONFIG_FAIL_MAKE_REQUEST
edfaa7c36   Kay Sievers   Driver core: conv...
980
  static struct device_attribute dev_attr_fail =
eddb2e26b   Tejun Heo   block: kill GENHD...
981
  	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
982
  #endif
581d4e28d   Jens Axboe   block: add fault ...
983
984
985
986
987
  #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...
988
989
990
  
  static struct attribute *disk_attrs[] = {
  	&dev_attr_range.attr,
1f0142905   Tejun Heo   block: adjust for...
991
  	&dev_attr_ext_range.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
992
  	&dev_attr_removable.attr,
1c9ce5276   Kay Sievers   block: export "ro...
993
  	&dev_attr_ro.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
994
  	&dev_attr_size.attr,
c72758f33   Martin K. Petersen   block: Export I/O...
995
  	&dev_attr_alignment_offset.attr,
86b372814   Martin K. Petersen   block: Expose dis...
996
  	&dev_attr_discard_alignment.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
997
998
  	&dev_attr_capability.attr,
  	&dev_attr_stat.attr,
316d315bf   Nikanth Karthikesan   block: Seperate r...
999
  	&dev_attr_inflight.attr,
99e6608c9   Vishal Verma   block: Add badblo...
1000
  	&dev_attr_badblocks.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1001
1002
1003
  #ifdef CONFIG_FAIL_MAKE_REQUEST
  	&dev_attr_fail.attr,
  #endif
581d4e28d   Jens Axboe   block: add fault ...
1004
1005
1006
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  	&dev_attr_fail_timeout.attr,
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
1007
1008
1009
1010
1011
1012
  	NULL
  };
  
  static struct attribute_group disk_attr_group = {
  	.attrs = disk_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
1013
  static const struct attribute_group *disk_attr_groups[] = {
edfaa7c36   Kay Sievers   Driver core: conv...
1014
1015
  	&disk_attr_group,
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  };
540eed563   Tejun Heo   block: make parti...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  /**
   * 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...
1034
1035
1036
  
  	if (old_ptbl) {
  		rcu_assign_pointer(old_ptbl->last_lookup, NULL);
57bdfbf9e   Lai Jiangshan   block,rcu: Conver...
1037
  		kfree_rcu(old_ptbl, rcu_head);
a6f23657d   Jens Axboe   block: add one-hi...
1038
  	}
540eed563   Tejun Heo   block: make parti...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  }
  
  /**
   * 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;
5fabcb4c3   Jens Axboe   genhd: check for ...
1060
  	int i, target;
540eed563   Tejun Heo   block: make parti...
1061
  	size_t size;
5fabcb4c3   Jens Axboe   genhd: check for ...
1062
1063
1064
1065
1066
1067
1068
1069
  
  	/*
  	 * check for int overflow, since we can get here from blkpg_ioctl()
  	 * with a user passed 'partno'.
  	 */
  	target = partno + 1;
  	if (target < 0)
  		return -EINVAL;
540eed563   Tejun Heo   block: make parti...
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  
  	/* 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;
540eed563   Tejun Heo   block: make parti...
1082
1083
1084
1085
1086
1087
1088
1089
  	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...
1090
  static void disk_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1092
  	struct gendisk *disk = dev_to_disk(dev);
2da78092d   Keith Busch   block: Fix dev_t ...
1093
  	blk_free_devt(dev->devt);
77ea887e4   Tejun Heo   implement in-kern...
1094
  	disk_release_events(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  	kfree(disk->random);
540eed563   Tejun Heo   block: make parti...
1096
  	disk_replace_part_tbl(disk, NULL);
b54e5ed8f   Ming Lei   block: partition:...
1097
  	hd_free_part(&disk->part0);
523e1d399   Tejun Heo   block: make gendi...
1098
1099
  	if (disk->queue)
  		blk_put_queue(disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
1101
  	kfree(disk);
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1102
1103
  struct class block_class = {
  	.name		= "block",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
  };
3c2670e65   Kay Sievers   driver core: add ...
1105
  static char *block_devnode(struct device *dev, umode_t *mode,
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
1106
  			   kuid_t *uid, kgid_t *gid)
b03f38b68   Kay Sievers   Driver Core: bloc...
1107
1108
  {
  	struct gendisk *disk = dev_to_disk(dev);
e454cea20   Kay Sievers   Driver-Core: exte...
1109
1110
  	if (disk->devnode)
  		return disk->devnode(disk, mode);
b03f38b68   Kay Sievers   Driver Core: bloc...
1111
1112
  	return NULL;
  }
1826eadfc   Adrian Bunk   block/genhd.c: cl...
1113
  static struct device_type disk_type = {
edfaa7c36   Kay Sievers   Driver core: conv...
1114
1115
1116
  	.name		= "disk",
  	.groups		= disk_attr_groups,
  	.release	= disk_release,
e454cea20   Kay Sievers   Driver-Core: exte...
1117
  	.devnode	= block_devnode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
  };
a6e2ba887   Randy Dunlap   block: make /proc...
1119
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
1120
1121
1122
1123
1124
1125
1126
1127
  /*
   * 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
1128
1129
  {
  	struct gendisk *gp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
1130
1131
  	struct disk_part_iter piter;
  	struct hd_struct *hd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
  	char buf[BDEVNAME_SIZE];
c99590591   Tejun Heo   block: fix diskst...
1133
  	int cpu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
  
  	/*
ed9e19823   Tejun Heo   block: implement ...
1136
  	if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
cf771cb5a   Tejun Heo   block: make varia...
1137
  		seq_puts(seqf,	"major minor name"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
  				"     rio rmerge rsect ruse wio wmerge "
  				"wsect wuse running use aveq"
  				"
  
  ");
  	*/
9f5e48655   Wanlong Gao   block:remove some...
1144

71982a409   Tejun Heo   block: include em...
1145
  	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1146
  	while ((hd = disk_part_iter_next(&piter))) {
074a7aca7   Tejun Heo   block: move stats...
1147
  		cpu = part_stat_lock();
c99590591   Tejun Heo   block: fix diskst...
1148
  		part_round_stats(cpu, hd);
074a7aca7   Tejun Heo   block: move stats...
1149
  		part_stat_unlock();
f95fe9cfb   Herbert Poetzl   block/genhd.c: re...
1150
1151
1152
  		seq_printf(seqf, "%4d %7d %s %lu %lu %lu "
  			   "%u %lu %lu %lu %u %u %u %u
  ",
f331c0296   Tejun Heo   block: don't depe...
1153
1154
  			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
  			   disk_name(gp, hd->partno, buf),
53f22956e   Liu Yuan   block/genhd: Chan...
1155
1156
  			   part_stat_read(hd, ios[READ]),
  			   part_stat_read(hd, merges[READ]),
f95fe9cfb   Herbert Poetzl   block/genhd.c: re...
1157
  			   part_stat_read(hd, sectors[READ]),
53f22956e   Liu Yuan   block/genhd: Chan...
1158
1159
1160
  			   jiffies_to_msecs(part_stat_read(hd, ticks[READ])),
  			   part_stat_read(hd, ios[WRITE]),
  			   part_stat_read(hd, merges[WRITE]),
f95fe9cfb   Herbert Poetzl   block/genhd.c: re...
1161
  			   part_stat_read(hd, sectors[WRITE]),
53f22956e   Liu Yuan   block/genhd: Chan...
1162
  			   jiffies_to_msecs(part_stat_read(hd, ticks[WRITE])),
316d315bf   Nikanth Karthikesan   block: Seperate r...
1163
  			   part_in_flight(hd),
28f39d553   Jerome Marchand   Enhanced partitio...
1164
1165
1166
  			   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
1167
  	}
e71bf0d0e   Tejun Heo   block: fix disk->...
1168
  	disk_part_iter_exit(&piter);
9f5e48655   Wanlong Gao   block:remove some...
1169

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
  	return 0;
  }
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1172
  static const struct seq_operations diskstats_op = {
def4e38dd   Tejun Heo   block: use class_...
1173
1174
1175
  	.start	= disk_seqf_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
  	.show	= diskstats_show
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
1178

31d85ab28   Alexey Dobriyan   proc: move /proc/...
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  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...
1190
1191
  static int __init proc_genhd_init(void)
  {
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1192
  	proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
f500975a3   Alexey Dobriyan   proc: move rest o...
1193
1194
1195
1196
  	proc_create("partitions", 0, NULL, &proc_partitions_operations);
  	return 0;
  }
  module_init(proc_genhd_init);
a6e2ba887   Randy Dunlap   block: make /proc...
1197
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198

cf771cb5a   Tejun Heo   block: make varia...
1199
  dev_t blk_lookup_devt(const char *name, int partno)
a142be856   Greg Kroah-Hartman   block: make blk_l...
1200
  {
def4e38dd   Tejun Heo   block: use class_...
1201
1202
1203
  	dev_t devt = MKDEV(0, 0);
  	struct class_dev_iter iter;
  	struct device *dev;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1204

def4e38dd   Tejun Heo   block: use class_...
1205
1206
  	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...
1207
  		struct gendisk *disk = dev_to_disk(dev);
548b10eb2   Tejun Heo   block: move __dev...
1208
  		struct hd_struct *part;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1209

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

41b8c853a   Neil Brown   block: fix bootin...
1213
1214
1215
1216
1217
1218
1219
1220
  		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...
1221
  		part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
1222
  		if (part) {
f331c0296   Tejun Heo   block: don't depe...
1223
  			devt = part_devt(part);
e71bf0d0e   Tejun Heo   block: fix disk->...
1224
  			disk_put_part(part);
548b10eb2   Tejun Heo   block: move __dev...
1225
  			break;
def4e38dd   Tejun Heo   block: use class_...
1226
  		}
548b10eb2   Tejun Heo   block: move __dev...
1227
  		disk_put_part(part);
5c0ef6d02   Kay Sievers   block: drop refer...
1228
  	}
def4e38dd   Tejun Heo   block: use class_...
1229
  	class_dev_iter_exit(&iter);
edfaa7c36   Kay Sievers   Driver core: conv...
1230
1231
  	return devt;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1232
  EXPORT_SYMBOL(blk_lookup_devt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
  struct gendisk *alloc_disk(int minors)
  {
c304a51bf   Ezequiel Garcia   block: use NUMA_N...
1235
  	return alloc_disk_node(minors, NUMA_NO_NODE);
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1236
  }
689d6fac4   Tejun Heo   block: replace @e...
1237
  EXPORT_SYMBOL(alloc_disk);
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1238
1239
1240
1241
  
  struct gendisk *alloc_disk_node(int minors, int node_id)
  {
  	struct gendisk *disk;
c1b511eb2   Joe Perches   block: Convert km...
1242
  	disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
  	if (disk) {
074a7aca7   Tejun Heo   block: move stats...
1244
  		if (!init_part_stats(&disk->part0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
1247
  			kfree(disk);
  			return NULL;
  		}
bf91db18a   Cheng Renquan   block: set disk->...
1248
  		disk->node_id = node_id;
540eed563   Tejun Heo   block: make parti...
1249
1250
  		if (disk_expand_part_tbl(disk, 0)) {
  			free_part_stats(&disk->part0);
b5d0b9df0   Tejun Heo   block: introduce ...
1251
1252
  			kfree(disk);
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  		}
540eed563   Tejun Heo   block: make parti...
1254
  		disk->part_tbl->part[0] = &disk->part0;
6c23a9681   Jens Axboe   block: add intern...
1255

c83f6bf98   Vivek Goyal   block: add partit...
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  		/*
  		 * set_capacity() and get_capacity() currently don't use
  		 * seqcounter to read/update the part0->nr_sects. Still init
  		 * the counter as we can read the sectors in IO submission
  		 * patch using seqence counters.
  		 *
  		 * TODO: Ideally set_capacity() and get_capacity() should be
  		 * converted to make use of bd_mutex and sequence counters.
  		 */
  		seqcount_init(&disk->part0.nr_sects_seq);
6c71013ec   Ming Lei   block: partition:...
1266
1267
1268
1269
1270
  		if (hd_ref_init(&disk->part0)) {
  			hd_free_part(&disk->part0);
  			kfree(disk);
  			return NULL;
  		}
b5d0b9df0   Tejun Heo   block: introduce ...
1271

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
  		disk->minors = minors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273
  		rand_initialize_disk(disk);
ed9e19823   Tejun Heo   block: implement ...
1274
1275
1276
  		disk_to_dev(disk)->class = &block_class;
  		disk_to_dev(disk)->type = &disk_type;
  		device_initialize(disk_to_dev(disk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
  	}
  	return disk;
  }
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1280
  EXPORT_SYMBOL(alloc_disk_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  
  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 ...
1292
  	kobj = kobject_get(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
  	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 ...
1306
  		kobject_put(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
1309
  }
  
  EXPORT_SYMBOL(put_disk);
e3264a4d7   Hannes Reinecke   Send uevents for ...
1310
1311
1312
1313
1314
1315
1316
1317
1318
  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
1319
1320
  void set_device_ro(struct block_device *bdev, int flag)
  {
b7db9956e   Tejun Heo   block: move polic...
1321
  	bdev->bd_part->policy = flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322
1323
1324
1325
1326
1327
  }
  
  EXPORT_SYMBOL(set_device_ro);
  
  void set_disk_ro(struct gendisk *disk, int flag)
  {
e71bf0d0e   Tejun Heo   block: fix disk->...
1328
1329
  	struct disk_part_iter piter;
  	struct hd_struct *part;
e3264a4d7   Hannes Reinecke   Send uevents for ...
1330
1331
1332
1333
1334
1335
  	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->...
1336
1337
1338
  	while ((part = disk_part_iter_next(&piter)))
  		part->policy = flag;
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
1344
1345
1346
  }
  
  EXPORT_SYMBOL(set_disk_ro);
  
  int bdev_read_only(struct block_device *bdev)
  {
  	if (!bdev)
  		return 0;
b7db9956e   Tejun Heo   block: move polic...
1347
  	return bdev->bd_part->policy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
  }
  
  EXPORT_SYMBOL(bdev_read_only);
cf771cb5a   Tejun Heo   block: make varia...
1351
  int invalidate_partition(struct gendisk *disk, int partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
  {
  	int res = 0;
cf771cb5a   Tejun Heo   block: make varia...
1354
  	struct block_device *bdev = bdget_disk(disk, partno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
  	if (bdev) {
2ef41634d   Christoph Hellwig   [PATCH] remove do...
1356
  		fsync_bdev(bdev);
93b270f76   NeilBrown   Fix over-zealous ...
1357
  		res = __invalidate_device(bdev, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
1362
1363
  		bdput(bdev);
  	}
  	return res;
  }
  
  EXPORT_SYMBOL(invalidate_partition);
77ea887e4   Tejun Heo   implement in-kern...
1364
1365
1366
1367
1368
1369
1370
1371
  
  /*
   * Disk events - monitor disk events like media change and eject request.
   */
  struct disk_events {
  	struct list_head	node;		/* all disk_event's */
  	struct gendisk		*disk;		/* the associated disk */
  	spinlock_t		lock;
fdd514e16   Tejun Heo   block: make disk_...
1372
  	struct mutex		block_mutex;	/* protects blocking */
77ea887e4   Tejun Heo   implement in-kern...
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
  	int			block;		/* event blocking depth */
  	unsigned int		pending;	/* events already sent out */
  	unsigned int		clearing;	/* events being cleared */
  
  	long			poll_msecs;	/* interval, -1 for default */
  	struct delayed_work	dwork;
  };
  
  static const char *disk_events_strs[] = {
  	[ilog2(DISK_EVENT_MEDIA_CHANGE)]	= "media_change",
  	[ilog2(DISK_EVENT_EJECT_REQUEST)]	= "eject_request",
  };
  
  static char *disk_uevents[] = {
  	[ilog2(DISK_EVENT_MEDIA_CHANGE)]	= "DISK_MEDIA_CHANGE=1",
  	[ilog2(DISK_EVENT_EJECT_REQUEST)]	= "DISK_EJECT_REQUEST=1",
  };
  
  /* list of all disk_events */
  static DEFINE_MUTEX(disk_events_mutex);
  static LIST_HEAD(disk_events);
  
  /* disable in-kernel polling by default */
1fe8f3484   Wei Tang   block: do not ini...
1396
  static unsigned long disk_events_dfl_poll_msecs;
77ea887e4   Tejun Heo   implement in-kern...
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
  
  static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
  {
  	struct disk_events *ev = disk->ev;
  	long intv_msecs = 0;
  
  	/*
  	 * If device-specific poll interval is set, always use it.  If
  	 * the default is being used, poll iff there are events which
  	 * can't be monitored asynchronously.
  	 */
  	if (ev->poll_msecs >= 0)
  		intv_msecs = ev->poll_msecs;
  	else if (disk->events & ~disk->async_events)
  		intv_msecs = disk_events_dfl_poll_msecs;
  
  	return msecs_to_jiffies(intv_msecs);
  }
c3af54afb   Tejun Heo   block: remove non...
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
  /**
   * disk_block_events - block and flush disk event checking
   * @disk: disk to block events for
   *
   * On return from this function, it is guaranteed that event checking
   * isn't in progress and won't happen until unblocked by
   * disk_unblock_events().  Events blocking is counted and the actual
   * unblocking happens after the matching number of unblocks are done.
   *
   * Note that this intentionally does not block event checking from
   * disk_clear_events().
   *
   * CONTEXT:
   * Might sleep.
   */
  void disk_block_events(struct gendisk *disk)
77ea887e4   Tejun Heo   implement in-kern...
1431
1432
1433
1434
  {
  	struct disk_events *ev = disk->ev;
  	unsigned long flags;
  	bool cancel;
c3af54afb   Tejun Heo   block: remove non...
1435
1436
  	if (!ev)
  		return;
fdd514e16   Tejun Heo   block: make disk_...
1437
1438
1439
1440
1441
  	/*
  	 * Outer mutex ensures that the first blocker completes canceling
  	 * the event work before further blockers are allowed to finish.
  	 */
  	mutex_lock(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1442
1443
1444
  	spin_lock_irqsave(&ev->lock, flags);
  	cancel = !ev->block++;
  	spin_unlock_irqrestore(&ev->lock, flags);
c3af54afb   Tejun Heo   block: remove non...
1445
1446
  	if (cancel)
  		cancel_delayed_work_sync(&disk->ev->dwork);
fdd514e16   Tejun Heo   block: make disk_...
1447
1448
  
  	mutex_unlock(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
  }
  
  static void __disk_unblock_events(struct gendisk *disk, bool check_now)
  {
  	struct disk_events *ev = disk->ev;
  	unsigned long intv;
  	unsigned long flags;
  
  	spin_lock_irqsave(&ev->lock, flags);
  
  	if (WARN_ON_ONCE(ev->block <= 0))
  		goto out_unlock;
  
  	if (--ev->block)
  		goto out_unlock;
77ea887e4   Tejun Heo   implement in-kern...
1464
  	intv = disk_events_poll_jiffies(disk);
77ea887e4   Tejun Heo   implement in-kern...
1465
  	if (check_now)
695588f94   Viresh Kumar   block: queue work...
1466
1467
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
77ea887e4   Tejun Heo   implement in-kern...
1468
  	else if (intv)
695588f94   Viresh Kumar   block: queue work...
1469
1470
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
1471
1472
1473
1474
1475
  out_unlock:
  	spin_unlock_irqrestore(&ev->lock, flags);
  }
  
  /**
77ea887e4   Tejun Heo   implement in-kern...
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
   * disk_unblock_events - unblock disk event checking
   * @disk: disk to unblock events for
   *
   * Undo disk_block_events().  When the block count reaches zero, it
   * starts events polling if configured.
   *
   * CONTEXT:
   * Don't care.  Safe to call from irq context.
   */
  void disk_unblock_events(struct gendisk *disk)
  {
  	if (disk->ev)
facc31ddc   Tejun Heo   block: Don't impl...
1488
  		__disk_unblock_events(disk, false);
77ea887e4   Tejun Heo   implement in-kern...
1489
1490
1491
  }
  
  /**
85ef06d1d   Tejun Heo   block: flush MEDI...
1492
1493
1494
   * disk_flush_events - schedule immediate event checking and flushing
   * @disk: disk to check and flush events for
   * @mask: events to flush
77ea887e4   Tejun Heo   implement in-kern...
1495
   *
85ef06d1d   Tejun Heo   block: flush MEDI...
1496
1497
1498
   * Schedule immediate event checking on @disk if not blocked.  Events in
   * @mask are scheduled to be cleared from the driver.  Note that this
   * doesn't clear the events from @disk->ev.
77ea887e4   Tejun Heo   implement in-kern...
1499
1500
   *
   * CONTEXT:
85ef06d1d   Tejun Heo   block: flush MEDI...
1501
   * If @mask is non-zero must be called with bdev->bd_mutex held.
77ea887e4   Tejun Heo   implement in-kern...
1502
   */
85ef06d1d   Tejun Heo   block: flush MEDI...
1503
  void disk_flush_events(struct gendisk *disk, unsigned int mask)
77ea887e4   Tejun Heo   implement in-kern...
1504
  {
a9dce2a3b   Tejun Heo   block: don't use ...
1505
  	struct disk_events *ev = disk->ev;
a9dce2a3b   Tejun Heo   block: don't use ...
1506
1507
1508
  
  	if (!ev)
  		return;
85ef06d1d   Tejun Heo   block: flush MEDI...
1509
1510
  	spin_lock_irq(&ev->lock);
  	ev->clearing |= mask;
41f63c535   Tejun Heo   workqueue: use mo...
1511
  	if (!ev->block)
695588f94   Viresh Kumar   block: queue work...
1512
1513
  		mod_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
85ef06d1d   Tejun Heo   block: flush MEDI...
1514
  	spin_unlock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
1515
  }
77ea887e4   Tejun Heo   implement in-kern...
1516
1517
1518
1519
  
  /**
   * disk_clear_events - synchronously check, clear and return pending events
   * @disk: disk to fetch and clear events from
da3dae54e   Masanari Iida   Documentation: Do...
1520
   * @mask: mask of events to be fetched and cleared
77ea887e4   Tejun Heo   implement in-kern...
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
   *
   * Disk events are synchronously checked and pending events in @mask
   * are cleared and returned.  This ignores the block count.
   *
   * CONTEXT:
   * Might sleep.
   */
  unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
  {
  	const struct block_device_operations *bdops = disk->fops;
  	struct disk_events *ev = disk->ev;
  	unsigned int pending;
12c2bdb23   Derek Basehore   block: prevent ra...
1533
  	unsigned int clearing = mask;
77ea887e4   Tejun Heo   implement in-kern...
1534
1535
1536
1537
1538
1539
1540
1541
  
  	if (!ev) {
  		/* for drivers still using the old ->media_changed method */
  		if ((mask & DISK_EVENT_MEDIA_CHANGE) &&
  		    bdops->media_changed && bdops->media_changed(disk))
  			return DISK_EVENT_MEDIA_CHANGE;
  		return 0;
  	}
12c2bdb23   Derek Basehore   block: prevent ra...
1542
1543
1544
1545
1546
1547
1548
  	disk_block_events(disk);
  
  	/*
  	 * store the union of mask and ev->clearing on the stack so that the
  	 * race with disk_flush_events does not cause ambiguity (ev->clearing
  	 * can still be modified even if events are blocked).
  	 */
77ea887e4   Tejun Heo   implement in-kern...
1549
  	spin_lock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1550
1551
  	clearing |= ev->clearing;
  	ev->clearing = 0;
77ea887e4   Tejun Heo   implement in-kern...
1552
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1553
  	disk_check_events(ev, &clearing);
aea24a8bb   Derek Basehore   block: remove dea...
1554
  	/*
12c2bdb23   Derek Basehore   block: prevent ra...
1555
1556
  	 * if ev->clearing is not 0, the disk_flush_events got called in the
  	 * middle of this function, so we want to run the workfn without delay.
aea24a8bb   Derek Basehore   block: remove dea...
1557
  	 */
12c2bdb23   Derek Basehore   block: prevent ra...
1558
  	__disk_unblock_events(disk, ev->clearing ? true : false);
77ea887e4   Tejun Heo   implement in-kern...
1559
1560
1561
  
  	/* then, fetch and clear pending events */
  	spin_lock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
1562
1563
1564
  	pending = ev->pending & mask;
  	ev->pending &= ~mask;
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1565
  	WARN_ON_ONCE(clearing & mask);
77ea887e4   Tejun Heo   implement in-kern...
1566
1567
1568
  
  	return pending;
  }
12c2bdb23   Derek Basehore   block: prevent ra...
1569
1570
1571
1572
  /*
   * Separate this part out so that a different pointer for clearing_ptr can be
   * passed in for disk_clear_events.
   */
77ea887e4   Tejun Heo   implement in-kern...
1573
1574
1575
1576
  static void disk_events_workfn(struct work_struct *work)
  {
  	struct delayed_work *dwork = to_delayed_work(work);
  	struct disk_events *ev = container_of(dwork, struct disk_events, dwork);
12c2bdb23   Derek Basehore   block: prevent ra...
1577
1578
1579
1580
1581
1582
1583
  
  	disk_check_events(ev, &ev->clearing);
  }
  
  static void disk_check_events(struct disk_events *ev,
  			      unsigned int *clearing_ptr)
  {
77ea887e4   Tejun Heo   implement in-kern...
1584
1585
  	struct gendisk *disk = ev->disk;
  	char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
12c2bdb23   Derek Basehore   block: prevent ra...
1586
  	unsigned int clearing = *clearing_ptr;
77ea887e4   Tejun Heo   implement in-kern...
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  	unsigned int events;
  	unsigned long intv;
  	int nr_events = 0, i;
  
  	/* check events */
  	events = disk->fops->check_events(disk, clearing);
  
  	/* accumulate pending events and schedule next poll if necessary */
  	spin_lock_irq(&ev->lock);
  
  	events &= ~ev->pending;
  	ev->pending |= events;
12c2bdb23   Derek Basehore   block: prevent ra...
1599
  	*clearing_ptr &= ~clearing;
77ea887e4   Tejun Heo   implement in-kern...
1600
1601
1602
  
  	intv = disk_events_poll_jiffies(disk);
  	if (!ev->block && intv)
695588f94   Viresh Kumar   block: queue work...
1603
1604
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
1605
1606
  
  	spin_unlock_irq(&ev->lock);
7c88a168d   Tejun Heo   block: don't prop...
1607
1608
1609
1610
1611
  	/*
  	 * Tell userland about new events.  Only the events listed in
  	 * @disk->events are reported.  Unlisted events are processed the
  	 * same internally but never get reported to userland.
  	 */
77ea887e4   Tejun Heo   implement in-kern...
1612
  	for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
7c88a168d   Tejun Heo   block: don't prop...
1613
  		if (events & disk->events & (1 << i))
77ea887e4   Tejun Heo   implement in-kern...
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
  			envp[nr_events++] = disk_uevents[i];
  
  	if (nr_events)
  		kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
  }
  
  /*
   * A disk events enabled device has the following sysfs nodes under
   * its /sys/block/X/ directory.
   *
   * events		: list of all supported events
   * events_async		: list of events which can be detected w/o polling
   * events_poll_msecs	: polling interval, 0: disable, -1: system default
   */
  static ssize_t __disk_events_show(unsigned int events, char *buf)
  {
  	const char *delim = "";
  	ssize_t pos = 0;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(disk_events_strs); i++)
  		if (events & (1 << i)) {
  			pos += sprintf(buf + pos, "%s%s",
  				       delim, disk_events_strs[i]);
  			delim = " ";
  		}
  	if (pos)
  		pos += sprintf(buf + pos, "
  ");
  	return pos;
  }
  
  static ssize_t disk_events_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return __disk_events_show(disk->events, buf);
  }
  
  static ssize_t disk_events_async_show(struct device *dev,
  				      struct device_attribute *attr, char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return __disk_events_show(disk->async_events, buf);
  }
  
  static ssize_t disk_events_poll_msecs_show(struct device *dev,
  					   struct device_attribute *attr,
  					   char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%ld
  ", disk->ev->poll_msecs);
  }
  
  static ssize_t disk_events_poll_msecs_store(struct device *dev,
  					    struct device_attribute *attr,
  					    const char *buf, size_t count)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  	long intv;
  
  	if (!count || !sscanf(buf, "%ld", &intv))
  		return -EINVAL;
  
  	if (intv < 0 && intv != -1)
  		return -EINVAL;
c3af54afb   Tejun Heo   block: remove non...
1684
  	disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
  	disk->ev->poll_msecs = intv;
  	__disk_unblock_events(disk, true);
  
  	return count;
  }
  
  static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL);
  static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL);
  static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR,
  			 disk_events_poll_msecs_show,
  			 disk_events_poll_msecs_store);
  
  static const struct attribute *disk_events_attrs[] = {
  	&dev_attr_events.attr,
  	&dev_attr_events_async.attr,
  	&dev_attr_events_poll_msecs.attr,
  	NULL,
  };
  
  /*
   * The default polling interval can be specified by the kernel
   * parameter block.events_dfl_poll_msecs which defaults to 0
   * (disable).  This can also be modified runtime by writing to
   * /sys/module/block/events_dfl_poll_msecs.
   */
  static int disk_events_set_dfl_poll_msecs(const char *val,
  					  const struct kernel_param *kp)
  {
  	struct disk_events *ev;
  	int ret;
  
  	ret = param_set_ulong(val, kp);
  	if (ret < 0)
  		return ret;
  
  	mutex_lock(&disk_events_mutex);
  
  	list_for_each_entry(ev, &disk_events, node)
85ef06d1d   Tejun Heo   block: flush MEDI...
1723
  		disk_flush_events(ev->disk, 0);
77ea887e4   Tejun Heo   implement in-kern...
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
  
  	mutex_unlock(&disk_events_mutex);
  
  	return 0;
  }
  
  static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = {
  	.set	= disk_events_set_dfl_poll_msecs,
  	.get	= param_get_ulong,
  };
  
  #undef MODULE_PARAM_PREFIX
  #define MODULE_PARAM_PREFIX	"block."
  
  module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops,
  		&disk_events_dfl_poll_msecs, 0644);
  
  /*
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1742
   * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
77ea887e4   Tejun Heo   implement in-kern...
1743
   */
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1744
  static void disk_alloc_events(struct gendisk *disk)
77ea887e4   Tejun Heo   implement in-kern...
1745
1746
  {
  	struct disk_events *ev;
75e3f3ee3   Tejun Heo   block: always all...
1747
  	if (!disk->fops->check_events)
77ea887e4   Tejun Heo   implement in-kern...
1748
1749
1750
1751
1752
1753
1754
1755
  		return;
  
  	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
  	if (!ev) {
  		pr_warn("%s: failed to initialize events
  ", disk->disk_name);
  		return;
  	}
77ea887e4   Tejun Heo   implement in-kern...
1756
1757
1758
  	INIT_LIST_HEAD(&ev->node);
  	ev->disk = disk;
  	spin_lock_init(&ev->lock);
fdd514e16   Tejun Heo   block: make disk_...
1759
  	mutex_init(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1760
1761
1762
  	ev->block = 1;
  	ev->poll_msecs = -1;
  	INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  	disk->ev = ev;
  }
  
  static void disk_add_events(struct gendisk *disk)
  {
  	if (!disk->ev)
  		return;
  
  	/* FIXME: error handling */
  	if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0)
  		pr_warn("%s: failed to create sysfs files for events
  ",
  			disk->disk_name);
77ea887e4   Tejun Heo   implement in-kern...
1776
  	mutex_lock(&disk_events_mutex);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1777
  	list_add_tail(&disk->ev->node, &disk_events);
77ea887e4   Tejun Heo   implement in-kern...
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
  	mutex_unlock(&disk_events_mutex);
  
  	/*
  	 * Block count is initialized to 1 and the following initial
  	 * unblock kicks it into action.
  	 */
  	__disk_unblock_events(disk, true);
  }
  
  static void disk_del_events(struct gendisk *disk)
  {
  	if (!disk->ev)
  		return;
c3af54afb   Tejun Heo   block: remove non...
1791
  	disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
  
  	mutex_lock(&disk_events_mutex);
  	list_del_init(&disk->ev->node);
  	mutex_unlock(&disk_events_mutex);
  
  	sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs);
  }
  
  static void disk_release_events(struct gendisk *disk)
  {
  	/* the block count should be 1 from disk_del_events() */
  	WARN_ON_ONCE(disk->ev && disk->ev->block != 1);
  	kfree(disk->ev);
  }