Blame view

block/genhd.c 50.5 KB
3dcf60bcb   Christoph Hellwig   block: add SPDX t...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  /*
   *  gendisk handling
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
  #include <linux/module.h>
  #include <linux/fs.h>
  #include <linux/genhd.h>
b446b60e4   Andrew Morton   [PATCH] rework re...
8
  #include <linux/kdev_t.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
  #include <linux/kernel.h>
  #include <linux/blkdev.h>
66114cad6   Tejun Heo   writeback: separa...
11
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include <linux/init.h>
  #include <linux/spinlock.h>
f500975a3   Alexey Dobriyan   proc: move rest o...
14
  #include <linux/proc_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
  #include <linux/seq_file.h>
  #include <linux/slab.h>
  #include <linux/kmod.h>
  #include <linux/kobj_map.h>
58383af62   Jes Sorensen   [PATCH] kobj_map ...
19
  #include <linux/mutex.h>
bcce3de1b   Tejun Heo   block: implement ...
20
  #include <linux/idr.h>
77ea887e4   Tejun Heo   implement in-kern...
21
  #include <linux/log2.h>
25e823c8c   Ming Lei   block/genhd.c: ap...
22
  #include <linux/pm_runtime.h>
99e6608c9   Vishal Verma   block: Add badblo...
23
  #include <linux/badblocks.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

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

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

2da78092d   Keith Busch   block: Fix dev_t ...
32
  /* For extended devt allocation.  ext_devt_lock prevents look up
bcce3de1b   Tejun Heo   block: implement ...
33
34
   * results from going away underneath its user.
   */
2da78092d   Keith Busch   block: Fix dev_t ...
35
  static DEFINE_SPINLOCK(ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
36
  static DEFINE_IDR(ext_devt_idr);
edf8ff558   Bart Van Assche   block: Constify d...
37
  static const struct device_type disk_type;
1826eadfc   Adrian Bunk   block/genhd.c: cl...
38

12c2bdb23   Derek Basehore   block: prevent ra...
39
40
  static void disk_check_events(struct disk_events *ev,
  			      unsigned int *clearing_ptr);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
41
  static void disk_alloc_events(struct gendisk *disk);
77ea887e4   Tejun Heo   implement in-kern...
42
43
44
  static void disk_add_events(struct gendisk *disk);
  static void disk_del_events(struct gendisk *disk);
  static void disk_release_events(struct gendisk *disk);
f299b7c7a   Jens Axboe   blk-mq: provide i...
45
46
  void part_inc_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
  {
344e9ffcb   Jens Axboe   block: add queue_...
47
  	if (queue_is_mq(q))
f299b7c7a   Jens Axboe   blk-mq: provide i...
48
  		return;
1226b8dd0   Mikulas Patocka   block: switch to ...
49
  	part_stat_local_inc(part, in_flight[rw]);
f299b7c7a   Jens Axboe   blk-mq: provide i...
50
  	if (part->partno)
1226b8dd0   Mikulas Patocka   block: switch to ...
51
  		part_stat_local_inc(&part_to_disk(part)->part0, in_flight[rw]);
f299b7c7a   Jens Axboe   blk-mq: provide i...
52
53
54
55
  }
  
  void part_dec_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
  {
344e9ffcb   Jens Axboe   block: add queue_...
56
  	if (queue_is_mq(q))
f299b7c7a   Jens Axboe   blk-mq: provide i...
57
  		return;
1226b8dd0   Mikulas Patocka   block: switch to ...
58
  	part_stat_local_dec(part, in_flight[rw]);
f299b7c7a   Jens Axboe   blk-mq: provide i...
59
  	if (part->partno)
1226b8dd0   Mikulas Patocka   block: switch to ...
60
  		part_stat_local_dec(&part_to_disk(part)->part0, in_flight[rw]);
f299b7c7a   Jens Axboe   blk-mq: provide i...
61
  }
e016b7820   Mikulas Patocka   block: return jus...
62
  unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part)
f299b7c7a   Jens Axboe   blk-mq: provide i...
63
  {
1226b8dd0   Mikulas Patocka   block: switch to ...
64
  	int cpu;
e016b7820   Mikulas Patocka   block: return jus...
65
  	unsigned int inflight;
1226b8dd0   Mikulas Patocka   block: switch to ...
66

344e9ffcb   Jens Axboe   block: add queue_...
67
  	if (queue_is_mq(q)) {
e016b7820   Mikulas Patocka   block: return jus...
68
  		return blk_mq_in_flight(q, part);
f299b7c7a   Jens Axboe   blk-mq: provide i...
69
  	}
e016b7820   Mikulas Patocka   block: return jus...
70
  	inflight = 0;
1226b8dd0   Mikulas Patocka   block: switch to ...
71
  	for_each_possible_cpu(cpu) {
e016b7820   Mikulas Patocka   block: return jus...
72
73
  		inflight += part_stat_local_read_cpu(part, in_flight[0], cpu) +
  			    part_stat_local_read_cpu(part, in_flight[1], cpu);
1226b8dd0   Mikulas Patocka   block: switch to ...
74
  	}
e016b7820   Mikulas Patocka   block: return jus...
75
76
  	if ((int)inflight < 0)
  		inflight = 0;
1226b8dd0   Mikulas Patocka   block: switch to ...
77

e016b7820   Mikulas Patocka   block: return jus...
78
  	return inflight;
f299b7c7a   Jens Axboe   blk-mq: provide i...
79
  }
bf0ddaba6   Omar Sandoval   blk-mq: fix sysfs...
80
81
82
  void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
  		       unsigned int inflight[2])
  {
1226b8dd0   Mikulas Patocka   block: switch to ...
83
  	int cpu;
344e9ffcb   Jens Axboe   block: add queue_...
84
  	if (queue_is_mq(q)) {
bf0ddaba6   Omar Sandoval   blk-mq: fix sysfs...
85
86
87
  		blk_mq_in_flight_rw(q, part, inflight);
  		return;
  	}
1226b8dd0   Mikulas Patocka   block: switch to ...
88
89
90
91
92
93
94
95
96
97
  	inflight[0] = 0;
  	inflight[1] = 0;
  	for_each_possible_cpu(cpu) {
  		inflight[0] += part_stat_local_read_cpu(part, in_flight[0], cpu);
  		inflight[1] += part_stat_local_read_cpu(part, in_flight[1], cpu);
  	}
  	if ((int)inflight[0] < 0)
  		inflight[0] = 0;
  	if ((int)inflight[1] < 0)
  		inflight[1] = 0;
bf0ddaba6   Omar Sandoval   blk-mq: fix sysfs...
98
  }
