Blame view

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

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

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

2da78092d   Keith Busch   block: Fix dev_t ...
33
  /* For extended devt allocation.  ext_devt_lock prevents look up
bcce3de1b   Tejun Heo   block: implement ...
34
35
   * results from going away underneath its user.
   */
2da78092d   Keith Busch   block: Fix dev_t ...
36
  static DEFINE_SPINLOCK(ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
37
  static DEFINE_IDR(ext_devt_idr);
12c2bdb23   Derek Basehore   block: prevent ra...
38
39
  static void disk_check_events(struct disk_events *ev,
  			      unsigned int *clearing_ptr);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
40
  static void disk_alloc_events(struct gendisk *disk);
77ea887e4   Tejun Heo   implement in-kern...
41
42
43
  static void disk_add_events(struct gendisk *disk);
  static void disk_del_events(struct gendisk *disk);
  static void disk_release_events(struct gendisk *disk);
e598a72fa   Balbir Singh   block/genhd: Noti...
44
45
46
47
  /*
   * Set disk capacity and notify if the size is not currently
   * zero and will not be set to zero
   */
7e890c37c   Christoph Hellwig   block: add a retu...
48
  bool set_capacity_revalidate_and_notify(struct gendisk *disk, sector_t size,
b8086d3f5   Christoph Hellwig   block: use revali...
49
  					bool update_bdev)
e598a72fa   Balbir Singh   block/genhd: Noti...
50
51
52
53
  {
  	sector_t capacity = get_capacity(disk);
  
  	set_capacity(disk, size);
b8086d3f5   Christoph Hellwig   block: use revali...
54
55
  	if (update_bdev)
  		revalidate_disk_size(disk, true);
e598a72fa   Balbir Singh   block/genhd: Noti...
56
57
58
59
60
  
  	if (capacity != size && capacity != 0 && size != 0) {
  		char *envp[] = { "RESIZE=1", NULL };
  
  		kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
7e890c37c   Christoph Hellwig   block: add a retu...
61
  		return true;
e598a72fa   Balbir Singh   block/genhd: Noti...
62
  	}
7e890c37c   Christoph Hellwig   block: add a retu...
63
64
  
  	return false;
e598a72fa   Balbir Singh   block/genhd: Noti...
65
66
67
  }
  
  EXPORT_SYMBOL_GPL(set_capacity_revalidate_and_notify);
5cbd28e3c   Christoph Hellwig   block: move disk_...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  /*
   * Format the device name of the indicated disk into the supplied buffer and
   * return a pointer to that same buffer for convenience.
   */
  char *disk_name(struct gendisk *hd, int partno, char *buf)
  {
  	if (!partno)
  		snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
  	else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
  		snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
  	else
  		snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
  
  	return buf;
  }
  
  const char *bdevname(struct block_device *bdev, char *buf)
  {
8a63a86e1   Christoph Hellwig   block: use bd_par...
86
  	return disk_name(bdev->bd_disk, bdev->bd_partno, buf);
5cbd28e3c   Christoph Hellwig   block: move disk_...
87
88
  }
  EXPORT_SYMBOL(bdevname);
e598a72fa   Balbir Singh   block/genhd: Noti...
89

ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
  {
  	int cpu;
  
  	memset(stat, 0, sizeof(struct disk_stats));
  	for_each_possible_cpu(cpu) {
  		struct disk_stats *ptr = per_cpu_ptr(part->dkstats, cpu);
  		int group;
  
  		for (group = 0; group < NR_STAT_GROUPS; group++) {
  			stat->nsecs[group] += ptr->nsecs[group];
  			stat->sectors[group] += ptr->sectors[group];
  			stat->ios[group] += ptr->ios[group];
  			stat->merges[group] += ptr->merges[group];
  		}
  
  		stat->io_ticks += ptr->io_ticks;
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
107
108
  	}
  }
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
109

1f06959bd   Christoph Hellwig   block: remove the...
110
  static unsigned int part_in_flight(struct hd_struct *part)
f299b7c7a   Jens Axboe   blk-mq: provide i...
111
  {
b2f609e19   Christoph Hellwig   block: move the b...
112
  	unsigned int inflight = 0;
1226b8dd0   Mikulas Patocka   block: switch to ...
113
  	int cpu;
f299b7c7a   Jens Axboe   blk-mq: provide i...
114

1226b8dd0   Mikulas Patocka   block: switch to ...
115
  	for_each_possible_cpu(cpu) {
e016b7820   Mikulas Patocka   block: return jus...
116
117
  		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 ...
118
  	}
e016b7820   Mikulas Patocka   block: return jus...
119
120
  	if ((int)inflight < 0)
  		inflight = 0;
1226b8dd0   Mikulas Patocka   block: switch to ...
121

e016b7820   Mikulas Patocka   block: return jus...
122
  	return inflight;
f299b7c7a   Jens Axboe   blk-mq: provide i...
123
  }
1f06959bd   Christoph Hellwig   block: remove the...
124
  static void part_in_flight_rw(struct hd_struct *part, unsigned int inflight[2])
bf0ddaba6   Omar Sandoval   blk-mq: fix sysfs...
125
  {
1226b8dd0   Mikulas Patocka   block: switch to ...
126
  	int cpu;
1226b8dd0   Mikulas Patocka   block: switch to ...
127
128
129
130
131
132
133
134
135
136
  	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...
137
  }
807d4af2f   Christoph Hellwig   block: add a __di...
138
139
140
141
142
143
144
145
  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->...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  /**
   * 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...
162
  	struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
163

e71bf0d0e   Tejun Heo   block: fix disk->...
164
  	rcu_read_lock();
807d4af2f   Christoph Hellwig   block: add a __di...
165
166
167
  	part = __disk_get_part(disk, partno);
  	if (part)
  		get_device(part_to_dev(part));
e71bf0d0e   Tejun Heo   block: fix disk->...
168
169
170
171
  	rcu_read_unlock();
  
  	return part;
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  
  /**
   * 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...
187
188
189
190
  	struct disk_part_tbl *ptbl;
  
  	rcu_read_lock();
  	ptbl = rcu_dereference(disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
191
192
193
194
  	piter->disk = disk;
  	piter->part = NULL;
  
  	if (flags & DISK_PITER_REVERSE)
540eed563   Tejun Heo   block: make parti...
195
  		piter->idx = ptbl->len - 1;
71982a409   Tejun Heo   block: include em...
196
  	else if (flags & (DISK_PITER_INCL_PART0 | DISK_PITER_INCL_EMPTY_PART0))
e71bf0d0e   Tejun Heo   block: fix disk->...
197
  		piter->idx = 0;
b5d0b9df0   Tejun Heo   block: introduce ...
198
199
  	else
  		piter->idx = 1;
e71bf0d0e   Tejun Heo   block: fix disk->...
200
201
  
  	piter->flags = flags;
540eed563   Tejun Heo   block: make parti...
202
203
  
  	rcu_read_unlock();
e71bf0d0e   Tejun Heo   block: fix disk->...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  }
  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...
218
  	struct disk_part_tbl *ptbl;
e71bf0d0e   Tejun Heo   block: fix disk->...
219
220
221
222
223
  	int inc, end;
  
  	/* put the last partition */
  	disk_put_part(piter->part);
  	piter->part = NULL;
540eed563   Tejun Heo   block: make parti...
224
  	/* get part_tbl */
e71bf0d0e   Tejun Heo   block: fix disk->...
225
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
226
  	ptbl = rcu_dereference(piter->disk->part_tbl);
e71bf0d0e   Tejun Heo   block: fix disk->...
227
228
229
230
  
  	/* determine iteration parameters */
  	if (piter->flags & DISK_PITER_REVERSE) {
  		inc = -1;
71982a409   Tejun Heo   block: include em...
231
232
  		if (piter->flags & (DISK_PITER_INCL_PART0 |
  				    DISK_PITER_INCL_EMPTY_PART0))
b5d0b9df0   Tejun Heo   block: introduce ...
233
234
235
  			end = -1;
  		else
  			end = 0;
e71bf0d0e   Tejun Heo   block: fix disk->...
236
237
  	} else {
  		inc = 1;
540eed563   Tejun Heo   block: make parti...
238
  		end = ptbl->len;
e71bf0d0e   Tejun Heo   block: fix disk->...
239
240
241
242
243
  	}
  
  	/* iterate to the next partition */
  	for (; piter->idx != end; piter->idx += inc) {
  		struct hd_struct *part;
540eed563   Tejun Heo   block: make parti...
244
  		part = rcu_dereference(ptbl->part[piter->idx]);
e71bf0d0e   Tejun Heo   block: fix disk->...
245
246
  		if (!part)
  			continue;
481097d66   Ming Lei   block: fix use-af...
247
248
  		get_device(part_to_dev(part));
  		piter->part = part;
c83f6bf98   Vivek Goyal   block: add partit...
249
  		if (!part_nr_sects_read(part) &&
71982a409   Tejun Heo   block: include em...
250
251
  		    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
  		    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
481097d66   Ming Lei   block: fix use-af...
252
253
254
  		      piter->idx == 0)) {
  			put_device(part_to_dev(part));
  			piter->part = NULL;
e71bf0d0e   Tejun Heo   block: fix disk->...
255
  			continue;
481097d66   Ming Lei   block: fix use-af...
256
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
257

e71bf0d0e   Tejun Heo   block: fix disk->...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		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...
283
284
285
  static inline int sector_in_part(struct hd_struct *part, sector_t sector)
  {
  	return part->start_sect <= sector &&
c83f6bf98   Vivek Goyal   block: add partit...
286
  		sector < part->start_sect + part_nr_sects_read(part);
a6f23657d   Jens Axboe   block: add one-hi...
287
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
288
289
290
291
292
293
294
295
296
  /**
   * 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:
b7d6c3033   Ming Lei   block: fix use-af...
297
   * RCU read locked.  The returned partition pointer is always valid
27eb3af9a   Ming Lei   block: don't hold...
298
299
   * because its refcount is grabbed except for part0, which lifetime
   * is same with the disk.
e71bf0d0e   Tejun Heo   block: fix disk->...
300
301
   *
   * RETURNS:
074a7aca7   Tejun Heo   block: move stats...
302
   * Found partition on success, part0 is returned if no partition matches
b7d6c3033   Ming Lei   block: fix use-af...
303
   * or the matched partition is being deleted.
e71bf0d0e   Tejun Heo   block: fix disk->...
304
305
306
   */
  struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
  {
540eed563   Tejun Heo   block: make parti...
307
  	struct disk_part_tbl *ptbl;
a6f23657d   Jens Axboe   block: add one-hi...
308
  	struct hd_struct *part;
e71bf0d0e   Tejun Heo   block: fix disk->...
309
  	int i;
8ab1d40a6   Konstantin Khlebnikov   block: remove rcu...
310
  	rcu_read_lock();
540eed563   Tejun Heo   block: make parti...
311
  	ptbl = rcu_dereference(disk->part_tbl);
a6f23657d   Jens Axboe   block: add one-hi...
312
  	part = rcu_dereference(ptbl->last_lookup);
b7d6c3033   Ming Lei   block: fix use-af...
313
  	if (part && sector_in_part(part, sector) && hd_struct_try_get(part))
8ab1d40a6   Konstantin Khlebnikov   block: remove rcu...
314
  		goto out_unlock;
a6f23657d   Jens Axboe   block: add one-hi...
315

540eed563   Tejun Heo   block: make parti...
316
  	for (i = 1; i < ptbl->len; i++) {
a6f23657d   Jens Axboe   block: add one-hi...
317
  		part = rcu_dereference(ptbl->part[i]);
e71bf0d0e   Tejun Heo   block: fix disk->...
318

a6f23657d   Jens Axboe   block: add one-hi...
319
  		if (part && sector_in_part(part, sector)) {
b7d6c3033   Ming Lei   block: fix use-af...
320
321
322
323
324
325
326
  			/*
  			 * only live partition can be cached for lookup,
  			 * so use-after-free on cached & deleting partition
  			 * can be avoided
  			 */
  			if (!hd_struct_try_get(part))
  				break;
a6f23657d   Jens Axboe   block: add one-hi...
327
  			rcu_assign_pointer(ptbl->last_lookup, part);
8ab1d40a6   Konstantin Khlebnikov   block: remove rcu...
328
  			goto out_unlock;
a6f23657d   Jens Axboe   block: add one-hi...
329
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
330
  	}
8ab1d40a6   Konstantin Khlebnikov   block: remove rcu...
331
332
333
334
335
  
  	part = &disk->part0;
  out_unlock:
  	rcu_read_unlock();
  	return part;
e71bf0d0e   Tejun Heo   block: fix disk->...
336
  }
e71bf0d0e   Tejun Heo   block: fix disk->...
337

b53df2e74   Shin'ichiro Kawasaki   block: Fix partit...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  /**
   * disk_has_partitions
   * @disk: gendisk of interest
   *
   * Walk through the partition table and check if valid partition exists.
   *
   * CONTEXT:
   * Don't care.
   *
   * RETURNS:
   * True if the gendisk has at least one valid non-zero size partition.
   * Otherwise false.
   */
  bool disk_has_partitions(struct gendisk *disk)
  {
  	struct disk_part_tbl *ptbl;
  	int i;
  	bool ret = false;
  
  	rcu_read_lock();
  	ptbl = rcu_dereference(disk->part_tbl);
  
  	/* Iterate partitions skipping the whole device at index 0 */
  	for (i = 1; i < ptbl->len; i++) {
  		if (rcu_dereference(ptbl->part[i])) {
  			ret = true;
  			break;
  		}
  	}
  
  	rcu_read_unlock();
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(disk_has_partitions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
  /*
   * Can be deleted altogether. Later.
   *
   */
133d55cdb   Logan Gunthorpe   block: order /pro...
377
  #define BLKDEV_MAJOR_HASH_SIZE 255
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
  static struct blk_major_name {
  	struct blk_major_name *next;
  	int major;
  	char name[16];
68eef3b47   Joe Korty   [PATCH] Simplify ...
382
  } *major_names[BLKDEV_MAJOR_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  
  /* index in the above - for now: assume no multimajor ranges */
e61eb2e93   Yang Zhang   fs/block: type si...
385
  static inline int major_to_index(unsigned major)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
387
  	return major % BLKDEV_MAJOR_HASH_SIZE;
7170be5f5   Neil Horman   [PATCH] convert /...
388
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
389
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
390
  void blkdev_show(struct seq_file *seqf, off_t offset)
7170be5f5   Neil Horman   [PATCH] convert /...
391
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
392
  	struct blk_major_name *dp;
7170be5f5   Neil Horman   [PATCH] convert /...
393

133d55cdb   Logan Gunthorpe   block: order /pro...
394
395
396
  	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...
397
398
  			seq_printf(seqf, "%3d %s
  ", dp->major, dp->name);
133d55cdb   Logan Gunthorpe   block: order /pro...
399
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
401
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

9e8c0bccd   Márton Németh   block: add docume...
403
404
405
  /**
   * register_blkdev - register a new block device
   *
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
406
407
   * @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...
408
409
410
411
   * @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...
412
413
   * The return value depends on the @major input parameter:
   *
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
414
415
   *  - 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...
416
   *  - if any unused major number was requested with @major = 0 parameter
9e8c0bccd   Márton Németh   block: add docume...
417
   *    then the return value is the allocated major number in range
f33ff110e   Srivatsa S. Bhat   block, char_dev: ...
418
419
420
421
   *    [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...
422
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
  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...
427
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
431
432
433
434
435
436
  
  	/* 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...
437
438
439
  			printk("%s: failed to get major for %s
  ",
  			       __func__, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
443
444
445
  			ret = -EBUSY;
  			goto out;
  		}
  		major = index;
  		ret = major;
  	}
133d55cdb   Logan Gunthorpe   block: order /pro...
446
  	if (major >= BLKDEV_MAJOR_MAX) {
dfc76d11d   Keyur Patel   block: Replace fu...
447
448
449
  		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...
450
451
452
453
  
  		ret = -EINVAL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	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: ...
475
476
  		printk("register_blkdev: cannot get major %u for %s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
  		       major, name);
  		kfree(p);
  	}
  out:
edfaa7c36   Kay Sievers   Driver core: conv...
481
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
  	return ret;
  }
  
  EXPORT_SYMBOL(register_blkdev);
f4480240f   Akinobu Mita   unregister_blkdev...
486
  void unregister_blkdev(unsigned int major, const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
  {
  	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
491

edfaa7c36   Kay Sievers   Driver core: conv...
492
  	mutex_lock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
  	for (n = &major_names[index]; *n; n = &(*n)->next)
  		if ((*n)->major == major)
  			break;
294462a5c   Akinobu Mita   unregister_blkdev...
496
497
  	if (!*n || strcmp((*n)->name, name)) {
  		WARN_ON(1);
294462a5c   Akinobu Mita   unregister_blkdev...
498
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
  		p = *n;
  		*n = p->next;
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
502
  	mutex_unlock(&block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  	kfree(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
  }
  
  EXPORT_SYMBOL(unregister_blkdev);
  
  static struct kobj_map *bdev_map;
bcce3de1b   Tejun Heo   block: implement ...
509
  /**
870d66561   Tejun Heo   block: implement ...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
   * 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 ...
542
543
   * blk_alloc_devt - allocate a dev_t for a partition
   * @part: partition to allocate dev_t for
bcce3de1b   Tejun Heo   block: implement ...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
   * @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...
558
  	int idx;
bcce3de1b   Tejun Heo   block: implement ...
559
560
561
562
563
564
565
566
  
  	/* 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 ...
567
  	idr_preload(GFP_KERNEL);
4d66e5e9b   Dan Williams   block: fix ext_de...
568
  	spin_lock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
569
  	idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
4d66e5e9b   Dan Williams   block: fix ext_de...
570
  	spin_unlock_bh(&ext_devt_lock);
2da78092d   Keith Busch   block: Fix dev_t ...
571
572
  
  	idr_preload_end();
bab998d62   Tejun Heo   block: convert to...
573
574
  	if (idx < 0)
  		return idx == -ENOSPC ? -EBUSY : idx;
bcce3de1b   Tejun Heo   block: implement ...
575

870d66561   Tejun Heo   block: implement ...
576
  	*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
bcce3de1b   Tejun Heo   block: implement ...
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  	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 ...
591
592
593
594
  	if (devt == MKDEV(0, 0))
  		return;
  
  	if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
4d66e5e9b   Dan Williams   block: fix ext_de...
595
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
596
  		idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
4d66e5e9b   Dan Williams   block: fix ext_de...
597
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
598
599
  	}
  }
33c826ef1   Bart Van Assche   block: Convert bl...
600
601
  /*
   * We invalidate devt by assigning NULL pointer for devt in idr.
6fcc44d1d   Yufen Yu   block: fix use-af...
602
603
604
605
606
607
608
609
610
   */
  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...
611
612
613
614
615
616
617
618
619
620
621
  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
622
623
624
625
626
  /*
   * 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...
627
  void blk_register_region(dev_t devt, unsigned long range, struct module *module,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
  			 struct kobject *(*probe)(dev_t, int *, void *),
  			 int (*lock)(dev_t, void *), void *data)
  {
edfaa7c36   Kay Sievers   Driver core: conv...
631
  	kobj_map(bdev_map, devt, range, module, probe, lock, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
  }
  
  EXPORT_SYMBOL(blk_register_region);
edfaa7c36   Kay Sievers   Driver core: conv...
635
  void blk_unregister_region(dev_t devt, unsigned long range)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  {
edfaa7c36   Kay Sievers   Driver core: conv...
637
  	kobj_unmap(bdev_map, devt, range);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
  }
  
  EXPORT_SYMBOL(blk_unregister_region);
cf771cb5a   Tejun Heo   block: make varia...
641
  static struct kobject *exact_match(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
  {
  	struct gendisk *p = data;
edfaa7c36   Kay Sievers   Driver core: conv...
644

ed9e19823   Tejun Heo   block: implement ...
645
  	return &disk_to_dev(p)->kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  }
edfaa7c36   Kay Sievers   Driver core: conv...
647
  static int exact_lock(dev_t devt, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  {
  	struct gendisk *p = data;
3079c22ea   Jan Kara   genhd: Rename get...
650
  	if (!get_disk_and_module(p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
  		return -1;
  	return 0;
  }
9301fe734   Christoph Hellwig   block: cleanup pa...
654
655
656
657
658
659
660
661
662
663
664
665
  static void disk_scan_partitions(struct gendisk *disk)
  {
  	struct block_device *bdev;
  
  	if (!get_capacity(disk) || !disk_part_scan_enabled(disk))
  		return;
  
  	set_bit(GD_NEED_PART_SCAN, &disk->state);
  	bdev = blkdev_get_by_dev(disk_devt(disk), FMODE_READ, NULL);
  	if (!IS_ERR(bdev))
  		blkdev_put(bdev, FMODE_READ);
  }
fef912bf8   Hannes Reinecke   block: genhd: add...
666
667
  static void register_disk(struct device *parent, struct gendisk *disk,
  			  const struct attribute_group **groups)
d2bf1b672   Tejun Heo   block: move regis...
668
669
  {
  	struct device *ddev = disk_to_dev(disk);
d2bf1b672   Tejun Heo   block: move regis...
670
671
672
  	struct disk_part_iter piter;
  	struct hd_struct *part;
  	int err;
e63a46bef   Dan Williams   block: introduce ...
673
  	ddev->parent = parent;
d2bf1b672   Tejun Heo   block: move regis...
674

ffc8b3086   Kees Cook   block: do not pas...
675
  	dev_set_name(ddev, "%s", disk->disk_name);
d2bf1b672   Tejun Heo   block: move regis...
676
677
678
  
  	/* delay uevents, until we scanned partition table */
  	dev_set_uevent_suppress(ddev, 1);
fef912bf8   Hannes Reinecke   block: genhd: add...
679
680
681
682
  	if (groups) {
  		WARN_ON(ddev->groups);
  		ddev->groups = groups;
  	}
d2bf1b672   Tejun Heo   block: move regis...
683
684
685
686
687
688
689
690
691
692
  	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...
693
694
695
696
697
698
699
  
  	/*
  	 * 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...
700
701
  	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 ...
702
703
704
705
  	if (disk->flags & GENHD_FL_HIDDEN) {
  		dev_set_uevent_suppress(ddev, 0);
  		return;
  	}
9301fe734   Christoph Hellwig   block: cleanup pa...
706
  	disk_scan_partitions(disk);
d2bf1b672   Tejun Heo   block: move regis...
707

d2bf1b672   Tejun Heo   block: move regis...
708
709
710
711
712
713
714
715
716
  	/* 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 ...
717

4d7c1d3fd   zhengbin   block: fix NULL p...
718
719
720
721
722
723
  	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...
724
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  /**
fa70d2e2c   Mike Snitzer   block: allow gend...
726
   * __device_add_disk - add disk information to kernel list
e63a46bef   Dan Williams   block: introduce ...
727
   * @parent: parent device for the disk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
   * @disk: per-device partitioning information
fef912bf8   Hannes Reinecke   block: genhd: add...
729
   * @groups: Additional per-device sysfs groups
fa70d2e2c   Mike Snitzer   block: allow gend...
730
   * @register_queue: register the queue if set to true
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
   *
   * This function registers the partitioning information in @disk
   * with the kernel.
3e1a7ff8a   Tejun Heo   block: allow disk...
734
735
   *
   * FIXME: error handling
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
   */
fa70d2e2c   Mike Snitzer   block: allow gend...
737
  static void __device_add_disk(struct device *parent, struct gendisk *disk,
fef912bf8   Hannes Reinecke   block: genhd: add...
738
  			      const struct attribute_group **groups,
fa70d2e2c   Mike Snitzer   block: allow gend...
739
  			      bool register_queue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  {
3e1a7ff8a   Tejun Heo   block: allow disk...
741
  	dev_t devt;
6ffeea77f   Greg Kroah-Hartman   block: fix compil...
742
  	int retval;
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
743

737eb78e8   Damien Le Moal   block: Delay defa...
744
745
746
747
748
749
750
751
  	/*
  	 * 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...
752
753
754
755
756
  	/* 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 ...
757
758
  	WARN_ON(!disk->minors &&
  		!(disk->flags & (GENHD_FL_EXT_DEVT | GENHD_FL_HIDDEN)));
3e1a7ff8a   Tejun Heo   block: allow disk...
759

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  	disk->flags |= GENHD_FL_UP;
3e1a7ff8a   Tejun Heo   block: allow disk...
761
762
763
764
765
766
  
  	retval = blk_alloc_devt(&disk->part0, &devt);
  	if (retval) {
  		WARN_ON(1);
  		return;
  	}
3e1a7ff8a   Tejun Heo   block: allow disk...
767
768
  	disk->major = MAJOR(devt);
  	disk->first_minor = MINOR(devt);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
769
  	disk_alloc_events(disk);
8ddcd6532   Christoph Hellwig   block: introduce ...
770
771
772
773
774
775
776
777
  	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 {
3c5d202b5   Christoph Hellwig   bdi: remove bdi_r...
778
779
  		struct backing_dev_info *bdi = disk->queue->backing_dev_info;
  		struct device *dev = disk_to_dev(disk);
3a92168bc   weiping zhang   block: add WARN_O...
780
  		int ret;
8ddcd6532   Christoph Hellwig   block: introduce ...
781
  		/* Register BDI before referencing it from bdev */
3c5d202b5   Christoph Hellwig   bdi: remove bdi_r...
782
783
  		dev->devt = devt;
  		ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
3a92168bc   weiping zhang   block: add WARN_O...
784
  		WARN_ON(ret);
3c5d202b5   Christoph Hellwig   bdi: remove bdi_r...
785
  		bdi_set_owner(bdi, dev);
8ddcd6532   Christoph Hellwig   block: introduce ...
786
787
788
  		blk_register_region(disk_devt(disk), disk->minors, NULL,
  				    exact_match, exact_lock, disk);
  	}
fef912bf8   Hannes Reinecke   block: genhd: add...
789
  	register_disk(parent, disk, groups);
fa70d2e2c   Mike Snitzer   block: allow gend...
790
791
  	if (register_queue)
  		blk_register_queue(disk);
cf0ca9fe5   Peter Zijlstra   mm: bdi: export B...
792

523e1d399   Tejun Heo   block: make gendi...
793
794
795
796
  	/*
  	 * 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...
797
  	WARN_ON_ONCE(!blk_get_queue(disk->queue));
523e1d399   Tejun Heo   block: make gendi...
798

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

fef912bf8   Hannes Reinecke   block: genhd: add...
803
804
  void device_add_disk(struct device *parent, struct gendisk *disk,
  		     const struct attribute_group **groups)
fa70d2e2c   Mike Snitzer   block: allow gend...
805
  {
fef912bf8   Hannes Reinecke   block: genhd: add...
806
  	__device_add_disk(parent, disk, groups, true);
fa70d2e2c   Mike Snitzer   block: allow gend...
807
  }
e63a46bef   Dan Williams   block: introduce ...
808
  EXPORT_SYMBOL(device_add_disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809

fa70d2e2c   Mike Snitzer   block: allow gend...
810
811
  void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk)
  {
fef912bf8   Hannes Reinecke   block: genhd: add...
812
  	__device_add_disk(parent, disk, NULL, false);
fa70d2e2c   Mike Snitzer   block: allow gend...
813
814
  }
  EXPORT_SYMBOL(device_add_disk_no_queue_reg);
02d33b677   Christoph Hellwig   block: mark inval...
815
816
817
818
819
820
821
822
823
824
  static void invalidate_partition(struct gendisk *disk, int partno)
  {
  	struct block_device *bdev;
  
  	bdev = bdget_disk(disk, partno);
  	if (!bdev)
  		return;
  
  	fsync_bdev(bdev);
  	__invalidate_device(bdev, true);
9bc5c397d   Christoph Hellwig   block: fold bdev_...
825
826
827
828
829
830
  
  	/*
  	 * Unhash the bdev inode for this device so that it gets evicted as soon
  	 * as last inode reference is dropped.
  	 */
  	remove_inode_hash(bdev->bd_inode);
02d33b677   Christoph Hellwig   block: mark inval...
831
832
  	bdput(bdev);
  }
b5bd357cf   Luis Chamberlain   block: add docs f...
833
834
835
836
837
838
839
840
841
842
843
844
845
  /**
   * del_gendisk - remove the gendisk
   * @disk: the struct gendisk to remove
   *
   * Removes the gendisk and all its associated resources. This deletes the
   * partitions associated with the gendisk, and unregisters the associated
   * request_queue.
   *
   * This is the counter to the respective __device_add_disk() call.
   *
   * The final removal of the struct gendisk happens when its refcount reaches 0
   * with put_disk(), which should be called after del_gendisk(), if
   * __device_add_disk() was used.
e8c7d14ac   Luis Chamberlain   block: revert bac...
846
847
848
849
850
   *
   * Drivers exist which depend on the release of the gendisk to be synchronous,
   * it should not be deferred.
   *
   * Context: can sleep
b5bd357cf   Luis Chamberlain   block: add docs f...
851
   */
d2bf1b672   Tejun Heo   block: move regis...
852
  void del_gendisk(struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  {
d2bf1b672   Tejun Heo   block: move regis...
854
855
  	struct disk_part_iter piter;
  	struct hd_struct *part;
e8c7d14ac   Luis Chamberlain   block: revert bac...
856
  	might_sleep();
25520d55c   Martin K. Petersen   block: Inline blk...
857
  	blk_integrity_del(disk);
77ea887e4   Tejun Heo   implement in-kern...
858
  	disk_del_events(disk);
56c0908c8   Jan Kara   genhd: Fix BUG in...
859
860
861
862
863
  	/*
  	 * 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...
864
865
866
867
868
  	/* 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);
8328eb283   Christoph Hellwig   block: remove the...
869
  		delete_partition(part);
d2bf1b672   Tejun Heo   block: move regis...
870
871
872
873
  	}
  	disk_part_iter_exit(&piter);
  
  	invalidate_partition(disk, 0);
d2bf1b672   Tejun Heo   block: move regis...
874
875
  	set_capacity(disk, 0);
  	disk->flags &= ~GENHD_FL_UP;
56c0908c8   Jan Kara   genhd: Fix BUG in...
876
  	up_write(&disk->lookup_sem);
d2bf1b672   Tejun Heo   block: move regis...
877

8ddcd6532   Christoph Hellwig   block: introduce ...
878
879
  	if (!(disk->flags & GENHD_FL_HIDDEN))
  		sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
90f16fddc   Jan Kara   block: Make del_g...
880
881
882
883
884
  	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...
885
886
  		if (!(disk->flags & GENHD_FL_HIDDEN))
  			bdi_unregister(disk->queue->backing_dev_info);
90f16fddc   Jan Kara   block: Make del_g...
887
888
889
890
  		blk_unregister_queue(disk);
  	} else {
  		WARN_ON(1);
  	}
d2bf1b672   Tejun Heo   block: move regis...
891

17eac0996   Hannes Reinecke   block: create 'sl...
892
  	if (!(disk->flags & GENHD_FL_HIDDEN))
8ddcd6532   Christoph Hellwig   block: introduce ...
893
  		blk_unregister_region(disk_devt(disk), disk->minors);
6fcc44d1d   Yufen Yu   block: fix use-af...
894
895
896
897
898
899
900
  	/*
  	 * 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...
901
902
903
  
  	kobject_put(disk->part0.holder_dir);
  	kobject_put(disk->slave_dir);
d2bf1b672   Tejun Heo   block: move regis...
904
905
906
  
  	part_stat_set_all(&disk->part0, 0);
  	disk->part0.stamp = 0;
d2bf1b672   Tejun Heo   block: move regis...
907
908
  	if (!sysfs_deprecated)
  		sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
25e823c8c   Ming Lei   block/genhd.c: ap...
909
  	pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
d2bf1b672   Tejun Heo   block: move regis...
910
  	device_del(disk_to_dev(disk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  }
d2bf1b672   Tejun Heo   block: move regis...
912
  EXPORT_SYMBOL(del_gendisk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913

99e6608c9   Vishal Verma   block: Add badblo...
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
  /* 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
939
940
  /**
   * get_gendisk - get partitioning information for a given device
710027a48   Randy Dunlap   Add some block/ s...
941
   * @devt: device to get partitioning information for
496aa8a98   Randy Dunlap   block: fix curren...
942
   * @partno: returned partition index
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
   *
   * This function gets the structure containing partitioning
710027a48   Randy Dunlap   Add some block/ s...
945
   * information for the given device @devt.
763b58923   Luis Chamberlain   block: clarify co...
946
947
   *
   * Context: can sleep
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
   */
cf771cb5a   Tejun Heo   block: make varia...
949
  struct gendisk *get_gendisk(dev_t devt, int *partno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  {
bcce3de1b   Tejun Heo   block: implement ...
951
  	struct gendisk *disk = NULL;
763b58923   Luis Chamberlain   block: clarify co...
952
  	might_sleep();
bcce3de1b   Tejun Heo   block: implement ...
953
954
955
956
957
958
959
960
  	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...
961
  		spin_lock_bh(&ext_devt_lock);
870d66561   Tejun Heo   block: implement ...
962
  		part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
3079c22ea   Jan Kara   genhd: Rename get...
963
  		if (part && get_disk_and_module(part_to_disk(part))) {
bcce3de1b   Tejun Heo   block: implement ...
964
965
966
  			*partno = part->partno;
  			disk = part_to_disk(part);
  		}
4d66e5e9b   Dan Williams   block: fix ext_de...
967
  		spin_unlock_bh(&ext_devt_lock);
bcce3de1b   Tejun Heo   block: implement ...
968
  	}
edfaa7c36   Kay Sievers   Driver core: conv...
969

56c0908c8   Jan Kara   genhd: Fix BUG in...
970
971
972
973
974
975
976
977
978
979
980
  	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...
981
  		put_disk_and_module(disk);
8ddcd6532   Christoph Hellwig   block: introduce ...
982
  		disk = NULL;
56c0908c8   Jan Kara   genhd: Fix BUG in...
983
984
  	} else {
  		up_read(&disk->lookup_sem);
8ddcd6532   Christoph Hellwig   block: introduce ...
985
  	}
bcce3de1b   Tejun Heo   block: implement ...
986
  	return disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  }
f331c0296   Tejun Heo   block: don't depe...
988
989
990
991
992
993
994
995
996
997
998
999
1000
  /**
   * 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...
1001
  struct block_device *bdget_disk(struct gendisk *disk, int partno)
f331c0296   Tejun Heo   block: don't depe...
1002
  {
548b10eb2   Tejun Heo   block: move __dev...
1003
1004
  	struct hd_struct *part;
  	struct block_device *bdev = NULL;
f331c0296   Tejun Heo   block: don't depe...
1005

548b10eb2   Tejun Heo   block: move __dev...
1006
  	part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
1007
  	if (part)
10ed16662   Christoph Hellwig   block: add a bdge...
1008
  		bdev = bdget_part(part);
548b10eb2   Tejun Heo   block: move __dev...
1009
  	disk_put_part(part);
f331c0296   Tejun Heo   block: don't depe...
1010

548b10eb2   Tejun Heo   block: move __dev...
1011
  	return bdev;
f331c0296   Tejun Heo   block: don't depe...
1012
1013
  }
  EXPORT_SYMBOL(bdget_disk);
dd2a345f8   Dave Gilbert   Display all possi...
1014
  /*
5c6f35c5e   Greg Kroah-Hartman   block: make print...
1015
1016
1017
1018
1019
1020
   * 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_...
1021
1022
1023
1024
1025
1026
  	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->...
1027
1028
  		struct disk_part_iter piter;
  		struct hd_struct *part;
1f0142905   Tejun Heo   block: adjust for...
1029
1030
  		char name_buf[BDEVNAME_SIZE];
  		char devt_buf[BDEVT_SIZE];
def4e38dd   Tejun Heo   block: use class_...
1031
1032
1033
  
  		/*
  		 * Don't show empty devices or things that have been
25985edce   Lucas De Marchi   Fix common misspe...
1034
  		 * suppressed
def4e38dd   Tejun Heo   block: use class_...
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  		 */
  		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...
1045
1046
1047
  		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_...
1048

b5af921ec   Will Drewry   init: add support...
1049
  			printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
1f0142905   Tejun Heo   block: adjust for...
1050
  			       bdevt_str(part_devt(part), devt_buf),
c83f6bf98   Vivek Goyal   block: add partit...
1051
1052
  			       (unsigned long long)part_nr_sects_read(part) >> 1
  			       , disk_name(disk, part->partno, name_buf),
1ad7e8994   Stephen Warren   block: store part...
1053
  			       part->info ? part->info->uuid : "");
074a7aca7   Tejun Heo   block: move stats...
1054
  			if (is_part0) {
52c44d93c   Dan Williams   block: remove ->d...
1055
  				if (dev->parent && dev->parent->driver)
074a7aca7   Tejun Heo   block: move stats...
1056
1057
  					printk(" driver: %s
  ",
52c44d93c   Dan Williams   block: remove ->d...
1058
  					      dev->parent->driver->name);
074a7aca7   Tejun Heo   block: move stats...
1059
1060
1061
1062
1063
1064
1065
  				else
  					printk(" (driver?)
  ");
  			} else
  				printk("
  ");
  		}
e71bf0d0e   Tejun Heo   block: fix disk->...
1066
  		disk_part_iter_exit(&piter);
def4e38dd   Tejun Heo   block: use class_...
1067
1068
  	}
  	class_dev_iter_exit(&iter);
dd2a345f8   Dave Gilbert   Display all possi...
1069
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
  #ifdef CONFIG_PROC_FS
  /* iterator */
def4e38dd   Tejun Heo   block: use class_...
1072
  static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
1073
  {
def4e38dd   Tejun Heo   block: use class_...
1074
1075
1076
  	loff_t skip = *pos;
  	struct class_dev_iter *iter;
  	struct device *dev;
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
1077

aeb3d3a81   Harvey Harrison   block: kmalloc ar...
1078
  	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
def4e38dd   Tejun Heo   block: use class_...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	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 ...
1091
  }
def4e38dd   Tejun Heo   block: use class_...
1092
  static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1094
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095

def4e38dd   Tejun Heo   block: use class_...
1096
1097
  	(*pos)++;
  	dev = class_dev_iter_next(seqf->private);
2ac3cee52   Tejun Heo   block: don't grab...
1098
  	if (dev)
68c4d4a78   Greg Kroah-Hartman   block: make proc ...
1099
  		return dev_to_disk(dev);
2ac3cee52   Tejun Heo   block: don't grab...
1100

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
  	return NULL;
  }
def4e38dd   Tejun Heo   block: use class_...
1103
  static void disk_seqf_stop(struct seq_file *seqf, void *v)
27f302519   Greg Kroah-Hartman   block: make /proc...
1104
  {
def4e38dd   Tejun Heo   block: use class_...
1105
  	struct class_dev_iter *iter = seqf->private;
27f302519   Greg Kroah-Hartman   block: make /proc...
1106

def4e38dd   Tejun Heo   block: use class_...
1107
1108
1109
1110
  	/* stop is called even after start failed :-( */
  	if (iter) {
  		class_dev_iter_exit(iter);
  		kfree(iter);
77da16053   Vegard Nossum   block: fix use-af...
1111
  		seqf->private = NULL;
5c0ef6d02   Kay Sievers   block: drop refer...
1112
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
  }
def4e38dd   Tejun Heo   block: use class_...
1114
  static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
  {
067680670   Jianpeng Ma   block: Don't use ...
1116
  	void *p;
def4e38dd   Tejun Heo   block: use class_...
1117
1118
  
  	p = disk_seqf_start(seqf, pos);
b9f985b6e   Yang Zhang   block: convert !I...
1119
  	if (!IS_ERR_OR_NULL(p) && !*pos)
def4e38dd   Tejun Heo   block: use class_...
1120
1121
1122
1123
  		seq_puts(seqf, "major minor  #blocks  name
  
  ");
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  }
cf771cb5a   Tejun Heo   block: make varia...
1125
  static int show_partition(struct seq_file *seqf, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  {
  	struct gendisk *sgp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
1128
1129
  	struct disk_part_iter piter;
  	struct hd_struct *part;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  	char buf[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  	/* Don't show non-partitionable removeable devices or empty devices */
d27769ec3   Tejun Heo   block: add GENHD_...
1132
  	if (!get_capacity(sgp) || (!disk_max_parts(sgp) &&
f331c0296   Tejun Heo   block: don't depe...
1133
  				   (sgp->flags & GENHD_FL_REMOVABLE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
1136
1137
1138
  		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...
1139
  	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1140
  	while ((part = disk_part_iter_next(&piter)))
1f0142905   Tejun Heo   block: adjust for...
1141
1142
  		seq_printf(seqf, "%4d  %7d %10llu %s
  ",
f331c0296   Tejun Heo   block: don't depe...
1143
  			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
c83f6bf98   Vivek Goyal   block: add partit...
1144
  			   (unsigned long long)part_nr_sects_read(part) >> 1,
f331c0296   Tejun Heo   block: don't depe...
1145
  			   disk_name(sgp, part->partno, buf));
e71bf0d0e   Tejun Heo   block: fix disk->...
1146
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
  
  	return 0;
  }
f500975a3   Alexey Dobriyan   proc: move rest o...
1150
  static const struct seq_operations partitions_op = {
def4e38dd   Tejun Heo   block: use class_...
1151
1152
1153
  	.start	= show_partition_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
edfaa7c36   Kay Sievers   Driver core: conv...
1154
  	.show	= show_partition
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
  };
  #endif
cf771cb5a   Tejun Heo   block: make varia...
1157
  static struct kobject *base_probe(dev_t devt, int *partno, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1159
  	if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  		/* Make old-style 2.4 aliases work */
edfaa7c36   Kay Sievers   Driver core: conv...
1161
  		request_module("block-major-%d", MAJOR(devt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
1164
1165
1166
  	return NULL;
  }
  
  static int __init genhd_device_init(void)
  {
e105b8bfc   Dan Williams   sysfs: add /sys/d...
1167
1168
1169
1170
  	int error;
  
  	block_class.dev_kobj = sysfs_dev_block_kobj;
  	error = class_register(&block_class);
ee27a558a   Roland McGrath   genhd must_check ...
1171
1172
  	if (unlikely(error))
  		return error;
edfaa7c36   Kay Sievers   Driver core: conv...
1173
  	bdev_map = kobj_map_init(base_probe, &block_class_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
  	blk_dev_init();
edfaa7c36   Kay Sievers   Driver core: conv...
1175

561ec68e4   Zhang, Yanmin   block: fix boot f...
1176
  	register_blkdev(BLOCK_EXT_MAJOR, "blkext");
edfaa7c36   Kay Sievers   Driver core: conv...
1177
  	/* create top-level block dir */
e52eec13c   Andi Kleen   SYSFS: Allow boot...
1178
1179
  	if (!sysfs_deprecated)
  		block_depr = kobject_create_and_add("block", NULL);
830d3cfb1   Greg Kroah-Hartman   kset: convert blo...
1180
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
  }
  
  subsys_initcall(genhd_device_init);
edfaa7c36   Kay Sievers   Driver core: conv...
1184
1185
  static ssize_t disk_range_show(struct device *dev,
  			       struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1187
  	struct gendisk *disk = dev_to_disk(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188

edfaa7c36   Kay Sievers   Driver core: conv...
1189
1190
  	return sprintf(buf, "%d
  ", disk->minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
  }
1f0142905   Tejun Heo   block: adjust for...
1192
1193
1194
1195
  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 ...
1196
1197
  	return sprintf(buf, "%d
  ", disk_max_parts(disk));
1f0142905   Tejun Heo   block: adjust for...
1198
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1199
1200
  static ssize_t disk_removable_show(struct device *dev,
  				   struct device_attribute *attr, char *buf)
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1201
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1202
  	struct gendisk *disk = dev_to_disk(dev);
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1203

edfaa7c36   Kay Sievers   Driver core: conv...
1204
1205
1206
  	return sprintf(buf, "%d
  ",
  		       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
a7fd67062   Kay Sievers   [PATCH] add sysfs...
1207
  }
8ddcd6532   Christoph Hellwig   block: introduce ...
1208
1209
1210
1211
1212
1213
1214
1215
1216
  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...
1217
1218
1219
1220
  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...
1221
1222
  	return sprintf(buf, "%d
  ", get_disk_ro(disk) ? 1 : 0);
1c9ce5276   Kay Sievers   block: export "ro...
1223
  }
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  ssize_t part_size_show(struct device *dev,
  		       struct device_attribute *attr, char *buf)
  {
  	struct hd_struct *p = dev_to_part(dev);
  
  	return sprintf(buf, "%llu
  ",
  		(unsigned long long)part_nr_sects_read(p));
  }
  
  ssize_t part_stat_show(struct device *dev,
  		       struct device_attribute *attr, char *buf)
  {
  	struct hd_struct *p = dev_to_part(dev);
  	struct request_queue *q = part_to_disk(p)->queue;
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1239
  	struct disk_stats stat;
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1240
  	unsigned int inflight;
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1241
  	part_stat_read_all(p, &stat);
b2f609e19   Christoph Hellwig   block: move the b...
1242
1243
1244
  	if (queue_is_mq(q))
  		inflight = blk_mq_in_flight(q, p);
  	else
1f06959bd   Christoph Hellwig   block: remove the...
1245
  		inflight = part_in_flight(p);
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1246

3ad5cee5c   Christoph Hellwig   block: move sysfs...
1247
1248
1249
1250
1251
1252
1253
1254
  	return sprintf(buf,
  		"%8lu %8lu %8llu %8u "
  		"%8lu %8lu %8llu %8u "
  		"%8u %8u %8u "
  		"%8lu %8lu %8llu %8u "
  		"%8lu %8u"
  		"
  ",
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1255
1256
1257
1258
1259
1260
1261
1262
  		stat.ios[STAT_READ],
  		stat.merges[STAT_READ],
  		(unsigned long long)stat.sectors[STAT_READ],
  		(unsigned int)div_u64(stat.nsecs[STAT_READ], NSEC_PER_MSEC),
  		stat.ios[STAT_WRITE],
  		stat.merges[STAT_WRITE],
  		(unsigned long long)stat.sectors[STAT_WRITE],
  		(unsigned int)div_u64(stat.nsecs[STAT_WRITE], NSEC_PER_MSEC),
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1263
  		inflight,
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1264
  		jiffies_to_msecs(stat.io_ticks),
8cd5b8fc0   Konstantin Khlebnikov   block/diskstats: ...
1265
1266
1267
1268
1269
  		(unsigned int)div_u64(stat.nsecs[STAT_READ] +
  				      stat.nsecs[STAT_WRITE] +
  				      stat.nsecs[STAT_DISCARD] +
  				      stat.nsecs[STAT_FLUSH],
  						NSEC_PER_MSEC),
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1270
1271
1272
1273
1274
1275
  		stat.ios[STAT_DISCARD],
  		stat.merges[STAT_DISCARD],
  		(unsigned long long)stat.sectors[STAT_DISCARD],
  		(unsigned int)div_u64(stat.nsecs[STAT_DISCARD], NSEC_PER_MSEC),
  		stat.ios[STAT_FLUSH],
  		(unsigned int)div_u64(stat.nsecs[STAT_FLUSH], NSEC_PER_MSEC));
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1276
1277
1278
1279
1280
1281
1282
1283
  }
  
  ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
  			   char *buf)
  {
  	struct hd_struct *p = dev_to_part(dev);
  	struct request_queue *q = part_to_disk(p)->queue;
  	unsigned int inflight[2];
b2f609e19   Christoph Hellwig   block: move the b...
1284
1285
1286
  	if (queue_is_mq(q))
  		blk_mq_in_flight_rw(q, p, inflight);
  	else
1f06959bd   Christoph Hellwig   block: remove the...
1287
  		part_in_flight_rw(p, inflight);
b2f609e19   Christoph Hellwig   block: move the b...
1288

3ad5cee5c   Christoph Hellwig   block: move sysfs...
1289
1290
1291
  	return sprintf(buf, "%8u %8u
  ", inflight[0], inflight[1]);
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1292
1293
  static ssize_t disk_capability_show(struct device *dev,
  				    struct device_attribute *attr, char *buf)
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
1294
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1295
1296
1297
1298
  	struct gendisk *disk = dev_to_disk(dev);
  
  	return sprintf(buf, "%x
  ", disk->flags);
86ce18d7b   Kristen Carlson Accardi   genhd: expose AN ...
1299
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1300

c72758f33   Martin K. Petersen   block: Export I/O...
1301
1302
1303
1304
1305
1306
1307
1308
1309
  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...
1310
1311
1312
1313
1314
  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...
1315
1316
  	return sprintf(buf, "%d
  ", queue_discard_alignment(disk->queue));
86b372814   Martin K. Petersen   block: Expose dis...
1317
  }
5657a819a   Joe Perches   block drivers/blo...
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
  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);
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1330

c17bb4951   Akinobu Mita   [PATCH] fault-inj...
1331
  #ifdef CONFIG_FAIL_MAKE_REQUEST
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
  ssize_t part_fail_show(struct device *dev,
  		       struct device_attribute *attr, char *buf)
  {
  	struct hd_struct *p = dev_to_part(dev);
  
  	return sprintf(buf, "%d
  ", p->make_it_fail);
  }
  
  ssize_t part_fail_store(struct device *dev,
  			struct device_attribute *attr,
  			const char *buf, size_t count)
  {
  	struct hd_struct *p = dev_to_part(dev);
  	int i;
  
  	if (count > 0 && sscanf(buf, "%d", &i) > 0)
  		p->make_it_fail = (i == 0) ? 0 : 1;
  
  	return count;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1353
  static struct device_attribute dev_attr_fail =
5657a819a   Joe Perches   block drivers/blo...
1354
  	__ATTR(make-it-fail, 0644, part_fail_show, part_fail_store);
3ad5cee5c   Christoph Hellwig   block: move sysfs...
1355
  #endif /* CONFIG_FAIL_MAKE_REQUEST */
581d4e28d   Jens Axboe   block: add fault ...
1356
1357
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  static struct device_attribute dev_attr_fail_timeout =
5657a819a   Joe Perches   block drivers/blo...
1358
  	__ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store);
581d4e28d   Jens Axboe   block: add fault ...
1359
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
1360
1361
1362
  
  static struct attribute *disk_attrs[] = {
  	&dev_attr_range.attr,
1f0142905   Tejun Heo   block: adjust for...
1363
  	&dev_attr_ext_range.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1364
  	&dev_attr_removable.attr,
8ddcd6532   Christoph Hellwig   block: introduce ...
1365
  	&dev_attr_hidden.attr,
1c9ce5276   Kay Sievers   block: export "ro...
1366
  	&dev_attr_ro.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1367
  	&dev_attr_size.attr,
c72758f33   Martin K. Petersen   block: Export I/O...
1368
  	&dev_attr_alignment_offset.attr,
86b372814   Martin K. Petersen   block: Expose dis...
1369
  	&dev_attr_discard_alignment.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1370
1371
  	&dev_attr_capability.attr,
  	&dev_attr_stat.attr,
316d315bf   Nikanth Karthikesan   block: Seperate r...
1372
  	&dev_attr_inflight.attr,
99e6608c9   Vishal Verma   block: Add badblo...
1373
  	&dev_attr_badblocks.attr,
edfaa7c36   Kay Sievers   Driver core: conv...
1374
1375
1376
  #ifdef CONFIG_FAIL_MAKE_REQUEST
  	&dev_attr_fail.attr,
  #endif
581d4e28d   Jens Axboe   block: add fault ...
1377
1378
1379
  #ifdef CONFIG_FAIL_IO_TIMEOUT
  	&dev_attr_fail_timeout.attr,
  #endif
edfaa7c36   Kay Sievers   Driver core: conv...
1380
1381
  	NULL
  };
9438b3e08   Dan Williams   block: hide badbl...
1382
1383
1384
1385
1386
1387
1388
1389
1390
  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...
1391
1392
  static struct attribute_group disk_attr_group = {
  	.attrs = disk_attrs,
9438b3e08   Dan Williams   block: hide badbl...
1393
  	.is_visible = disk_visible,
edfaa7c36   Kay Sievers   Driver core: conv...
1394
  };
a4dbd6740   David Brownell   driver model: con...
1395
  static const struct attribute_group *disk_attr_groups[] = {
edfaa7c36   Kay Sievers   Driver core: conv...
1396
1397
  	&disk_attr_group,
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  };
540eed563   Tejun Heo   block: make parti...
1399
1400
1401
1402
1403
1404
1405
1406
1407
  /**
   * 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...
1408
   * Matching bd_mutex locked or the caller is the only user of @disk.
540eed563   Tejun Heo   block: make parti...
1409
1410
1411
1412
   */
  static void disk_replace_part_tbl(struct gendisk *disk,
  				  struct disk_part_tbl *new_ptbl)
  {
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1413
1414
  	struct disk_part_tbl *old_ptbl =
  		rcu_dereference_protected(disk->part_tbl, 1);
540eed563   Tejun Heo   block: make parti...
1415
1416
  
  	rcu_assign_pointer(disk->part_tbl, new_ptbl);
a6f23657d   Jens Axboe   block: add one-hi...
1417
1418
1419
  
  	if (old_ptbl) {
  		rcu_assign_pointer(old_ptbl->last_lookup, NULL);
57bdfbf9e   Lai Jiangshan   block,rcu: Conver...
1420
  		kfree_rcu(old_ptbl, rcu_head);
a6f23657d   Jens Axboe   block: add one-hi...
1421
  	}
540eed563   Tejun Heo   block: make parti...
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
  }
  
  /**
   * 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...
1433
1434
   * Matching bd_mutex locked or the caller is the only user of @disk.
   * Might sleep.
540eed563   Tejun Heo   block: make parti...
1435
1436
1437
1438
1439
1440
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  int disk_expand_part_tbl(struct gendisk *disk, int partno)
  {
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1441
1442
  	struct disk_part_tbl *old_ptbl =
  		rcu_dereference_protected(disk->part_tbl, 1);
540eed563   Tejun Heo   block: make parti...
1443
1444
  	struct disk_part_tbl *new_ptbl;
  	int len = old_ptbl ? old_ptbl->len : 0;
5fabcb4c3   Jens Axboe   genhd: check for ...
1445
  	int i, target;
5fabcb4c3   Jens Axboe   genhd: check for ...
1446
1447
1448
1449
1450
1451
1452
1453
  
  	/*
  	 * 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...
1454
1455
1456
1457
1458
1459
1460
  
  	/* 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...
1461
1462
  	new_ptbl = kzalloc_node(struct_size(new_ptbl, part, target), GFP_KERNEL,
  				disk->node_id);
540eed563   Tejun Heo   block: make parti...
1463
1464
  	if (!new_ptbl)
  		return -ENOMEM;
540eed563   Tejun Heo   block: make parti...
1465
1466
1467
1468
1469
1470
1471
1472
  	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;
  }
b5bd357cf   Luis Chamberlain   block: add docs f...
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
  /**
   * disk_release - releases all allocated resources of the gendisk
   * @dev: the device representing this disk
   *
   * This function releases all allocated resources of the gendisk.
   *
   * The struct gendisk refcount is incremented with get_gendisk() or
   * get_disk_and_module(), and its refcount is decremented with
   * put_disk_and_module() or put_disk(). Once the refcount reaches 0 this
   * function is called.
   *
   * Drivers which used __device_add_disk() have a gendisk with a request_queue
   * assigned. Since the request_queue sits on top of the gendisk for these
   * drivers we also call blk_put_queue() for them, and we expect the
   * request_queue refcount to reach 0 at this point, and so the request_queue
   * will also be freed prior to the disk.
e8c7d14ac   Luis Chamberlain   block: revert bac...
1489
1490
   *
   * Context: can sleep
b5bd357cf   Luis Chamberlain   block: add docs f...
1491
   */
edfaa7c36   Kay Sievers   Driver core: conv...
1492
  static void disk_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
  {
edfaa7c36   Kay Sievers   Driver core: conv...
1494
  	struct gendisk *disk = dev_to_disk(dev);
e8c7d14ac   Luis Chamberlain   block: revert bac...
1495
  	might_sleep();
2da78092d   Keith Busch   block: Fix dev_t ...
1496
  	blk_free_devt(dev->devt);
77ea887e4   Tejun Heo   implement in-kern...
1497
  	disk_release_events(disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
  	kfree(disk->random);
540eed563   Tejun Heo   block: make parti...
1499
  	disk_replace_part_tbl(disk, NULL);
b54e5ed8f   Ming Lei   block: partition:...
1500
  	hd_free_part(&disk->part0);
523e1d399   Tejun Heo   block: make gendi...
1501
1502
  	if (disk->queue)
  		blk_put_queue(disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
  	kfree(disk);
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1505
1506
  struct class block_class = {
  	.name		= "block",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  };
3c2670e65   Kay Sievers   driver core: add ...
1508
  static char *block_devnode(struct device *dev, umode_t *mode,
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
1509
  			   kuid_t *uid, kgid_t *gid)
b03f38b68   Kay Sievers   Driver Core: bloc...
1510
1511
  {
  	struct gendisk *disk = dev_to_disk(dev);
348e114bb   Christoph Hellwig   block: move the -...
1512
1513
  	if (disk->fops->devnode)
  		return disk->fops->devnode(disk, mode);
b03f38b68   Kay Sievers   Driver Core: bloc...
1514
1515
  	return NULL;
  }
ef45fe470   Boris Burkov   blk-cgroup: show ...
1516
  const struct device_type disk_type = {
edfaa7c36   Kay Sievers   Driver core: conv...
1517
1518
1519
  	.name		= "disk",
  	.groups		= disk_attr_groups,
  	.release	= disk_release,
e454cea20   Kay Sievers   Driver-Core: exte...
1520
  	.devnode	= block_devnode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
  };
a6e2ba887   Randy Dunlap   block: make /proc...
1522
  #ifdef CONFIG_PROC_FS
cf771cb5a   Tejun Heo   block: make varia...
1523
1524
1525
1526
1527
1528
1529
1530
  /*
   * 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
1531
1532
  {
  	struct gendisk *gp = v;
e71bf0d0e   Tejun Heo   block: fix disk->...
1533
1534
  	struct disk_part_iter piter;
  	struct hd_struct *hd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  	char buf[BDEVNAME_SIZE];
e016b7820   Mikulas Patocka   block: return jus...
1536
  	unsigned int inflight;
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1537
  	struct disk_stats stat;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
1539
  
  	/*
ed9e19823   Tejun Heo   block: implement ...
1540
  	if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
cf771cb5a   Tejun Heo   block: make varia...
1541
  		seq_puts(seqf,	"major minor name"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
1543
1544
1545
1546
1547
  				"     rio rmerge rsect ruse wio wmerge "
  				"wsect wuse running use aveq"
  				"
  
  ");
  	*/
9f5e48655   Wanlong Gao   block:remove some...
1548

71982a409   Tejun Heo   block: include em...
1549
  	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
e71bf0d0e   Tejun Heo   block: fix disk->...
1550
  	while ((hd = disk_part_iter_next(&piter))) {
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1551
  		part_stat_read_all(hd, &stat);
b2f609e19   Christoph Hellwig   block: move the b...
1552
1553
1554
  		if (queue_is_mq(gp->queue))
  			inflight = blk_mq_in_flight(gp->queue, hd);
  		else
1f06959bd   Christoph Hellwig   block: remove the...
1555
  			inflight = part_in_flight(hd);
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1556

bdca3c87f   Michael Callahan   block: Track DISC...
1557
1558
1559
1560
  		seq_printf(seqf, "%4d %7d %s "
  			   "%lu %lu %lu %u "
  			   "%lu %lu %lu %u "
  			   "%u %u %u "
b68663186   Konstantin Khlebnikov   block: add iostat...
1561
1562
1563
1564
  			   "%lu %lu %lu %u "
  			   "%lu %u"
  			   "
  ",
f331c0296   Tejun Heo   block: don't depe...
1565
1566
  			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
  			   disk_name(gp, hd->partno, buf),
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
  			   stat.ios[STAT_READ],
  			   stat.merges[STAT_READ],
  			   stat.sectors[STAT_READ],
  			   (unsigned int)div_u64(stat.nsecs[STAT_READ],
  							NSEC_PER_MSEC),
  			   stat.ios[STAT_WRITE],
  			   stat.merges[STAT_WRITE],
  			   stat.sectors[STAT_WRITE],
  			   (unsigned int)div_u64(stat.nsecs[STAT_WRITE],
  							NSEC_PER_MSEC),
e016b7820   Mikulas Patocka   block: return jus...
1577
  			   inflight,
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1578
  			   jiffies_to_msecs(stat.io_ticks),
8cd5b8fc0   Konstantin Khlebnikov   block/diskstats: ...
1579
1580
1581
1582
1583
  			   (unsigned int)div_u64(stat.nsecs[STAT_READ] +
  						 stat.nsecs[STAT_WRITE] +
  						 stat.nsecs[STAT_DISCARD] +
  						 stat.nsecs[STAT_FLUSH],
  							NSEC_PER_MSEC),
ea18e0f0a   Konstantin Khlebnikov   block/diskstats: ...
1584
1585
1586
1587
1588
1589
1590
1591
  			   stat.ios[STAT_DISCARD],
  			   stat.merges[STAT_DISCARD],
  			   stat.sectors[STAT_DISCARD],
  			   (unsigned int)div_u64(stat.nsecs[STAT_DISCARD],
  						 NSEC_PER_MSEC),
  			   stat.ios[STAT_FLUSH],
  			   (unsigned int)div_u64(stat.nsecs[STAT_FLUSH],
  						 NSEC_PER_MSEC)
28f39d553   Jerome Marchand   Enhanced partitio...
1592
  			);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  	}
e71bf0d0e   Tejun Heo   block: fix disk->...
1594
  	disk_part_iter_exit(&piter);
9f5e48655   Wanlong Gao   block:remove some...
1595

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596
1597
  	return 0;
  }
31d85ab28   Alexey Dobriyan   proc: move /proc/...
1598
  static const struct seq_operations diskstats_op = {
def4e38dd   Tejun Heo   block: use class_...
1599
1600
1601
  	.start	= disk_seqf_start,
  	.next	= disk_seqf_next,
  	.stop	= disk_seqf_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
1603
  	.show	= diskstats_show
  };
f500975a3   Alexey Dobriyan   proc: move rest o...
1604
1605
1606
  
  static int __init proc_genhd_init(void)
  {
fddda2b7b   Christoph Hellwig   proc: introduce p...
1607
1608
  	proc_create_seq("diskstats", 0, NULL, &diskstats_op);
  	proc_create_seq("partitions", 0, NULL, &partitions_op);
f500975a3   Alexey Dobriyan   proc: move rest o...
1609
1610
1611
  	return 0;
  }
  module_init(proc_genhd_init);
a6e2ba887   Randy Dunlap   block: make /proc...
1612
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613

cf771cb5a   Tejun Heo   block: make varia...
1614
  dev_t blk_lookup_devt(const char *name, int partno)
a142be856   Greg Kroah-Hartman   block: make blk_l...
1615
  {
def4e38dd   Tejun Heo   block: use class_...
1616
1617
1618
  	dev_t devt = MKDEV(0, 0);
  	struct class_dev_iter iter;
  	struct device *dev;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1619

def4e38dd   Tejun Heo   block: use class_...
1620
1621
  	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...
1622
  		struct gendisk *disk = dev_to_disk(dev);
548b10eb2   Tejun Heo   block: move __dev...
1623
  		struct hd_struct *part;
a142be856   Greg Kroah-Hartman   block: make blk_l...
1624

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

41b8c853a   Neil Brown   block: fix bootin...
1628
1629
1630
1631
1632
1633
1634
1635
  		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...
1636
  		part = disk_get_part(disk, partno);
2bbedcb4c   Tejun Heo   block: don't test...
1637
  		if (part) {
f331c0296   Tejun Heo   block: don't depe...
1638
  			devt = part_devt(part);
e71bf0d0e   Tejun Heo   block: fix disk->...
1639
  			disk_put_part(part);
548b10eb2   Tejun Heo   block: move __dev...
1640
  			break;
def4e38dd   Tejun Heo   block: use class_...
1641
  		}
548b10eb2   Tejun Heo   block: move __dev...
1642
  		disk_put_part(part);
5c0ef6d02   Kay Sievers   block: drop refer...
1643
  	}
def4e38dd   Tejun Heo   block: use class_...
1644
  	class_dev_iter_exit(&iter);
edfaa7c36   Kay Sievers   Driver core: conv...
1645
1646
  	return devt;
  }
edfaa7c36   Kay Sievers   Driver core: conv...
1647

e319e1fbd   Byungchul Park   block, locking/lo...
1648
  struct gendisk *__alloc_disk_node(int minors, int node_id)
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1649
1650
  {
  	struct gendisk *disk;
6d2cf6f2b   Bart Van Assche   genhd: Annotate a...
1651
  	struct disk_part_tbl *ptbl;
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1652

de65b0123   Christoph Hellwig   block: reject att...
1653
1654
  	if (minors > DISK_MAX_PARTS) {
  		printk(KERN_ERR
7fb526212   Randy Dunlap   block: genhd.c: f...
1655
1656
  			"block: can't allocate more than %d partitions
  ",
de65b0123   Christoph Hellwig   block: reject att...
1657
1658
1659
  			DISK_MAX_PARTS);
  		minors = DISK_MAX_PARTS;
  	}
1946089a1   Christoph Lameter   [PATCH] NUMA awar...
1660

c1b511eb2   Joe Perches   block: Convert km...
1661
  	disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
f93af2a49   Christoph Hellwig   block: cleanup __...
1662
1663
  	if (!disk)
  		return NULL;
6c23a9681   Jens Axboe   block: add intern...
1664

f93af2a49   Christoph Hellwig   block: cleanup __...
1665
1666
1667
  	disk->part0.dkstats = alloc_percpu(struct disk_stats);
  	if (!disk->part0.dkstats)
  		goto out_free_disk;
b5d0b9df0   Tejun Heo   block: introduce ...
1668

f93af2a49   Christoph Hellwig   block: cleanup __...
1669
1670
1671
1672
1673
  	init_rwsem(&disk->lookup_sem);
  	disk->node_id = node_id;
  	if (disk_expand_part_tbl(disk, 0)) {
  		free_percpu(disk->part0.dkstats);
  		goto out_free_disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
  	}
f93af2a49   Christoph Hellwig   block: cleanup __...
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
  
  	ptbl = rcu_dereference_protected(disk->part_tbl, 1);
  	rcu_assign_pointer(ptbl->part[0], &disk->part0);
  
  	/*
  	 * 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.
  	 */
  	hd_sects_seq_init(&disk->part0);
  	if (hd_ref_init(&disk->part0))
  		goto out_free_part0;
  
  	disk->minors = minors;
  	rand_initialize_disk(disk);
  	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
1697
  	return disk;
f93af2a49   Christoph Hellwig   block: cleanup __...
1698
1699
1700
1701
1702
1703
  
  out_free_part0:
  	hd_free_part(&disk->part0);
  out_free_disk:
  	kfree(disk);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
  }
e319e1fbd   Byungchul Park   block, locking/lo...
1705
  EXPORT_SYMBOL(__alloc_disk_node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1706

b5bd357cf   Luis Chamberlain   block: add docs f...
1707
1708
  /**
   * get_disk_and_module - increments the gendisk and gendisk fops module refcount
0d20dcc27   Randy Dunlap   block: genhd: del...
1709
   * @disk: the struct gendisk to increment the refcount for
b5bd357cf   Luis Chamberlain   block: add docs f...
1710
1711
1712
   *
   * This increments the refcount for the struct gendisk, and the gendisk's
   * fops module owner.
763b58923   Luis Chamberlain   block: clarify co...
1713
1714
   *
   * Context: Any context.
b5bd357cf   Luis Chamberlain   block: add docs f...
1715
   */
3079c22ea   Jan Kara   genhd: Rename get...
1716
  struct kobject *get_disk_and_module(struct gendisk *disk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1717
1718
1719
1720
1721
1722
1723
1724
1725
  {
  	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...
1726
  	kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1727
1728
1729
1730
1731
1732
1733
  	if (kobj == NULL) {
  		module_put(owner);
  		return NULL;
  	}
  	return kobj;
  
  }
3079c22ea   Jan Kara   genhd: Rename get...
1734
  EXPORT_SYMBOL(get_disk_and_module);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735

b5bd357cf   Luis Chamberlain   block: add docs f...
1736
1737
  /**
   * put_disk - decrements the gendisk refcount
0d20dcc27   Randy Dunlap   block: genhd: del...
1738
   * @disk: the struct gendisk to decrement the refcount for
b5bd357cf   Luis Chamberlain   block: add docs f...
1739
1740
1741
   *
   * This decrements the refcount for the struct gendisk. When this reaches 0
   * we'll have disk_release() called.
e8c7d14ac   Luis Chamberlain   block: revert bac...
1742
1743
1744
   *
   * Context: Any context, but the last reference must not be dropped from
   *          atomic context.
b5bd357cf   Luis Chamberlain   block: add docs f...
1745
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746
1747
1748
  void put_disk(struct gendisk *disk)
  {
  	if (disk)
ed9e19823   Tejun Heo   block: implement ...
1749
  		kobject_put(&disk_to_dev(disk)->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
  EXPORT_SYMBOL(put_disk);
b5bd357cf   Luis Chamberlain   block: add docs f...
1752
1753
  /**
   * put_disk_and_module - decrements the module and gendisk refcount
0d20dcc27   Randy Dunlap   block: genhd: del...
1754
   * @disk: the struct gendisk to decrement the refcount for
b5bd357cf   Luis Chamberlain   block: add docs f...
1755
   *
9df6c2991   Jan Kara   genhd: Add helper...
1756
1757
   * This is a counterpart of get_disk_and_module() and thus also of
   * get_gendisk().
e8c7d14ac   Luis Chamberlain   block: revert bac...
1758
1759
1760
   *
   * Context: Any context, but the last reference must not be dropped from
   *          atomic context.
9df6c2991   Jan Kara   genhd: Add helper...
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
   */
  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 ...
1772
1773
1774
1775
1776
1777
1778
1779
1780
  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
1781
1782
  void set_device_ro(struct block_device *bdev, int flag)
  {
b7db9956e   Tejun Heo   block: move polic...
1783
  	bdev->bd_part->policy = flag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
  }
  
  EXPORT_SYMBOL(set_device_ro);
  
  void set_disk_ro(struct gendisk *disk, int flag)
  {
e71bf0d0e   Tejun Heo   block: fix disk->...
1790
1791
  	struct disk_part_iter piter;
  	struct hd_struct *part;
e3264a4d7   Hannes Reinecke   Send uevents for ...
1792
1793
1794
1795
1796
1797
  	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->...
1798
1799
1800
  	while ((part = disk_part_iter_next(&piter)))
  		part->policy = flag;
  	disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
1802
1803
1804
1805
1806
1807
1808
  }
  
  EXPORT_SYMBOL(set_disk_ro);
  
  int bdev_read_only(struct block_device *bdev)
  {
  	if (!bdev)
  		return 0;
b7db9956e   Tejun Heo   block: move polic...
1809
  	return bdev->bd_part->policy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
1811
1812
  }
  
  EXPORT_SYMBOL(bdev_read_only);
77ea887e4   Tejun Heo   implement in-kern...
1813
1814
1815
1816
1817
1818
1819
  /*
   * 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_...
1820
  	struct mutex		block_mutex;	/* protects blocking */
77ea887e4   Tejun Heo   implement in-kern...
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  	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...
1844
  static unsigned long disk_events_dfl_poll_msecs;
77ea887e4   Tejun Heo   implement in-kern...
1845
1846
1847
1848
1849
1850
1851
1852
  
  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...
1853
  	 * the default is being used, poll if the POLL flag is set.
77ea887e4   Tejun Heo   implement in-kern...
1854
1855
1856
  	 */
  	if (ev->poll_msecs >= 0)
  		intv_msecs = ev->poll_msecs;
c92e2f04b   Martin Wilck   block: disk_event...
1857
  	else if (disk->event_flags & DISK_EVENT_FLAG_POLL)
77ea887e4   Tejun Heo   implement in-kern...
1858
1859
1860
1861
  		intv_msecs = disk_events_dfl_poll_msecs;
  
  	return msecs_to_jiffies(intv_msecs);
  }
c3af54afb   Tejun Heo   block: remove non...
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
  /**
   * 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...
1878
1879
1880
1881
  {
  	struct disk_events *ev = disk->ev;
  	unsigned long flags;
  	bool cancel;
c3af54afb   Tejun Heo   block: remove non...
1882
1883
  	if (!ev)
  		return;
fdd514e16   Tejun Heo   block: make disk_...
1884
1885
1886
1887
1888
  	/*
  	 * 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...
1889
1890
1891
  	spin_lock_irqsave(&ev->lock, flags);
  	cancel = !ev->block++;
  	spin_unlock_irqrestore(&ev->lock, flags);
c3af54afb   Tejun Heo   block: remove non...
1892
1893
  	if (cancel)
  		cancel_delayed_work_sync(&disk->ev->dwork);
fdd514e16   Tejun Heo   block: make disk_...
1894
1895
  
  	mutex_unlock(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
  }
  
  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...
1911
  	intv = disk_events_poll_jiffies(disk);
77ea887e4   Tejun Heo   implement in-kern...
1912
  	if (check_now)
695588f94   Viresh Kumar   block: queue work...
1913
1914
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
77ea887e4   Tejun Heo   implement in-kern...
1915
  	else if (intv)
695588f94   Viresh Kumar   block: queue work...
1916
1917
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
1918
1919
1920
1921
1922
  out_unlock:
  	spin_unlock_irqrestore(&ev->lock, flags);
  }
  
  /**
77ea887e4   Tejun Heo   implement in-kern...
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
   * 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...
1935
  		__disk_unblock_events(disk, false);
77ea887e4   Tejun Heo   implement in-kern...
1936
1937
1938
  }
  
  /**
85ef06d1d   Tejun Heo   block: flush MEDI...
1939
1940
1941
   * 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...
1942
   *
85ef06d1d   Tejun Heo   block: flush MEDI...
1943
1944
1945
   * 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...
1946
1947
   *
   * CONTEXT:
85ef06d1d   Tejun Heo   block: flush MEDI...
1948
   * If @mask is non-zero must be called with bdev->bd_mutex held.
77ea887e4   Tejun Heo   implement in-kern...
1949
   */
85ef06d1d   Tejun Heo   block: flush MEDI...
1950
  void disk_flush_events(struct gendisk *disk, unsigned int mask)
77ea887e4   Tejun Heo   implement in-kern...
1951
  {
a9dce2a3b   Tejun Heo   block: don't use ...
1952
  	struct disk_events *ev = disk->ev;
a9dce2a3b   Tejun Heo   block: don't use ...
1953
1954
1955
  
  	if (!ev)
  		return;
85ef06d1d   Tejun Heo   block: flush MEDI...
1956
1957
  	spin_lock_irq(&ev->lock);
  	ev->clearing |= mask;
41f63c535   Tejun Heo   workqueue: use mo...
1958
  	if (!ev->block)
695588f94   Viresh Kumar   block: queue work...
1959
1960
  		mod_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, 0);
85ef06d1d   Tejun Heo   block: flush MEDI...
1961
  	spin_unlock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
1962
  }
77ea887e4   Tejun Heo   implement in-kern...
1963
1964
1965
1966
  
  /**
   * disk_clear_events - synchronously check, clear and return pending events
   * @disk: disk to fetch and clear events from
da3dae54e   Masanari Iida   Documentation: Do...
1967
   * @mask: mask of events to be fetched and cleared
77ea887e4   Tejun Heo   implement in-kern...
1968
1969
1970
1971
1972
1973
1974
   *
   * Disk events are synchronously checked and pending events in @mask
   * are cleared and returned.  This ignores the block count.
   *
   * CONTEXT:
   * Might sleep.
   */
95f6f3a46   Christoph Hellwig   block: add a bdev...
1975
  static unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
77ea887e4   Tejun Heo   implement in-kern...
1976
  {
77ea887e4   Tejun Heo   implement in-kern...
1977
1978
  	struct disk_events *ev = disk->ev;
  	unsigned int pending;
12c2bdb23   Derek Basehore   block: prevent ra...
1979
  	unsigned int clearing = mask;
77ea887e4   Tejun Heo   implement in-kern...
1980

a564e23f0   Christoph Hellwig   md: switch to ->c...
1981
  	if (!ev)
77ea887e4   Tejun Heo   implement in-kern...
1982
  		return 0;
77ea887e4   Tejun Heo   implement in-kern...
1983

12c2bdb23   Derek Basehore   block: prevent ra...
1984
1985
1986
1987
1988
1989
1990
  	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...
1991
  	spin_lock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1992
1993
  	clearing |= ev->clearing;
  	ev->clearing = 0;
77ea887e4   Tejun Heo   implement in-kern...
1994
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
1995
  	disk_check_events(ev, &clearing);
aea24a8bb   Derek Basehore   block: remove dea...
1996
  	/*
12c2bdb23   Derek Basehore   block: prevent ra...
1997
1998
  	 * 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...
1999
  	 */
12c2bdb23   Derek Basehore   block: prevent ra...
2000
  	__disk_unblock_events(disk, ev->clearing ? true : false);
77ea887e4   Tejun Heo   implement in-kern...
2001
2002
2003
  
  	/* then, fetch and clear pending events */
  	spin_lock_irq(&ev->lock);
77ea887e4   Tejun Heo   implement in-kern...
2004
2005
2006
  	pending = ev->pending & mask;
  	ev->pending &= ~mask;
  	spin_unlock_irq(&ev->lock);
12c2bdb23   Derek Basehore   block: prevent ra...
2007
  	WARN_ON_ONCE(clearing & mask);
77ea887e4   Tejun Heo   implement in-kern...
2008
2009
2010
  
  	return pending;
  }
95f6f3a46   Christoph Hellwig   block: add a bdev...
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
  /**
   * bdev_check_media_change - check if a removable media has been changed
   * @bdev: block device to check
   *
   * Check whether a removable media has been changed, and attempt to free all
   * dentries and inodes and invalidates all block device page cache entries in
   * that case.
   *
   * Returns %true if the block device changed, or %false if not.
   */
  bool bdev_check_media_change(struct block_device *bdev)
  {
  	unsigned int events;
  
  	events = disk_clear_events(bdev->bd_disk, DISK_EVENT_MEDIA_CHANGE |
  				   DISK_EVENT_EJECT_REQUEST);
  	if (!(events & DISK_EVENT_MEDIA_CHANGE))
  		return false;
  
  	if (__invalidate_device(bdev, true))
  		pr_warn("VFS: busy inodes on changed media %s
  ",
  			bdev->bd_disk->disk_name);
38430f087   Christoph Hellwig   block: move the N...
2034
  	set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state);
95f6f3a46   Christoph Hellwig   block: add a bdev...
2035
2036
2037
  	return true;
  }
  EXPORT_SYMBOL(bdev_check_media_change);
12c2bdb23   Derek Basehore   block: prevent ra...
2038
2039
2040
2041
  /*
   * 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...
2042
2043
2044
2045
  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...
2046
2047
2048
2049
2050
2051
2052
  
  	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...
2053
2054
  	struct gendisk *disk = ev->disk;
  	char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
12c2bdb23   Derek Basehore   block: prevent ra...
2055
  	unsigned int clearing = *clearing_ptr;
77ea887e4   Tejun Heo   implement in-kern...
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
  	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...
2068
  	*clearing_ptr &= ~clearing;
77ea887e4   Tejun Heo   implement in-kern...
2069
2070
2071
  
  	intv = disk_events_poll_jiffies(disk);
  	if (!ev->block && intv)
695588f94   Viresh Kumar   block: queue work...
2072
2073
  		queue_delayed_work(system_freezable_power_efficient_wq,
  				&ev->dwork, intv);
77ea887e4   Tejun Heo   implement in-kern...
2074
2075
  
  	spin_unlock_irq(&ev->lock);
7c88a168d   Tejun Heo   block: don't prop...
2076
2077
  	/*
  	 * Tell userland about new events.  Only the events listed in
c92e2f04b   Martin Wilck   block: disk_event...
2078
2079
2080
  	 * @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...
2081
  	 */
77ea887e4   Tejun Heo   implement in-kern...
2082
  	for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
c92e2f04b   Martin Wilck   block: disk_event...
2083
2084
  		if ((events & disk->events & (1 << i)) &&
  		    (disk->event_flags & DISK_EVENT_FLAG_UEVENT))
77ea887e4   Tejun Heo   implement in-kern...
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
  			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...
2097
   *			  (always empty, only for backwards compatibility)
77ea887e4   Tejun Heo   implement in-kern...
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
   * 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...
2122
2123
  	if (!(disk->event_flags & DISK_EVENT_FLAG_UEVENT))
  		return 0;
77ea887e4   Tejun Heo   implement in-kern...
2124
2125
2126
2127
2128
2129
  	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...
2130
  	return 0;
77ea887e4   Tejun Heo   implement in-kern...
2131
2132
2133
2134
2135
2136
2137
  }
  
  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...
2138
2139
2140
  	if (!disk->ev)
  		return sprintf(buf, "-1
  ");
77ea887e4   Tejun Heo   implement in-kern...
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
  	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...
2157
2158
  	if (!disk->ev)
  		return -ENODEV;
c3af54afb   Tejun Heo   block: remove non...
2159
  	disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
2160
2161
2162
2163
2164
  	disk->ev->poll_msecs = intv;
  	__disk_unblock_events(disk, true);
  
  	return count;
  }
5657a819a   Joe Perches   block drivers/blo...
2165
2166
2167
  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...
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
  			 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 ...
2182
   * /sys/module/block/parameters/events_dfl_poll_msecs.
77ea887e4   Tejun Heo   implement in-kern...
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
   */
  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...
2197
  		disk_flush_events(ev->disk, 0);
77ea887e4   Tejun Heo   implement in-kern...
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
  
  	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...
2216
   * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
77ea887e4   Tejun Heo   implement in-kern...
2217
   */
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
2218
  static void disk_alloc_events(struct gendisk *disk)
77ea887e4   Tejun Heo   implement in-kern...
2219
2220
  {
  	struct disk_events *ev;
cdf3e3deb   Martin Wilck   block: check_even...
2221
  	if (!disk->fops->check_events || !disk->events)
77ea887e4   Tejun Heo   implement in-kern...
2222
2223
2224
2225
2226
2227
2228
2229
  		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...
2230
2231
2232
  	INIT_LIST_HEAD(&ev->node);
  	ev->disk = disk;
  	spin_lock_init(&ev->lock);
fdd514e16   Tejun Heo   block: make disk_...
2233
  	mutex_init(&ev->block_mutex);
77ea887e4   Tejun Heo   implement in-kern...
2234
2235
2236
  	ev->block = 1;
  	ev->poll_msecs = -1;
  	INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
2237
2238
2239
2240
2241
  	disk->ev = ev;
  }
  
  static void disk_add_events(struct gendisk *disk)
  {
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
2242
2243
2244
2245
2246
  	/* 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...
2247
2248
  	if (!disk->ev)
  		return;
77ea887e4   Tejun Heo   implement in-kern...
2249
  	mutex_lock(&disk_events_mutex);
9f53d2fe8   Stanislaw Gruszka   block: fix __blkd...
2250
  	list_add_tail(&disk->ev->node, &disk_events);
77ea887e4   Tejun Heo   implement in-kern...
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
  	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...
2262
2263
  	if (disk->ev) {
  		disk_block_events(disk);
77ea887e4   Tejun Heo   implement in-kern...
2264

cdf3e3deb   Martin Wilck   block: check_even...
2265
2266
2267
2268
  		mutex_lock(&disk_events_mutex);
  		list_del_init(&disk->ev->node);
  		mutex_unlock(&disk_events_mutex);
  	}
77ea887e4   Tejun Heo   implement in-kern...
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
  
  	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);
  }