807d4af2f   Christoph Hellwig   block: add a __di...
99
100
101
102
103
104
105
106
  struct hd_struct *__disk_get_part(struct gendisk *disk, int partno)
  {
  	struct disk_part_tbl *ptbl = rcu_dereference(disk->part_tbl);
  
  	if (unlikely(partno < 0 || partno >= ptbl->len))
  		return NULL;
  	return rcu_dereference(ptbl->part[partno]);
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  /**
   * 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)
  {
807d4af2f   Christoph Hellwig   block: add a __di...
123
  	struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
124

e71bf0d0e   Tejun Heo   block: fix disk->...
125
  	rcu_read_lock();
807d4af2f   Christoph Hellwig   block: add a __di...
126
127
128
  	part = __disk_get_part(disk, partno);
  	if (part)
  		get_device(part_to_dev(part));
e71bf0d0e   Tejun Heo   block: fix disk->...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  	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...
149
150
151
152
  	struct disk_part_tbl *ptbl;
  
  	rcu_read_lock();
  	ptbl = rcu_dereference(disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
153
154
155
156
  	piter->disk = disk;
  	piter->part = NULL;
  
  	if (flags & DISK_PITER_REVERSE)
540eed563   Tejun Heo   block: make parti...
157
  		piter->idx = ptbl->len - 1;
71982a409   Tejun Heo   block: include em...
158
  	else if (flags & (DISK_PITER_INCL_PART0 | DISK_PITER_INCL_EMPTY_PART0))
e71bf0d0e   Tejun Heo   block: fix disk->...
159
  		piter->idx = 0;
b5d0b9df0   Tejun Heo   block: introduce ...
160
161
  	else
  		piter->idx = 1;
e71bf0d0e   Tejun Heo   block: fix disk->...
162
163
  
  	piter->flags = flags;
540eed563   Tejun Heo   block: make parti...
164
165
  
  	rcu_read_unlock();
e71bf0d0e   Tejun Heo   block: fix disk->...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  }
  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...
180
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
181
182
183
184
185
  	int inc, end;
  
  	/* put the last partition */
  	disk_put_part(piter->part);
  	piter->part = NULL;
540eed563   Tejun Heo   block: make parti...
186
  	/* get part_tbl */
e71bf0d0e   Tejun Heo   block: fix disk->...
187
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
188
  	ptbl = rcu_dereference(piter->disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
189
190
191
192
  
  	/* determine iteration parameters */
  	if (piter->flags & DISK_PITER_REVERSE) {
  		inc = -1;
71982a409   Tejun Heo   block: include em...
193
194
  		if (piter->flags & (DISK_PITER_INCL_PART0 |
  				    DISK_PITER_INCL_EMPTY_PART0))
b5d0b9df0   Tejun Heo   block: introduce ...
195
196
197
  			end = -1;
  		else
  			end = 0;
e71bf0d0e   Tejun Heo   block: fix disk->...
198
199
  	} else {
  		inc = 1;
540eed563   Tejun Heo   block: make parti...
200
  		end = ptbl->len;
e71bf0d0e   Tejun Heo   block: fix disk->...
201
202
203
204
205
  	}
  
  	/* iterate to the next partition */
  	for (; piter->idx != end; piter->idx += inc) {
  		struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
206
  		part = rcu_dereference(ptbl->part[piter->idx]);
e71bf0d0e   Tejun Heo   block: fix disk->...
207
208
  		if (!part)
  			continue;
c83f6bf98   Vivek Goyal   block: add partit...
209
  		if (!part_nr_sects_read(part) &&
71982a409   Tejun Heo   block: include em...
210
211
212
  		    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
  		    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
  		      piter->idx == 0))
e71bf0d0e   Tejun Heo   block: fix disk->...
213
  			continue;
ed9e19823   Tejun Heo   block: implement ...
214
  		get_device(part_to_dev(part));
e71bf0d0e   Tejun Heo   block: fix disk->...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  		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...
241
242
243
  static inline int sector_in_part(struct hd_struct *part, sector_t sector)
  {
  	return part->start_sect <= sector &&
c83f6bf98   Vivek Goyal   block: add partit...
244
  		sector < part->start_sect + part_nr_sects_read(part);
a6f23657d   Jens Axboe   block: add one-hi...
245
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
246
247
248
249
250
251
252
253
254
255
256
257
258
  /**
   * 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...
259
   * Found partition on success, part0 is returned if no partition matches
e71bf0d0e   Tejun Heo   block: fix disk->...
260
261
262
   */
  struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
  {
540eed563   Tejun Heo   block: make parti...
263
  	struct disk_part_tbl *ptbl;
a6f23657d   Jens Axboe   block: add one-hi...
264
  	struct hd_struct *part;
e71bf0d0e   Tejun Heo   block: fix disk->...
265
  	int i;
540eed563   Tejun Heo   block: make parti...
266
  	ptbl = rcu_dereference(disk->part_tbl);
a6f23657d   Jens Axboe   block: add one-hi...
267
268
269
  	part = rcu_dereference(ptbl->last_lookup);
  	if (part && sector_in_part(part, sector))
  		return part;
540eed563   Tejun Heo   block: make parti...
270
  	for (i = 1; i < ptbl->len; i++) {
a6f23657d   Jens Axboe   block: add one-hi...
271
  		part = rcu_dereference(ptbl->part[i]);
e71bf0d0e   Tejun Heo   block: fix disk->...
272

a6f23657d   Jens Axboe   block: add one-hi...
273
274
  		if (part && sector_in_part(part, sector)) {
  			rcu_assign_pointer(ptbl->last_lookup, part);
e71bf0d0e   Tejun Heo   block: fix disk->...
275
  			return part;
a6f23657d   Jens Axboe   block: add one-hi...
276
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
277
  	}
074a7aca7   Tejun Heo   block: move stats...
278
  	return &disk->part0;
e71bf0d0e   Tejun Heo   block: fix disk->...
279
280
  }
  EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
  /*
   * Can be deleted altogether. Later.
   *
   */
133d55cdb   Logan Gunthorpe   block: order /pro...
285
  #define BLKDEV_MAJOR_HASH_SIZE 255
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
  static struct blk_major_name {
  	struct blk_major_name *next;
  	int major;
  	char name[16];
68eef3b47   Joe Korty   [PATCH] Simplify ...
290
  } *major_names[BLKDEV_MAJOR_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  
  /* index in the above - for now: assume no multimajor ranges */
e61eb2e93   Yang Zhang   fs/block: type si...
293
  static inline int major_to_index(unsigned major)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
295
  	return major % BLKDEV_MAJOR_HASH_SIZE;
7170be5f5   Neil Horman   [PATCH] convert /...
296
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
297
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
298
  void blkdev_show(struct seq_file *seqf, off_t offset)
7170be5f5   Neil Horman   [PATCH] convert /...
299
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
300
  	struct blk_major_name *dp;
7170be5f5   Neil Horman   [PATCH] convert /...
301

133d55cdb   Logan Gunthorpe   block: order /pro...
302
303
304
  	mutex_lock(&block_class_lock);
  	for (dp = major_names[major_to_index(offset)]; dp; dp = dp->next)
  		if (dp->major == offset)
cf771cb5a   Tejun Heo   block: make varia...
305
306
  			seq_printf(seqf, "%3d %s
  ", dp->major, dp->name);
133d55cdb   Logan Gunthorpe   block: order /pro...
307
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
309
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310

9e8c0bccd   Márton Németh   block: add docume...
311
312
313
  /**
   * register_blkdev - register a new block device
   *
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
314
315
   * @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If
   *         @major = 0, try to allocate any unused major number.
9e8c0bccd   Márton Németh   block: add docume...
316
317
318
319
   * @name: the name of the new block device as a zero terminated string
   *
   * The @name must be unique within the system.
   *
0e056eb55   mchehab@s-opensource.com   kernel-api.rst: f...
320
321
   * The return value depends on the @major input parameter:
   *
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
322
323
   *  - if a major device number was requested in range [1..BLKDEV_MAJOR_MAX-1]
   *    then the function returns zero on success, or a negative error code
0e056eb55   mchehab@s-opensource.com   kernel-api.rst: f...
324
   *  - if any unused major number was requested with @major = 0 parameter
9e8c0bccd   Márton Németh   block: add docume...
325
   *    then the return value is the allocated major number in range
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
326
327
328
329
   *    [1..BLKDEV_MAJOR_MAX-1] or a negative error code otherwise
   *
   * See Documentation/admin-guide/devices.txt for the list of allocated
   * major numbers.
9e8c0bccd   Márton Németh   block: add docume...
330
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
  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...
335
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
  
  	/* temporary */
  	if (major == 0) {
  		for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
  			if (major_names[index] == NULL)
  				break;
  		}
  
  		if (index == 0) {
dfc76d11d   Keyur Patel   block: Replace fu...
345
346
347
  			printk("%s: failed to get major for %s
  ",
  			       __func__, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
  			ret = -EBUSY;
  			goto out;
  		}
  		major = index;
  		ret = major;
  	}
133d55cdb   Logan Gunthorpe   block: order /pro...
354
  	if (major >= BLKDEV_MAJOR_MAX) {
dfc76d11d   Keyur Patel   block: Replace fu...
355
356
357
  		pr_err("%s: major requested (%u) is greater than the maximum (%u) for %s
  ",
  		       __func__, major, BLKDEV_MAJOR_MAX-1, name);
133d55cdb   Logan Gunthorpe   block: order /pro...
358
359
360
361
  
  		ret = -EINVAL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  	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) {
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
383
384
  		printk("register_blkdev: cannot get major %u for %s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
  		       major, name);
  		kfree(p);
  	}
  out:
edfaa7c36   Kay Sievers   Driver core: conv...
389
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
  	return ret;
  }
  
  EXPORT_SYMBOL(register_blkdev);
f4480240f   Akinobu Mita   unregister_blkdev...
394
  void unregister_blkdev(unsigned int major, const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
  {
  	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
399

edfaa7c36   Kay Sievers   Driver core: conv...
400
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
  	for (n = &major_names[index]; *n; n = &(*n)->next)
  		if ((*n)->major == major)
  			break;
294462a5c   Akinobu Mita   unregister_blkdev...
404
405
  	if (!*n || strcmp((*n)->name, name)) {
  		WARN_ON(1);
294462a5c   Akinobu Mita   unregister_blkdev...
406
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  		p = *n;
  		*n = p->next;
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
410
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	kfree(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
  }
  
  EXPORT_SYMBOL(unregister_blkdev);
  
  static struct kobj_map *bdev_map;
bcce3de1b   Tejun Heo   block: implement ...
417
  /**
870d66561   Tejun Heo   block: implement ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
   * 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 ...
450
451
   * blk_alloc_devt - allocate a dev_t for a partition
   * @part: partition to allocate dev_t for
bcce3de1b   Tejun Heo   block: implement ...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
   * @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...
466
  	int idx;
bcce3de1b   Tejun Heo   block: implement ...
467
468
469
470
471
472
473
474
  
  	/* 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 ...
475
  	idr_preload(GFP_KERNEL);
4d66e5e9b   Dan Williams   block: fix ext_de...
476
  	spin_lock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
477
  	idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
4d66e5e9b   Dan Williams   block: fix ext_de...
478
  	spin_unlock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
479
480
  
  	idr_preload_end();
bab998d62   Tejun Heo   block: convert to...
481
482
  	if (idx < 0)
  		return idx == -ENOSPC ? -EBUSY : idx;
bcce3de1b   Tejun Heo   block: implement ...
483

870d66561   Tejun Heo   block: implement ...
484
  	*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
bcce3de1b   Tejun Heo   block: implement ...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  	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 ...
499
500
501
502
  	if (devt == MKDEV(0, 0))
  		return;
  
  	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
4d66e5e9b   Dan Williams   block: fix ext_de...
503
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
504
  		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
4d66e5e9b   Dan Williams   block: fix ext_de...
505
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
506
507
  	}
  }
33c826ef1   Bart Van Assche   block: Convert bl...
508
509
  /*
   * We invalidate devt by assigning NULL pointer for devt in idr.
6fcc44d1d   Yufen Yu   block: fix use-af...
510
511
512
513
514
515
516
517
518
   */
  void blk_invalidate_devt(dev_t devt)
  {
  	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
  		spin_lock_bh(&ext_devt_lock);
  		idr_replace(&ext_devt_idr, NULL, blk_mangle_minor(MINOR(devt)));
  		spin_unlock_bh(&ext_devt_lock);
  	}
  }
1f0142905   Tejun Heo   block: adjust for...
519
520
521
522
523
524
525
526
527
528
529
  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
530
531
532
533
534
  /*
   * 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...
535
  void blk_register_region(dev_t devt, unsigned long range, struct module *module,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
  			 struct kobject *(*probe)(dev_t, int *, void *),
  			 int (*lock)(dev_t, void *), void *data)
  {
edfaa7c36   Kay Sievers   Driver core: conv...
539
  	kobj_map(bdev_map, devt, range, module, probe, lock, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
  }
  
  EXPORT_SYMBOL(blk_register_region);
edfaa7c36   Kay Sievers   Driver core: conv...
543
  void blk_unregister_region(dev_t devt, unsigned long range)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  {
edfaa7c36   Kay Sievers   Driver core: conv...
545
  	kobj_unmap(bdev_map, devt, range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
  }
  
  EXPORT_SYMBOL(blk_unregister_region);
cf771cb5a   Tejun Heo   block: make varia...
549
  static struct kobject *exact_match(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
  {
  	struct gendisk *p = data;
edfaa7c36   Kay Sievers   Driver core: conv...
552

ed9e19823   Tejun Heo   block: implement ...
553
  	return &disk_to_dev(p)->kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  }
edfaa7c36   Kay Sievers   Driver core: conv...
555
  static int exact_lock(dev_t devt, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  {
  	struct gendisk *p = data;
3079c22ea   Jan Kara   genhd: Rename get...
558
  	if (!get_disk_and_module(p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
  		return -1;
  	return 0;
  }
fef912bf8   Hannes Reinecke   block: genhd: add...
562
563
  static void register_disk(struct device *parent, struct gendisk *disk,
  			  const struct attribute_group **groups)
d2bf1b672   Tejun Heo   block: move regis...
564
565
566
567
568
569
  {
  	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 ...
570
  	ddev->parent = parent;
d2bf1b672   Tejun Heo   block: move regis...
571

ffc8b3086   Kees Cook   block: do not pas...
572
  	dev_set_name(ddev, "%s", disk->disk_name);
d2bf1b672   Tejun Heo   block: move regis...
573
574
575
  
  	/* delay uevents, until we scanned partition table */
  	dev_set_uevent_suppress(ddev, 1);
fef912bf8   Hannes Reinecke   block: genhd: add...
576
577
578
579
  	if (groups) {
  		WARN_ON(ddev->groups);
  		ddev->groups = groups;
  	}
d2bf1b672   Tejun Heo   block: move regis...
580
581
582
583
584
585
586
587
588
589
  	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...
590
591
592
593
594
595
596
  
  	/*
  	 * 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...
597
598
  	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
  	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
8ddcd6532   Christoph Hellwig   block: introduce ...
599
600
601
602
  	if (disk->flags & GENHD_FL_HIDDEN) {
  		dev_set_uevent_suppress(ddev, 0);
  		return;
  	}
d2bf1b672   Tejun Heo   block: move regis...
603
  	/* No minors to use for partitions */
d27769ec3   Tejun Heo   block: add GENHD_...
604
  	if (!disk_part_scan_enabled(disk))
d2bf1b672   Tejun Heo   block: move regis...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  		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);
8ddcd6532   Christoph Hellwig   block: introduce ...
631

4d7c1d3fd   zhengbin   block: fix NULL p...
632
633
634
635
636
637
  	if (disk->queue->backing_dev_info->dev) {
  		err = sysfs_create_link(&ddev->kobj,
  			  &disk->queue->backing_dev_info->dev->kobj,
  			  "bdi");
  		WARN_ON(err);
  	}
d2bf1b672   Tejun Heo   block: move regis...
638
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  /**
fa70d2e2c   Mike Snitzer   block: allow gend...
640
   * __device_add_disk - add disk information to kernel list
e63a46bef   Dan Williams   block: introduce ...
641
   * @parent: parent device for the disk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
   * @disk: per-device partitioning information
fef912bf8   Hannes Reinecke   block: genhd: add...
643
   * @groups: Additional per-device sysfs groups
fa70d2e2c   Mike Snitzer   block: allow gend...
644
   * @register_queue: register the queue if set to true
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
   *
   * This function registers the partitioning information in @disk
   * with the kernel.
3e1a7ff8a   Tejun Heo   block: allow disk...
648
649
   *
   * FIXME: error handling
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
   */
fa70d2e2c   Mike Snitzer   block: allow gend...
651
  static void __device_add_disk(struct device *parent, struct gendisk *disk,
fef912bf8   Hannes Reinecke   block: genhd: add...
652
  			      const struct attribute_group **groups,
fa70d2e2c   Mike Snitzer   block: allow gend...
653
  			      bool register_queue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  {
3e1a7ff8a   Tejun Heo   block: allow disk...
655
  	dev_t devt;
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
656
  	int retval;
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
657

737eb78e8   Damien Le Moal   block: Delay defa...
658
659
660
661
662
663
664
665
  	/*
  	 * The disk queue should now be all set with enough information about
  	 * the device for the elevator code to pick an adequate default
  	 * elevator if one is needed, that is, for devices requesting queue
  	 * registration.
  	 */
  	if (register_queue)
  		elevator_init_mq(disk->queue);
3e1a7ff8a   Tejun Heo   block: allow disk...
666
667
668
669
670
  	/* 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));
8ddcd6532   Christoph Hellwig   block: introduce ...
671
672
  	WARN_ON(!disk->minors &&
  		!(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
3e1a7ff8a   Tejun Heo   block: allow disk...
673

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  	disk->flags |= GENHD_FL_UP;
3e1a7ff8a   Tejun Heo   block: allow disk...
675
676
677
678
679
680
  
  	retval = blk_alloc_devt(&disk->part0, &devt);
  	if (retval) {
  		WARN_ON(1);
  		return;
  	}
3e1a7ff8a   Tejun Heo   block: allow disk...
681
682
  	disk->major = MAJOR(devt);
  	disk->first_minor = MINOR(devt);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
683
  	disk_alloc_events(disk);
8ddcd6532   Christoph Hellwig   block: introduce ...
684
685
686
687
688
689
690
691
  	if (disk->flags & GENHD_FL_HIDDEN) {
  		/*
  		 * Don't let hidden disks show up in /proc/partitions,
  		 * and don't bother scanning for partitions either.
  		 */
  		disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
  		disk->flags |= GENHD_FL_NO_PART_SCAN;
  	} else {
3a92168bc   weiping zhang   block: add WARN_O...
692
  		int ret;
8ddcd6532   Christoph Hellwig   block: introduce ...
693
694
  		/* Register BDI before referencing it from bdev */
  		disk_to_dev(disk)->devt = devt;
3a92168bc   weiping zhang   block: add WARN_O...
695
696
697
  		ret = bdi_register_owner(disk->queue->backing_dev_info,
  						disk_to_dev(disk));
  		WARN_ON(ret);
8ddcd6532   Christoph Hellwig   block: introduce ...
698
699
700
  		blk_register_region(disk_devt(disk), disk->minors, NULL,
  				    exact_match, exact_lock, disk);
  	}
fef912bf8   Hannes Reinecke   block: genhd: add...
701
  	register_disk(parent, disk, groups);
fa70d2e2c   Mike Snitzer   block: allow gend...
702
703
  	if (register_queue)
  		blk_register_queue(disk);
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
704

523e1d399   Tejun Heo   block: make gendi...
705
706
707
708
  	/*
  	 * 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...
709
  	WARN_ON_ONCE(!blk_get_queue(disk->queue));
523e1d399   Tejun Heo   block: make gendi...
710

77ea887e4   Tejun Heo   implement in-kern...
711
  	disk_add_events(disk);
25520d55c   Martin K. Petersen   block: Inline blk...
712
  	blk_integrity_add(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  }
fa70d2e2c   Mike Snitzer   block: allow gend...
714

fef912bf8   Hannes Reinecke   block: genhd: add...
715
716
  void device_add_disk(struct device *parent, struct gendisk *disk,
  		     const struct attribute_group **groups)
fa70d2e2c   Mike Snitzer   block: allow gend...
717
  {
fef912bf8   Hannes Reinecke   block: genhd: add...
718
  	__device_add_disk(parent, disk, groups, true);
fa70d2e2c   Mike Snitzer   block: allow gend...
719
  }
e63a46bef   Dan Williams   block: introduce ...
720
  EXPORT_SYMBOL(device_add_disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721

fa70d2e2c   Mike Snitzer   block: allow gend...
722
723
  void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk)
  {
fef912bf8   Hannes Reinecke   block: genhd: add...
724
  	__device_add_disk(parent, disk, NULL, false);
fa70d2e2c   Mike Snitzer   block: allow gend...
725
726
  }
  EXPORT_SYMBOL(device_add_disk_no_queue_reg);
d2bf1b672   Tejun Heo   block: move regis...
727
  void del_gendisk(struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  {
d2bf1b672   Tejun Heo   block: move regis...
729
730
  	struct disk_part_iter piter;
  	struct hd_struct *part;
25520d55c   Martin K. Petersen   block: Inline blk...
731
  	blk_integrity_del(disk);
77ea887e4   Tejun Heo   implement in-kern...
732
  	disk_del_events(disk);
56c0908c8   Jan Kara   genhd: Fix BUG in...
733
734
735
736
737
  	/*
  	 * Block lookups of the disk until all bdevs are unhashed and the
  	 * disk is marked as dead (GENHD_FL_UP cleared).
  	 */
  	down_write(&disk->lookup_sem);
d2bf1b672   Tejun Heo   block: move regis...
738
739
740
741
742
  	/* 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);
4b8c861a7   Jan Kara   block: Move bdev_...
743
  		bdev_unhash_inode(part_devt(part));
d2bf1b672   Tejun Heo   block: move regis...
744
745
746
747
748
  		delete_partition(disk, part->partno);
  	}
  	disk_part_iter_exit(&piter);
  
  	invalidate_partition(disk, 0);
d06e05c02   Jan Kara   block: Unhash als...
749
  	bdev_unhash_inode(disk_devt(disk));
d2bf1b672   Tejun Heo   block: move regis...
750
751
  	set_capacity(disk, 0);
  	disk->flags &= ~GENHD_FL_UP;
56c0908c8   Jan Kara   genhd: Fix BUG in...
752
  	up_write(&disk->lookup_sem);
d2bf1b672   Tejun Heo   block: move regis...
753

8ddcd6532   Christoph Hellwig   block: introduce ...
754
755
  	if (!(disk->flags & GENHD_FL_HIDDEN))
  		sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
90f16fddc   Jan Kara   block: Make del_g...
756
757
758
759
760
  	if (disk->queue) {
  		/*
  		 * Unregister bdi before releasing device numbers (as they can
  		 * get reused and we'd get clashes in sysfs).
  		 */
bc8d062c3   Mike Snitzer   block: only bdi_u...
761
762
  		if (!(disk->flags & GENHD_FL_HIDDEN))
  			bdi_unregister(disk->queue->backing_dev_info);
90f16fddc   Jan Kara   block: Make del_g...
763
764
765
766
  		blk_unregister_queue(disk);
  	} else {
  		WARN_ON(1);
  	}
d2bf1b672   Tejun Heo   block: move regis...
767

17eac0996   Hannes Reinecke   block: create 'sl...
768
  	if (!(disk->flags & GENHD_FL_HIDDEN))
8ddcd6532   Christoph Hellwig   block: introduce ...
769
  		blk_unregister_region(disk_devt(disk), disk->minors);
6fcc44d1d   Yufen Yu   block: fix use-af...
770
771
772
773
774
775
776
  	/*
  	 * Remove gendisk pointer from idr so that it cannot be looked up
  	 * while RCU period before freeing gendisk is running to prevent
  	 * use-after-free issues. Note that the device number stays
  	 * "in-use" until we really free the gendisk.
  	 */
  	blk_invalidate_devt(disk_devt(disk));
d2bf1b672   Tejun Heo   block: move regis...
777
778
779
  
  	kobject_put(disk->part0.holder_dir);
  	kobject_put(disk->slave_dir);
d2bf1b672   Tejun Heo   block: move regis...
780
781
782
  
  	part_stat_set_all(&disk->part0, 0);
  	disk->part0.stamp = 0;
d2bf1b672   Tejun Heo   block: move regis...
783
784
  	if (!sysfs_deprecated)
  		sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
25e823c8c   Ming Lei   block/genhd.c: ap...
785
  	pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
d2bf1b672   Tejun Heo   block: move regis...
786
  	device_del(disk_to_dev(disk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  }
d2bf1b672   Tejun Heo   block: move regis...
788
  EXPORT_SYMBOL(del_gendisk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

99e6608c9   Vishal Verma   block: Add badblo...
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  /* 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
815
816
  /**
   * get_gendisk - get partitioning information for a given device
710027a48   Randy Dunlap   Add some block/ s...
817
   * @devt: device to get partitioning information for
496aa8a98   Randy Dunlap   block: fix curren...
818
   * @partno: returned partition index
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
   *
   * This function gets the structure containing partitioning
710027a48   Randy Dunlap   Add some block/ s...
821
   * information for the given device @devt.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
   */
cf771cb5a   Tejun Heo   block: make varia...
823
  struct gendisk *get_gendisk(dev_t devt, int *partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  {
bcce3de1b   Tejun Heo   block: implement ...
825
826
827
828
829
830
831
832
833
834
  	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...
835
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
836
  		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
3079c22ea   Jan Kara   genhd: Rename get...
837
  		if (part && get_disk_and_module(part_to_disk(part))) {
bcce3de1b   Tejun Heo   block: implement ...
838
839
840
  			*partno = part->partno;
  			disk = part_to_disk(part);
  		}
4d66e5e9b   Dan Williams   block: fix ext_de...
841
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
842
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
843

56c0908c8   Jan Kara   genhd: Fix BUG in...
844
845
846
847
848
849
850
851
852
853
854
  	if (!disk)
  		return NULL;
  
  	/*
  	 * Synchronize with del_gendisk() to not return disk that is being
  	 * destroyed.
  	 */
  	down_read(&disk->lookup_sem);
  	if (unlikely((disk->flags & GENHD_FL_HIDDEN) ||
  		     !(disk->flags & GENHD_FL_UP))) {
  		up_read(&disk->lookup_sem);
9df6c2991   Jan Kara   genhd: Add helper...
855
  		put_disk_and_module(disk);
8ddcd6532   Christoph Hellwig   block: introduce ...
856
  		disk = NULL;
56c0908c8   Jan Kara   genhd: Fix BUG in...
857
858
  	} else {
  		up_read(&disk->lookup_sem);
8ddcd6532   Christoph Hellwig   block: introduce ...
859
  	}
bcce3de1b   Tejun Heo   block: implement ...
860
  	return disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  }
b6ac23af2   Divyesh Shah   blkio: fix for mo...
862
  EXPORT_SYMBOL(get_gendisk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863

f331c0296   Tejun Heo   block: don't depe...
864
865
866
867
868
869
870
871
872
873
874
875
876
  /**
   * 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...
877
  struct block_device *bdget_disk(struct gendisk *disk, int partno)
f331c0296   Tejun Heo   block: don't depe...
878
  {
548b10eb2   Tejun Heo   block: move __dev...
879
880
  	struct hd_struct *part;
  	struct block_device *bdev = NULL;
f331c0296   Tejun Heo   block: don't depe...
881

548b10eb2   Tejun Heo   block: move __dev...
882
  	part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
883
  	if (part)
548b10eb2   Tejun Heo   block: move __dev...
884
885
  		bdev = bdget(part_devt(part));
  	disk_put_part(part);
f331c0296   Tejun Heo   block: don't depe...
886

548b10eb2   Tejun Heo   block: move __dev...
887
  	return bdev;
f331c0296   Tejun Heo   block: don't depe...
888
889
  }
  EXPORT_SYMBOL(bdget_disk);
dd2a345f8   Dave Gilbert   Display all possi...
890
  /*
5c6f35c5e   Greg Kroah-Hartman   block: make print...
891
892
893
894
895
896
   * 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_...
897
898
899
900
901
902
  	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->...
903
904
  		struct disk_part_iter piter;
  		struct hd_struct *part;
1f0142905   Tejun Heo   block: adjust for...
905
906
  		char name_buf[BDEVNAME_SIZE];
  		char devt_buf[BDEVT_SIZE];
def4e38dd   Tejun Heo   block: use class_...
907
908
909
  
  		/*
  		 * Don't show empty devices or things that have been
25985edce   Lucas De Marchi   Fix common misspe...
910
  		 * suppressed
def4e38dd   Tejun Heo   block: use class_...
911
912
913
914
915
916
917
918
919
920
  		 */
  		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...
921
922
923
  		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_...
924

b5af921ec   Will Drewry   init: add support...
925
  			printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
1f0142905   Tejun Heo   block: adjust for...
926
  			       bdevt_str(part_devt(part), devt_buf),
c83f6bf98   Vivek Goyal   block: add partit...
927
928
  			       (unsigned long long)part_nr_sects_read(part) >> 1
  			       , disk_name(disk, part->partno, name_buf),
1ad7e8994   Stephen Warren   block: store part...
929
  			       part->info ? part->info->uuid : "");
074a7aca7   Tejun Heo   block: move stats...
930
  			if (is_part0) {
52c44d93c   Dan Williams   block: remove ->d...
931
  				if (dev->parent && dev->parent->driver)
074a7aca7   Tejun Heo   block: move stats...
932
933
  					printk(" driver: %s
  ",
52c44d93c   Dan Williams   block: remove ->d...
934
  					      dev->parent->driver->name);
074a7aca7   Tejun Heo   block: move stats...
935
936
937
938
939
940
941
  				else
  					printk(" (driver?)
  ");
  			} else
  				printk("
  ");
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
942
  		disk_part_iter_exit(&piter);
def4e38dd   Tejun Heo   block: use class_...
943
944
  	}
  	class_dev_iter_exit(&iter);
dd2a345f8   Dave Gilbert   Display all possi...
945
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
  #ifdef CONFIG_PROC_FS
  /* iterator */
def4e38dd   Tejun Heo   block: use class_...
948
  static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
949
  {
def4e38dd   Tejun Heo   block: use class_...
950
951
952
  	loff_t skip = *pos;
  	struct class_dev_iter *iter;
  	struct device *dev;
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
953

aeb3d3a81   Harvey Harrison   block: kmalloc ar...
954
  	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
def4e38dd   Tejun Heo   block: use class_...
955
956
957
958
959
960
961
962
963
964
965
966
  	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 ...
967
  }
def4e38dd   Tejun Heo   block: use class_...
968
  static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  {
edfaa7c36   Kay Sievers   Driver core: conv...
970
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971

def4e38dd   Tejun Heo   block: use class_...
972
973
  	(*pos)++;
  	dev = class_dev_iter_next(seqf->private);
2ac3cee52   Tejun Heo   block: don't grab...
974
  	if (dev)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
975
  		return dev_to_disk(dev);
2ac3cee52   Tejun Heo   block: don't grab...
976

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
  	return NULL;
  }
def4e38dd   Tejun Heo   block: use class_...
979
  static void disk_seqf_stop(struct seq_file *seqf, void *v)
27f302519   Greg Kroah-Hartman   block: make /proc...
980
  {
def4e38dd   Tejun Heo   block: use class_...
981
  	struct class_dev_iter *iter = seqf->private;
27f302519   Greg Kroah-Hartman   block: make /proc...
982

def4e38dd   Tejun Heo   block: use class_...
983
984
985
986
  	/* stop is called even after start failed :-( */
  	if (iter) {
  		class_dev_iter_exit(iter);
  		kfree(iter);
77da16053   Vegard Nossum   block: fix use-af...
987
  		seqf->private = NULL;
5c0ef6d02   Kay Sievers   block: drop refer...
988
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  }
def4e38dd   Tejun Heo   block: use class_...
990
  static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  {
067680670   Jianpeng Ma   block: Don't use ...
992
  	void *p;
def4e38dd   Tejun Heo   block: use class_...
993
994
  
  	p = disk_seqf_start(seqf, pos);
b9f985b6e   Yang Zhang   block: convert !I...
995
  	if (!IS_ERR_OR_NULL(p) && !*pos)
def4e38dd   Tejun Heo   block: use class_...
996
997
998
999
  		seq_puts(seqf, "major minor  #blocks  name
  
  ");
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  }
cf771cb5a   Tejun Heo   block: make varia...
1001
  static int show_partition(struct seq_file *seqf, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
  {
  	struct gendisk *sgp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
1004
1005
  	struct disk_part_iter piter;
  	struct hd_struct *part;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  	char buf[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	/* Don't show non-partitionable removeable devices or empty devices */
d27769ec3   Tejun Heo   block: add GENHD_...
1008
  	if (!get_capacity(sgp) || (!disk_max_parts(sgp) &&
f331c0296   Tejun Heo   block: don't depe...
1009
  				   (sgp->flags & GENHD_FL_REMOVABLE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
1014
  		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...
1015
  	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1016
  	while ((part = disk_part_iter_next(&piter)))
1f0142905   Tejun Heo   block: adjust for...
1017
1018
  		seq_printf(seqf, "%4d  %7d %10llu %s
  ",
f331c0296   Tejun Heo   block: don't depe...
1019
  			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
c83f6bf98   Vivek Goyal   block: add partit...
1020
  			   (unsigned long long)part_nr_sects_read(part) >> 1,
f331c0296   Tejun Heo   block: don't depe...
1021
  			   disk_name(sgp, part->partno, buf));
e71bf0d0e   Tejun Heo   block: fix disk->...
1022
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
  
  	return 0;
  }
f500975a3   Alexey Dobriyan   proc: move rest o...
1026
  static const struct seq_operations partitions_op = {
def4e38dd   Tejun Heo   block: use class_...
1027
1028
1029
  	.start	= show_partition_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
edfaa7c36   Kay Sievers   Driver core: conv...
1030
  	.show	= show_partition
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
  };
  #endif
cf771cb5a   Tejun Heo   block: make varia...
1033
  static struct kobject *base_probe(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1035
  	if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
  		/* Make old-style 2.4 aliases work */
edfaa7c36   Kay Sievers   Driver core: conv...
1037
  		request_module("block-major-%d", MAJOR(devt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
1042
  	return NULL;
  }
  
  static int __init genhd_device_init(void)
  {
e105b8bfc   Dan Williams   sysfs: add /sys/d...
1043
1044
1045
1046
  	int error;
  
  	block_class.dev_kobj = sysfs_dev_block_kobj;
  	error = class_register(&block_class);
ee27a558a   Roland McGrath   genhd must_check ...
1047
1048
  	if (unlikely(error))
  		return error;
edfaa7c36   Kay Sievers   Driver core: conv...
1049
  	bdev_map = kobj_map_init(base_probe, &block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  	blk_dev_init();
edfaa7c36   Kay Sievers   Driver core: conv...
1051

561ec68e4   Zhang, Yanmin   block: fix boot f...
1052
  	register_blkdev(BLOCK_EXT_MAJOR, "blkext");
edfaa7c36   Kay Sievers   Driver core: conv...
1053
  	/* create top-level block dir */
e52eec13c   Andi Kleen   SYSFS: Allow boot...
1054
1055
  	if (!sysfs_deprecated)
  		block_depr = kobject_create_and_add("block", NULL);
830d3cfb1   Greg Kroah-Hartman   kset: convert blo...
1056
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
  }
  
  subsys_initcall(genhd_device_init);
edfaa7c36   Kay Sievers   Driver core: conv...
1060
1061
  static ssize_t disk_range_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1063
  	struct gendisk *disk = dev_to_disk(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064

edfaa7c36   Kay Sievers   Driver core: conv...
1065
1066
  	return sprintf(buf, "%d
  ", disk->minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  }
1f0142905   Tejun Heo   block: adjust for...
1068
1069
1070
1071
  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 ...
1072
1073
  	return sprintf(buf, "%d
  ", disk_max_parts(disk));
1f0142905   Tejun Heo   block: adjust for...
1074
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1075
1076
  static ssize_t disk_removable_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1077
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1078
  	struct gendisk *disk = dev_to_disk(dev);
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1079

edfaa7c36   Kay Sievers   Driver core: conv...
1080
1081
1082
  	return sprintf(buf, "%d
  ",
  		       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1083
  }
8ddcd6532   Christoph Hellwig   block: introduce ...
1084
1085
1086
1087
1088
1089
1090
1091
1092
  static ssize_t disk_hidden_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%d
  ",
  		       (disk->flags & GENHD_FL_HIDDEN ? 1 : 0));
  }
1c9ce5276   Kay Sievers   block: export "ro...
1093
1094
1095
1096
  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...
1097
1098
  	return sprintf(buf, "%d
  ", get_disk_ro(disk) ? 1 : 0);
1c9ce5276   Kay Sievers   block: export "ro...
1099
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1100
1101
  static ssize_t disk_capability_show(struct device *dev,
  				    struct device_attribute *attr, char *buf)
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
1102
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1103
1104
1105
1106
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%x
  ", disk->flags);
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
1107
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1108

c72758f33   Martin K. Petersen   block: Export I/O...
1109
1110
1111
1112
1113
1114
1115
1116
1117
  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...
1118
1119
1120
1121
1122
  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...
1123
1124
  	return sprintf(buf, "%d
  ", queue_discard_alignment(disk->queue));
86b372814   Martin K. Petersen   block: Expose dis...
1125
  }
5657a819a   Joe Perches   block drivers/blo...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  static DEVICE_ATTR(range, 0444, disk_range_show, NULL);
  static DEVICE_ATTR(ext_range, 0444, disk_ext_range_show, NULL);
  static DEVICE_ATTR(removable, 0444, disk_removable_show, NULL);
  static DEVICE_ATTR(hidden, 0444, disk_hidden_show, NULL);
  static DEVICE_ATTR(ro, 0444, disk_ro_show, NULL);
  static DEVICE_ATTR(size, 0444, part_size_show, NULL);
  static DEVICE_ATTR(alignment_offset, 0444, disk_alignment_offset_show, NULL);
  static DEVICE_ATTR(discard_alignment, 0444, disk_discard_alignment_show, NULL);
  static DEVICE_ATTR(capability, 0444, disk_capability_show, NULL);
  static DEVICE_ATTR(stat, 0444, part_stat_show, NULL);
  static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL);
  static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
1138
  #ifdef CONFIG_FAIL_MAKE_REQUEST
edfaa7c36   Kay Sievers   Driver core: conv...
1139
  static struct device_attribute dev_attr_fail =
5657a819a   Joe Perches   block drivers/blo...
1140
  	__ATTR(make-it-fail, 0644, part_fail_show, part_fail_store);
c17bb4951   Akinobu Mita   [PATCH] fault-inj...
1141
  #endif
581d4e28d   Jens Axboe   block: add fault ...
1142
1143
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  static struct device_attribute dev_attr_fail_timeout =
5657a819a   Joe Perches   block drivers/blo...
1144
  	__ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store);
581d4e28d   Jens Axboe   block: add fault ...
1145
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
1146
1147
1148
  
  static struct attribute *disk_attrs[] = {
  	&dev_attr_range.attr,
1f0142905   Tejun Heo   block: adjust for...
1149
  	&dev_attr_ext_range.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1150
  	&dev_attr_removable.attr,
8ddcd6532   Christoph Hellwig   block: introduce ...
1151
  	&dev_attr_hidden.attr,
1c9ce5276   Kay Sievers   block: export "ro...
1152
  	&dev_attr_ro.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1153
  	&dev_attr_size.attr,
c72758f33   Martin K. Petersen   block: Export I/O...
1154
  	&dev_attr_alignment_offset.attr,
86b372814   Martin K. Petersen   block: Expose dis...
1155
  	&dev_attr_discard_alignment.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1156
1157
  	&dev_attr_capability.attr,
  	&dev_attr_stat.attr,
316d315bf   Nikanth Karthikesan   block: Seperate r...
1158
  	&dev_attr_inflight.attr,
99e6608c9   Vishal Verma   block: Add badblo...
1159
  	&dev_attr_badblocks.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1160
1161
1162
  #ifdef CONFIG_FAIL_MAKE_REQUEST
  	&dev_attr_fail.attr,
  #endif
581d4e28d   Jens Axboe   block: add fault ...
1163
1164
1165
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  	&dev_attr_fail_timeout.attr,
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
1166
1167
  	NULL
  };
9438b3e08   Dan Williams   block: hide badbl...
1168
1169
1170
1171
1172
1173
1174
1175
1176
  static umode_t disk_visible(struct kobject *kobj, struct attribute *a, int n)
  {
  	struct device *dev = container_of(kobj, typeof(*dev), kobj);
  	struct gendisk *disk = dev_to_disk(dev);
  
  	if (a == &dev_attr_badblocks.attr && !disk->bb)
  		return 0;
  	return a->mode;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1177
1178
  static struct attribute_group disk_attr_group = {
  	.attrs = disk_attrs,
9438b3e08   Dan Williams   block: hide badbl...
1179
  	.is_visible = disk_visible,
edfaa7c36   Kay Sievers   Driver core: conv...
1180
  };
a4dbd6740   David Brownell   driver model: con...
1181
  static const struct attribute_group *disk_attr_groups[] = {
edfaa7c36   Kay Sievers   Driver core: conv...
1182
1183
  	&disk_attr_group,
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
  };
540eed563   Tejun Heo   block: make parti...
1185
1186
1187
1188
1189
1190
1191
1192
1193
  /**
   * 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:
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1194
   * Matching bd_mutex locked or the caller is the only user of @disk.
540eed563   Tejun Heo   block: make parti...
1195
1196
1197
1198
   */
  static void disk_replace_part_tbl(struct gendisk *disk,
  				  struct disk_part_tbl *new_ptbl)
  {
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1199
1200
  	struct disk_part_tbl *old_ptbl =
  		rcu_dereference_protected(disk->part_tbl, 1);
540eed563   Tejun Heo   block: make parti...
1201
1202
  
  	rcu_assign_pointer(disk->part_tbl, new_ptbl);
a6f23657d   Jens Axboe   block: add one-hi...
1203
1204
1205
  
  	if (old_ptbl) {
  		rcu_assign_pointer(old_ptbl->last_lookup, NULL);
57bdfbf9e   Lai Jiangshan   block,rcu: Conver...
1206
  		kfree_rcu(old_ptbl, rcu_head);
a6f23657d   Jens Axboe   block: add one-hi...
1207
  	}
540eed563   Tejun Heo   block: make parti...
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
  }
  
  /**
   * 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:
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1219
1220
   * Matching bd_mutex locked or the caller is the only user of @disk.
   * Might sleep.
540eed563   Tejun Heo   block: make parti...
1221
1222
1223
1224
1225
1226
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  int disk_expand_part_tbl(struct gendisk *disk, int partno)
  {
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1227
1228
  	struct disk_part_tbl *old_ptbl =
  		rcu_dereference_protected(disk->part_tbl, 1);
540eed563   Tejun Heo   block: make parti...
1229
1230
  	struct disk_part_tbl *new_ptbl;
  	int len = old_ptbl ? old_ptbl->len : 0;
5fabcb4c3   Jens Axboe   genhd: check for ...
1231
  	int i, target;
5fabcb4c3   Jens Axboe   genhd: check for ...
1232
1233
1234
1235
1236
1237
1238
1239
  
  	/*
  	 * 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...
1240
1241
1242
1243
1244
1245
1246
  
  	/* 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;
78b90a2ce   Gustavo A. R. Silva   block: genhd: Use...
1247
1248
  	new_ptbl = kzalloc_node(struct_size(new_ptbl, part, target), GFP_KERNEL,
  				disk->node_id);
540eed563   Tejun Heo   block: make parti...
1249
1250
  	if (!new_ptbl)
  		return -ENOMEM;
540eed563   Tejun Heo   block: make parti...
1251
1252
1253
1254
1255
1256
1257
1258
  	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...
1259
  static void disk_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1261
  	struct gendisk *disk = dev_to_disk(dev);
2da78092d   Keith Busch   block: Fix dev_t ...
1262
  	blk_free_devt(dev->devt);
77ea887e4   Tejun Heo   implement in-kern...
1263
  	disk_release_events(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
  	kfree(disk->random);
540eed563   Tejun Heo   block: make parti...
1265
  	disk_replace_part_tbl(disk, NULL);
b54e5ed8f   Ming Lei   block: partition:...
1266
  	hd_free_part(&disk->part0);
523e1d399   Tejun Heo   block: make gendi...
1267
1268
  	if (disk->queue)
  		blk_put_queue(disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
1270
  	kfree(disk);
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1271
1272
  struct class block_class = {
  	.name		= "block",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273
  };
3c2670e65   Kay Sievers   driver core: add ...
1274
  static char *block_devnode(struct device *dev, umode_t *mode,
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
1275
  			   kuid_t *uid, kgid_t *gid)
b03f38b68   Kay Sievers   Driver Core: bloc...
1276
1277
  {
  	struct gendisk *disk = dev_to_disk(dev);
e454cea20   Kay Sievers   Driver-Core: exte...
1278
1279
  	if (disk->devnode)
  		return disk->devnode(disk, mode);
b03f38b68   Kay Sievers   Driver Core: bloc...
1280
1281
  	return NULL;
  }
edf8ff558   Bart Van Assche   block: Constify d...
1282
  static const struct device_type disk_type = {
edfaa7c36   Kay Sievers   Driver core: conv...
1283
1284
1285
  	.name		= "disk",
  	.groups		= disk_attr_groups,
  	.release	= disk_release,
e454cea20   Kay Sievers   Driver-Core: exte...
1286
  	.devnode	= block_devnode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
  };
a6e2ba887   Randy Dunlap   block: make /proc...
1288
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
1289
1290
1291
1292
1293
1294
1295
1296
  /*
   * 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
1297
1298
  {
  	struct gendisk *gp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
1299
1300
  	struct disk_part_iter piter;
  	struct hd_struct *hd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
  	char buf[BDEVNAME_SIZE];
e016b7820   Mikulas Patocka   block: return jus...
1302
  	unsigned int inflight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
  
  	/*
ed9e19823   Tejun Heo   block: implement ...
1305
  	if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
cf771cb5a   Tejun Heo   block: make varia...
1306
  		seq_puts(seqf,	"major minor name"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
1309
1310
1311
1312
  				"     rio rmerge rsect ruse wio wmerge "
  				"wsect wuse running use aveq"
  				"
  
  ");
  	*/
9f5e48655   Wanlong Gao   block:remove some...
1313

71982a409   Tejun Heo   block: include em...
1314
  	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1315
  	while ((hd = disk_part_iter_next(&piter))) {
e016b7820   Mikulas Patocka   block: return jus...
1316
  		inflight = part_in_flight(gp->queue, hd);
bdca3c87f   Michael Callahan   block: Track DISC...
1317
1318
1319
1320
1321
1322
  		seq_printf(seqf, "%4d %7d %s "
  			   "%lu %lu %lu %u "
  			   "%lu %lu %lu %u "
  			   "%u %u %u "
  			   "%lu %lu %lu %u
  ",
f331c0296   Tejun Heo   block: don't depe...
1323
1324
  			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
  			   disk_name(gp, hd->partno, buf),
dbae2c551   Michael Callahan   block: Define and...
1325
1326
1327
  			   part_stat_read(hd, ios[STAT_READ]),
  			   part_stat_read(hd, merges[STAT_READ]),
  			   part_stat_read(hd, sectors[STAT_READ]),
b57e99b4b   Omar Sandoval   block: use nanose...
1328
  			   (unsigned int)part_stat_read_msecs(hd, STAT_READ),
dbae2c551   Michael Callahan   block: Define and...
1329
1330
1331
  			   part_stat_read(hd, ios[STAT_WRITE]),
  			   part_stat_read(hd, merges[STAT_WRITE]),
  			   part_stat_read(hd, sectors[STAT_WRITE]),
b57e99b4b   Omar Sandoval   block: use nanose...
1332
  			   (unsigned int)part_stat_read_msecs(hd, STAT_WRITE),
e016b7820   Mikulas Patocka   block: return jus...
1333
  			   inflight,
28f39d553   Jerome Marchand   Enhanced partitio...
1334
  			   jiffies_to_msecs(part_stat_read(hd, io_ticks)),
bdca3c87f   Michael Callahan   block: Track DISC...
1335
1336
1337
1338
  			   jiffies_to_msecs(part_stat_read(hd, time_in_queue)),
  			   part_stat_read(hd, ios[STAT_DISCARD]),
  			   part_stat_read(hd, merges[STAT_DISCARD]),
  			   part_stat_read(hd, sectors[STAT_DISCARD]),
b57e99b4b   Omar Sandoval   block: use nanose...
1339
  			   (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD)
28f39d553   Jerome Marchand   Enhanced partitio...
1340
  			);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
  	}
e71bf0d0e   Tejun Heo   block: fix disk->...
1342
  	disk_part_iter_exit(&piter);
9f5e48655   Wanlong Gao   block:remove some...
1343

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
  	return 0;
  }
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1346
  static const struct seq_operations diskstats_op = {
def4e38dd   Tejun Heo   block: use class_...
1347
1348
1349
  	.start	= disk_seqf_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
1351
  	.show	= diskstats_show
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
1352
1353
1354
  
  static int __init proc_genhd_init(void)
  {
fddda2b7b   Christoph Hellwig   proc: introduce p...
1355
1356
  	proc_create_seq("diskstats", 0, NULL, &diskstats_op);
  	proc_create_seq("partitions", 0, NULL, &partitions_op);
f500975a3   Alexey Dobriyan   proc: move rest o...
1357
1358
1359
  	return 0;
  }
  module_init(proc_genhd_init);
a6e2ba887   Randy Dunlap   block: make /proc...
1360
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361

cf771cb5a   Tejun Heo   block: make varia...
1362
  dev_t blk_lookup_devt(const char *name, int partno)
a142be856   Greg Kroah-Hartman   block: make blk_l...
1363
  {
def4e38dd   Tejun Heo   block: use class_...
1364
1365
1366
  	dev_t devt = MKDEV(0, 0);
  	struct class_dev_iter iter;
  	struct device *dev;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1367

def4e38dd   Tejun Heo   block: use class_...
1368
1369
  	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...
1370
  		struct gendisk *disk = dev_to_disk(dev);
548b10eb2   Tejun Heo   block: move __dev...
1371
  		struct hd_struct *part;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1372

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

41b8c853a   Neil Brown   block: fix bootin...
1376
1377
1378
1379
1380
1381
1382
1383
  		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...
1384
  		part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
1385
  		if (part) {
f331c0296   Tejun Heo   block: don't depe...
1386
  			devt = part_devt(part);
e71bf0d0e   Tejun Heo   block: fix disk->...
1387
  			disk_put_part(part);
548b10eb2   Tejun Heo   block: move __dev...
1388
  			break;
def4e38dd   Tejun Heo   block: use class_...
1389
  		}
548b10eb2   Tejun Heo   block: move __dev...
1390
  		disk_put_part(part);
5c0ef6d02   Kay Sievers   block: drop refer...
1391
  	}
def4e38dd   Tejun Heo   block: use class_...
1392
  	class_dev_iter_exit(&iter);
edfaa7c36   Kay Sievers   Driver core: conv...
1393
1394
  	return devt;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1395
  EXPORT_SYMBOL(blk_lookup_devt);
e319e1fbd   Byungchul Park   block, locking/lo...
1396
  struct gendisk *__alloc_disk_node(int minors, int node_id)
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1397
1398
  {
  	struct gendisk *disk;
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1399
  	struct disk_part_tbl *ptbl;
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1400

de65b0123   Christoph Hellwig   block: reject att...
1401
1402
  	if (minors > DISK_MAX_PARTS) {
  		printk(KERN_ERR
7fb526212   Randy Dunlap   block: genhd.c: f...
1403
1404
  			"block: can't allocate more than %d partitions
  ",
de65b0123   Christoph Hellwig   block: reject att...
1405
1406
1407
  			DISK_MAX_PARTS);
  		minors = DISK_MAX_PARTS;
  	}
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1408

c1b511eb2   Joe Perches   block: Convert km...
1409
  	disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
  	if (disk) {
074a7aca7   Tejun Heo   block: move stats...
1411
  		if (!init_part_stats(&disk->part0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
  			kfree(disk);
  			return NULL;
  		}
56c0908c8   Jan Kara   genhd: Fix BUG in...
1415
  		init_rwsem(&disk->lookup_sem);
bf91db18a   Cheng Renquan   block: set disk->...
1416
  		disk->node_id = node_id;
540eed563   Tejun Heo   block: make parti...
1417
1418
  		if (disk_expand_part_tbl(disk, 0)) {
  			free_part_stats(&disk->part0);
b5d0b9df0   Tejun Heo   block: introduce ...
1419
1420
  			kfree(disk);
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
  		}
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1422
1423
  		ptbl = rcu_dereference_protected(disk->part_tbl, 1);
  		rcu_assign_pointer(ptbl->part[0], &disk->part0);
6c23a9681   Jens Axboe   block: add intern...
1424

c83f6bf98   Vivek Goyal   block: add partit...
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  		/*
  		 * 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:...
1435
1436
1437
1438
1439
  		if (hd_ref_init(&disk->part0)) {
  			hd_free_part(&disk->part0);
  			kfree(disk);
  			return NULL;
  		}
b5d0b9df0   Tejun Heo   block: introduce ...
1440

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
  		disk->minors = minors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
  		rand_initialize_disk(disk);
ed9e19823   Tejun Heo   block: implement ...
1443
1444
1445
  		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
1446
1447
1448
  	}
  	return disk;
  }
e319e1fbd   Byungchul Park   block, locking/lo...
1449
  EXPORT_SYMBOL(__alloc_disk_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450

3079c22ea   Jan Kara   genhd: Rename get...
1451
  struct kobject *get_disk_and_module(struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
1454
1455
1456
1457
1458
1459
1460
  {
  	struct module *owner;
  	struct kobject *kobj;
  
  	if (!disk->fops)
  		return NULL;
  	owner = disk->fops->owner;
  	if (owner && !try_module_get(owner))
  		return NULL;
d01b2dcb4   Jan Kara   block: Fix oops s...
1461
  	kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
1465
1466
1467
1468
  	if (kobj == NULL) {
  		module_put(owner);
  		return NULL;
  	}
  	return kobj;
  
  }
3079c22ea   Jan Kara   genhd: Rename get...
1469
  EXPORT_SYMBOL(get_disk_and_module);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
1473
  
  void put_disk(struct gendisk *disk)
  {
  	if (disk)
ed9e19823   Tejun Heo   block: implement ...
1474
  		kobject_put(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
  EXPORT_SYMBOL(put_disk);
9df6c2991   Jan Kara   genhd: Add helper...
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
  /*
   * This is a counterpart of get_disk_and_module() and thus also of
   * get_gendisk().
   */
  void put_disk_and_module(struct gendisk *disk)
  {
  	if (disk) {
  		struct module *owner = disk->fops->owner;
  
  		put_disk(disk);
  		module_put(owner);
  	}
  }
  EXPORT_SYMBOL(put_disk_and_module);
e3264a4d7   Hannes Reinecke   Send uevents for ...
1491
1492
1493
1494
1495
1496
1497
1498
1499
  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
1500
1501
  void set_device_ro(struct block_device *bdev, int flag)
  {
b7db9956e   Tejun Heo   block: move polic...
1502
  	bdev->bd_part->policy = flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
1506
1507
1508
  }
  
  EXPORT_SYMBOL(set_device_ro);
  
  void set_disk_ro(struct gendisk *disk, int flag)
  {
e71bf0d0e   Tejun Heo   block: fix disk->...
1509
1510
  	struct disk_part_iter piter;
  	struct hd_struct *part;
e3264a4d7   Hannes Reinecke   Send uevents for ...
1511
1512
1513
1514
1515
1516
  	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->...
1517
1518
1519
  	while ((part = disk_part_iter_next(&piter)))
  		part->policy = flag;
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
1521
1522
1523
1524
1525
1526
1527
  }
  
  EXPORT_SYMBOL(set_disk_ro);
  
  int bdev_read_only(struct block_device *bdev)
  {
  	if (!bdev)
  		return 0;
b7db9956e   Tejun Heo   block: move polic...
1528
  	return bdev->bd_part->policy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
  }
  
  EXPORT_SYMBOL(bdev_read_only);
cf771cb5a   Tejun Heo   block: make varia...
1532
  int invalidate_partition(struct gendisk *disk, int partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
1534
  {
  	int res = 0;
cf771cb5a   Tejun Heo   block: make varia...
1535
  	struct block_device *bdev = bdget_disk(disk, partno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
  	if (bdev) {
2ef41634d   Christoph Hellwig   [PATCH] remove do...
1537
  		fsync_bdev(bdev);
93b270f76   NeilBrown   Fix over-zealous ...
1538
  		res = __invalidate_device(bdev, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
1540
1541
1542
1543
1544
  		bdput(bdev);
  	}
  	return res;
  }
  
  EXPORT_SYMBOL(invalidate_partition);
77ea887e4   Tejun Heo   implement in-kern...
1545
1546
1547
1548
1549
1550
1551
1552
  
  /*
   * 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_...
1553
  	struct mutex		block_mutex;	/* protects blocking */
77ea887e4   Tejun Heo   implement in-kern...
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
  	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...
1577
  static unsigned long disk_events_dfl_poll_msecs;
77ea887e4   Tejun Heo   implement in-kern...
1578
1579
1580
1581
1582
1583
1584
1585
  
  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
673387a93   Martin Wilck   block: genhd: rem...
1586
  	 * the default is being used, poll if the POLL flag is set.
77ea887e4   Tejun Heo   implement in-kern...
1587
1588
1589
  	 */
  	if (ev->poll_msecs >= 0)
  		intv_msecs = ev->poll_msecs;
c92e2f04b   Martin Wilck   block: disk_event...
1590
  	else if (disk->event_flags & DISK_EVENT_FLAG_POLL)
77ea887e4   Tejun Heo   implement in-kern...
1591
1592
1593
1594
  		intv_msecs = disk_events_dfl_poll_msecs;
  
  	return msecs_to_jiffies(intv_msecs);
  }
c3af54afb   Tejun Heo   block: remove non...
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
  /**
   * 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...
1611
1612
1613
1614
  {
  	struct disk_events *ev = disk->ev;
  	unsigned long flags;
  	bool cancel;
c3af54afb   Tejun Heo   block: remove non...
1615
1616
  	if (!ev)
  		return;
fdd514e16   Tejun Heo   block: make disk_...
1617
1618
1619
1620
1621
  	/*
  	 * 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...
1622
1623
1624
  	spin_lock_irqsave(&ev->lock, flags);
  	cancel = !ev->block++;
  	spin_unlock_irqrestore(&ev->lock, flags);
c3af54afb   Tejun Heo   block: remove non...
1625
1626
  	if (cancel)
  		cancel_delayed_work_sync(&disk->ev->dwork);
fdd514e16   Tejun Heo   block: make disk_...
1627
1628
  
  	mutex_unlock(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
  }
  
  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...
1644
  	intv = disk_events_poll_jiffies(disk);
77ea887e4   Tejun Heo   implement in-kern...
1645
  	if (check_now)
695588f94   Viresh Kumar   block: queue work...
1646
1647
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
77ea887e4   Tejun Heo   implement in-kern...
1648
  	else if (intv)
695588f94   Viresh Kumar   block: queue work...
1649
1650
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
1651
1652
1653
1654
1655
  out_unlock:
  	spin_unlock_irqrestore(&ev->lock, flags);
  }
  
  /**
77ea887e4   Tejun Heo   implement in-kern...
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
   * 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...
1668
  		__disk_unblock_events(disk, false);
77ea887e4   Tejun Heo   implement in-kern...
1669
1670
1671
  }
  
  /**
85ef06d1d   Tejun Heo   block: flush MEDI...
1672
1673
1674
   * 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...
1675
   *
85ef06d1d   Tejun Heo   block: flush MEDI...
1676
1677
1678
   * 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...
1679
1680
   *
   * CONTEXT:
85ef06d1d   Tejun Heo   block: flush MEDI...
1681
   * If @mask is non-zero must be called with bdev->bd_mutex held.
77ea887e4   Tejun Heo   implement in-kern...
1682
   */
85ef06d1d   Tejun Heo   block: flush MEDI...
1683
  void disk_flush_events(struct gendisk *disk, unsigned int mask)
77ea887e4   Tejun Heo   implement in-kern...
1684
  {
a9dce2a3b   Tejun Heo   block: don't use ...
1685
  	struct disk_events *ev = disk->ev;
a9dce2a3b   Tejun Heo   block: don't use ...
1686
1687
1688
  
  	if (!ev)
  		return;
85ef06d1d   Tejun Heo   block: flush MEDI...
1689
1690
  	spin_lock_irq(&ev->lock);
  	ev->clearing |= mask;
41f63c535   Tejun Heo   workqueue: use mo...
1691
  	if (!ev->block)
695588f94   Viresh Kumar   block: queue work...
1692
1693
  		mod_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
85ef06d1d   Tejun Heo   block: flush MEDI...
1694
  	spin_unlock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
1695
  }
77ea887e4   Tejun Heo   implement in-kern...
1696
1697
1698
1699
  
  /**
   * disk_clear_events - synchronously check, clear and return pending events
   * @disk: disk to fetch and clear events from
da3dae54e   Masanari Iida   Documentation: Do...
1700
   * @mask: mask of events to be fetched and cleared
77ea887e4   Tejun Heo   implement in-kern...
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
   *
   * 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...
1713
  	unsigned int clearing = mask;
77ea887e4   Tejun Heo   implement in-kern...
1714
1715
1716
1717
1718
1719
1720
1721
  
  	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...
1722
1723
1724
1725
1726
1727
1728
  	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...
1729
  	spin_lock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1730
1731
  	clearing |= ev->clearing;
  	ev->clearing = 0;
77ea887e4   Tejun Heo   implement in-kern...
1732
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1733
  	disk_check_events(ev, &clearing);
aea24a8bb   Derek Basehore   block: remove dea...
1734
  	/*
12c2bdb23   Derek Basehore   block: prevent ra...
1735
1736
  	 * 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...
1737
  	 */
12c2bdb23   Derek Basehore   block: prevent ra...
1738
  	__disk_unblock_events(disk, ev->clearing ? true : false);
77ea887e4   Tejun Heo   implement in-kern...
1739
1740
1741
  
  	/* then, fetch and clear pending events */
  	spin_lock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
1742
1743
1744
  	pending = ev->pending & mask;
  	ev->pending &= ~mask;
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1745
  	WARN_ON_ONCE(clearing & mask);
77ea887e4   Tejun Heo   implement in-kern...
1746
1747
1748
  
  	return pending;
  }
12c2bdb23   Derek Basehore   block: prevent ra...
1749
1750
1751
1752
  /*
   * 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...
1753
1754
1755
1756
  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...
1757
1758
1759
1760
1761
1762
1763
  
  	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...
1764
1765
  	struct gendisk *disk = ev->disk;
  	char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
12c2bdb23   Derek Basehore   block: prevent ra...
1766
  	unsigned int clearing = *clearing_ptr;
77ea887e4   Tejun Heo   implement in-kern...
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
  	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...
1779
  	*clearing_ptr &= ~clearing;
77ea887e4   Tejun Heo   implement in-kern...
1780
1781
1782
  
  	intv = disk_events_poll_jiffies(disk);
  	if (!ev->block && intv)
695588f94   Viresh Kumar   block: queue work...
1783
1784
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
1785
1786
  
  	spin_unlock_irq(&ev->lock);
7c88a168d   Tejun Heo   block: don't prop...
1787
1788
  	/*
  	 * Tell userland about new events.  Only the events listed in
c92e2f04b   Martin Wilck   block: disk_event...
1789
1790
1791
  	 * @disk->events are reported, and only if DISK_EVENT_FLAG_UEVENT
  	 * is set. Otherwise, events are processed internally but never
  	 * get reported to userland.
7c88a168d   Tejun Heo   block: don't prop...
1792
  	 */
77ea887e4   Tejun Heo   implement in-kern...
1793
  	for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
c92e2f04b   Martin Wilck   block: disk_event...
1794
1795
  		if ((events & disk->events & (1 << i)) &&
  		    (disk->event_flags & DISK_EVENT_FLAG_UEVENT))
77ea887e4   Tejun Heo   implement in-kern...
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
  			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
673387a93   Martin Wilck   block: genhd: rem...
1808
   *			  (always empty, only for backwards compatibility)
77ea887e4   Tejun Heo   implement in-kern...
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
   * 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);
c92e2f04b   Martin Wilck   block: disk_event...
1833
1834
  	if (!(disk->event_flags & DISK_EVENT_FLAG_UEVENT))
  		return 0;
77ea887e4   Tejun Heo   implement in-kern...
1835
1836
1837
1838
1839
1840
  	return __disk_events_show(disk->events, buf);
  }
  
  static ssize_t disk_events_async_show(struct device *dev,
  				      struct device_attribute *attr, char *buf)
  {
673387a93   Martin Wilck   block: genhd: rem...
1841
  	return 0;
77ea887e4   Tejun Heo   implement in-kern...
1842
1843
1844
1845
1846
1847
1848
  }
  
  static ssize_t disk_events_poll_msecs_show(struct device *dev,
  					   struct device_attribute *attr,
  					   char *buf)
  {
  	struct gendisk *disk = dev_to_disk(dev);
cdf3e3deb   Martin Wilck   block: check_even...
1849
1850
1851
  	if (!disk->ev)
  		return sprintf(buf, "-1
  ");
77ea887e4   Tejun Heo   implement in-kern...
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
  	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;
cdf3e3deb   Martin Wilck   block: check_even...
1868
1869
  	if (!disk->ev)
  		return -ENODEV;
c3af54afb   Tejun Heo   block: remove non...
1870
  	disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
1871
1872
1873
1874
1875
  	disk->ev->poll_msecs = intv;
  	__disk_unblock_events(disk, true);
  
  	return count;
  }
5657a819a   Joe Perches   block drivers/blo...
1876
1877
1878
  static const DEVICE_ATTR(events, 0444, disk_events_show, NULL);
  static const DEVICE_ATTR(events_async, 0444, disk_events_async_show, NULL);
  static const DEVICE_ATTR(events_poll_msecs, 0644,
77ea887e4   Tejun Heo   implement in-kern...
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
  			 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
1624b0b20   Akinobu Mita   block: fix sysfs ...
1893
   * /sys/module/block/parameters/events_dfl_poll_msecs.
77ea887e4   Tejun Heo   implement in-kern...
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
   */
  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...
1908
  		disk_flush_events(ev->disk, 0);
77ea887e4   Tejun Heo   implement in-kern...
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
  
  	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...
1927
   * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
77ea887e4   Tejun Heo   implement in-kern...
1928
   */
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1929
  static void disk_alloc_events(struct gendisk *disk)
77ea887e4   Tejun Heo   implement in-kern...
1930
1931
  {
  	struct disk_events *ev;
cdf3e3deb   Martin Wilck   block: check_even...
1932
  	if (!disk->fops->check_events || !disk->events)
77ea887e4   Tejun Heo   implement in-kern...
1933
1934
1935
1936
1937
1938
1939
1940
  		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...
1941
1942
1943
  	INIT_LIST_HEAD(&ev->node);
  	ev->disk = disk;
  	spin_lock_init(&ev->lock);
fdd514e16   Tejun Heo   block: make disk_...
1944
  	mutex_init(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1945
1946
1947
  	ev->block = 1;
  	ev->poll_msecs = -1;
  	INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1948
1949
1950
1951
1952
  	disk->ev = ev;
  }
  
  static void disk_add_events(struct gendisk *disk)
  {
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1953
1954
1955
1956
1957
  	/* 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);
cdf3e3deb   Martin Wilck   block: check_even...
1958
1959
  	if (!disk->ev)
  		return;
77ea887e4   Tejun Heo   implement in-kern...
1960
  	mutex_lock(&disk_events_mutex);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
1961
  	list_add_tail(&disk->ev->node, &disk_events);
77ea887e4   Tejun Heo   implement in-kern...
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
  	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)
  {
cdf3e3deb   Martin Wilck   block: check_even...
1973
1974
  	if (disk->ev) {
  		disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
1975

cdf3e3deb   Martin Wilck   block: check_even...
1976
1977
1978
1979
  		mutex_lock(&disk_events_mutex);
  		list_del_init(&disk->ev->node);
  		mutex_unlock(&disk_events_mutex);
  	}
77ea887e4   Tejun Heo   implement in-kern...
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
  
  	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);
  }