Blame view
fs/partitions/check.c
18.1 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* * fs/partitions/check.c * * Code extracted from drivers/block/genhd.c * Copyright (C) 1991-1998 Linus Torvalds * Re-organised Feb 1998 Russell King * * We now have independent partition support from the * block drivers, which allows all the partition code to * be grouped in one location, and it to be mostly self * contained. * * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} */ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> |
5a0e3ad6a
|
19 |
#include <linux/slab.h> |
1da177e4c
|
20 21 |
#include <linux/kmod.h> #include <linux/ctype.h> |
6f2576af5
|
22 |
#include <linux/genhd.h> |
157f9c00e
|
23 |
#include <linux/blktrace_api.h> |
1da177e4c
|
24 25 |
#include "check.h" |
1da177e4c
|
26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include "acorn.h" #include "amiga.h" #include "atari.h" #include "ldm.h" #include "mac.h" #include "msdos.h" #include "osf.h" #include "sgi.h" #include "sun.h" #include "ibm.h" #include "ultrix.h" #include "efi.h" |
0e6e1db4a
|
39 |
#include "karma.h" |
19d0e8ce8
|
40 |
#include "sysv68.h" |
1da177e4c
|
41 42 43 44 45 46 |
#ifdef CONFIG_BLK_DEV_MD extern void md_autodetect_dev(dev_t dev); #endif int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ |
1493bf217
|
47 |
static int (*check_part[])(struct parsed_partitions *) = { |
1da177e4c
|
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
/* * Probe partition formats with tables at disk address 0 * that also have an ADFS boot block at 0xdc0. */ #ifdef CONFIG_ACORN_PARTITION_ICS adfspart_check_ICS, #endif #ifdef CONFIG_ACORN_PARTITION_POWERTEC adfspart_check_POWERTEC, #endif #ifdef CONFIG_ACORN_PARTITION_EESOX adfspart_check_EESOX, #endif /* * Now move on to formats that only have partition info at * disk address 0xdc0. Since these may also have stale * PC/BIOS partition tables, they need to come before * the msdos entry. */ #ifdef CONFIG_ACORN_PARTITION_CUMANA adfspart_check_CUMANA, #endif #ifdef CONFIG_ACORN_PARTITION_ADFS adfspart_check_ADFS, #endif #ifdef CONFIG_EFI_PARTITION efi_partition, /* this must come before msdos */ #endif #ifdef CONFIG_SGI_PARTITION sgi_partition, #endif #ifdef CONFIG_LDM_PARTITION ldm_partition, /* this must come before msdos */ #endif |
1da177e4c
|
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#ifdef CONFIG_MSDOS_PARTITION msdos_partition, #endif #ifdef CONFIG_OSF_PARTITION osf_partition, #endif #ifdef CONFIG_SUN_PARTITION sun_partition, #endif #ifdef CONFIG_AMIGA_PARTITION amiga_partition, #endif #ifdef CONFIG_ATARI_PARTITION atari_partition, #endif #ifdef CONFIG_MAC_PARTITION mac_partition, #endif #ifdef CONFIG_ULTRIX_PARTITION ultrix_partition, #endif #ifdef CONFIG_IBM_PARTITION ibm_partition, #endif |
0e6e1db4a
|
108 109 110 |
#ifdef CONFIG_KARMA_PARTITION karma_partition, #endif |
19d0e8ce8
|
111 112 113 |
#ifdef CONFIG_SYSV68_PARTITION sysv68_partition, #endif |
1da177e4c
|
114 115 116 117 118 119 120 121 122 |
NULL }; /* * disk_name() is used by partition check code and the genhd driver. * It formats the devicename of the indicated disk into * the supplied buffer (of size at least 32), and returns * a pointer to that same buffer (for convenience). */ |
cf771cb5a
|
123 |
char *disk_name(struct gendisk *hd, int partno, char *buf) |
1da177e4c
|
124 |
{ |
cf771cb5a
|
125 |
if (!partno) |
1da177e4c
|
126 127 |
snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) |
cf771cb5a
|
128 |
snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno); |
1da177e4c
|
129 |
else |
cf771cb5a
|
130 |
snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno); |
1da177e4c
|
131 132 133 134 135 136 |
return buf; } const char *bdevname(struct block_device *bdev, char *buf) { |
0762b8bde
|
137 |
return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf); |
1da177e4c
|
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
} EXPORT_SYMBOL(bdevname); /* * There's very little reason to use this, you should really * have a struct block_device just about everywhere and use * bdevname() instead. */ const char *__bdevname(dev_t dev, char *buffer) { scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", MAJOR(dev), MINOR(dev)); return buffer; } EXPORT_SYMBOL(__bdevname); static struct parsed_partitions * check_partition(struct gendisk *hd, struct block_device *bdev) { struct parsed_partitions *state; |
57881dd9d
|
160 |
int i, res, err; |
1da177e4c
|
161 |
|
b403a98e2
|
162 |
state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL); |
1da177e4c
|
163 164 |
if (!state) return NULL; |
9c867fbe0
|
165 166 167 168 169 170 |
state->pp_buf = (char *)__get_free_page(GFP_KERNEL); if (!state->pp_buf) { kfree(state); return NULL; } state->pp_buf[0] = '\0'; |
1da177e4c
|
171 |
|
1493bf217
|
172 |
state->bdev = bdev; |
a29641883
|
173 |
disk_name(hd, 0, state->name); |
9c867fbe0
|
174 |
snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name); |
a29641883
|
175 |
if (isdigit(state->name[strlen(state->name)-1])) |
1da177e4c
|
176 |
sprintf(state->name, "p"); |
a29641883
|
177 |
|
b5d0b9df0
|
178 |
state->limit = disk_max_parts(hd); |
57881dd9d
|
179 |
i = res = err = 0; |
1da177e4c
|
180 181 |
while (!res && check_part[i]) { memset(&state->parts, 0, sizeof(state->parts)); |
1493bf217
|
182 |
res = check_part[i++](state); |
57881dd9d
|
183 184 185 186 187 188 189 |
if (res < 0) { /* We have hit an I/O error which we don't report now. * But record it, and let the others do their job. */ err = res; res = 0; } |
1da177e4c
|
190 |
} |
9c867fbe0
|
191 192 193 194 |
if (res > 0) { printk(KERN_INFO "%s", state->pp_buf); free_page((unsigned long)state->pp_buf); |
1da177e4c
|
195 |
return state; |
9c867fbe0
|
196 |
} |
b403a98e2
|
197 198 |
if (state->access_beyond_eod) err = -ENOSPC; |
9bebff6ca
|
199 |
if (err) |
57881dd9d
|
200 201 |
/* The partition is unrecognized. So report I/O errors if there were any */ res = err; |
1da177e4c
|
202 |
if (!res) |
9c867fbe0
|
203 204 |
strlcat(state->pp_buf, " unknown partition table ", PAGE_SIZE); |
1da177e4c
|
205 |
else if (warn_no_part) |
9c867fbe0
|
206 207 208 209 210 211 |
strlcat(state->pp_buf, " unable to read partition table ", PAGE_SIZE); printk(KERN_INFO "%s", state->pp_buf); free_page((unsigned long)state->pp_buf); |
1da177e4c
|
212 |
kfree(state); |
5127d002f
|
213 |
return ERR_PTR(res); |
1da177e4c
|
214 |
} |
0fc71e3d6
|
215 216 217 218 219 220 221 222 |
static ssize_t part_partition_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%d ", p->partno); } |
edfaa7c36
|
223 224 |
static ssize_t part_start_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c
|
225 |
{ |
edfaa7c36
|
226 |
struct hd_struct *p = dev_to_part(dev); |
a7fd67062
|
227 |
|
edfaa7c36
|
228 229 |
return sprintf(buf, "%llu ",(unsigned long long)p->start_sect); |
1da177e4c
|
230 |
} |
e56105214
|
231 232 |
ssize_t part_size_show(struct device *dev, struct device_attribute *attr, char *buf) |
a7fd67062
|
233 |
{ |
edfaa7c36
|
234 235 236 |
struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%llu ",(unsigned long long)p->nr_sects); |
a7fd67062
|
237 |
} |
edfaa7c36
|
238 |
|
c72758f33
|
239 240 241 242 243 244 245 |
ssize_t part_alignment_offset_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)p->alignment_offset); } |
86b372814
|
246 247 248 249 250 251 252 |
ssize_t part_discard_alignment_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%u ", p->discard_alignment); } |
074a7aca7
|
253 254 |
ssize_t part_stat_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c
|
255 |
{ |
edfaa7c36
|
256 |
struct hd_struct *p = dev_to_part(dev); |
c99590591
|
257 |
int cpu; |
edfaa7c36
|
258 |
|
074a7aca7
|
259 |
cpu = part_stat_lock(); |
c99590591
|
260 |
part_round_stats(cpu, p); |
074a7aca7
|
261 |
part_stat_unlock(); |
34e8beac9
|
262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
return sprintf(buf, "%8lu %8lu %8llu %8u " "%8lu %8lu %8llu %8u " "%8u %8u %8u" " ", part_stat_read(p, ios[READ]), part_stat_read(p, merges[READ]), (unsigned long long)part_stat_read(p, sectors[READ]), jiffies_to_msecs(part_stat_read(p, ticks[READ])), part_stat_read(p, ios[WRITE]), part_stat_read(p, merges[WRITE]), (unsigned long long)part_stat_read(p, sectors[WRITE]), jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), |
316d315bf
|
276 |
part_in_flight(p), |
34e8beac9
|
277 278 |
jiffies_to_msecs(part_stat_read(p, io_ticks)), jiffies_to_msecs(part_stat_read(p, time_in_queue))); |
1da177e4c
|
279 |
} |
1da177e4c
|
280 |
|
316d315bf
|
281 282 283 284 285 286 287 288 |
ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%8u %8u ", p->in_flight[0], p->in_flight[1]); } |
c17bb4951
|
289 |
#ifdef CONFIG_FAIL_MAKE_REQUEST |
eddb2e26b
|
290 291 |
ssize_t part_fail_show(struct device *dev, struct device_attribute *attr, char *buf) |
edfaa7c36
|
292 293 |
{ struct hd_struct *p = dev_to_part(dev); |
c17bb4951
|
294 |
|
edfaa7c36
|
295 296 297 |
return sprintf(buf, "%d ", p->make_it_fail); } |
eddb2e26b
|
298 299 300 |
ssize_t part_fail_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
c17bb4951
|
301 |
{ |
edfaa7c36
|
302 |
struct hd_struct *p = dev_to_part(dev); |
c17bb4951
|
303 304 305 306 307 308 309 |
int i; if (count > 0 && sscanf(buf, "%d", &i) > 0) p->make_it_fail = (i == 0) ? 0 : 1; return count; } |
edfaa7c36
|
310 |
#endif |
c17bb4951
|
311 |
|
0fc71e3d6
|
312 |
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); |
edfaa7c36
|
313 314 |
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
c72758f33
|
315 |
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); |
86b372814
|
316 317 |
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, NULL); |
edfaa7c36
|
318 |
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
316d315bf
|
319 |
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); |
edfaa7c36
|
320 321 322 |
#ifdef CONFIG_FAIL_MAKE_REQUEST static struct device_attribute dev_attr_fail = __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); |
c17bb4951
|
323 |
#endif |
edfaa7c36
|
324 |
static struct attribute *part_attrs[] = { |
0fc71e3d6
|
325 |
&dev_attr_partition.attr, |
edfaa7c36
|
326 327 |
&dev_attr_start.attr, &dev_attr_size.attr, |
c72758f33
|
328 |
&dev_attr_alignment_offset.attr, |
86b372814
|
329 |
&dev_attr_discard_alignment.attr, |
edfaa7c36
|
330 |
&dev_attr_stat.attr, |
316d315bf
|
331 |
&dev_attr_inflight.attr, |
c17bb4951
|
332 |
#ifdef CONFIG_FAIL_MAKE_REQUEST |
edfaa7c36
|
333 |
&dev_attr_fail.attr, |
c17bb4951
|
334 |
#endif |
edfaa7c36
|
335 |
NULL |
1da177e4c
|
336 |
}; |
edfaa7c36
|
337 338 339 |
static struct attribute_group part_attr_group = { .attrs = part_attrs, }; |
1da177e4c
|
340 |
|
a4dbd6740
|
341 |
static const struct attribute_group *part_attr_groups[] = { |
edfaa7c36
|
342 |
&part_attr_group, |
c71a89615
|
343 344 345 |
#ifdef CONFIG_BLK_DEV_IO_TRACE &blk_trace_attr_group, #endif |
edfaa7c36
|
346 347 348 349 |
NULL }; static void part_release(struct device *dev) |
1da177e4c
|
350 |
{ |
edfaa7c36
|
351 |
struct hd_struct *p = dev_to_part(dev); |
6f2576af5
|
352 |
free_part_stats(p); |
1da177e4c
|
353 354 |
kfree(p); } |
edfaa7c36
|
355 356 357 |
struct device_type part_type = { .name = "partition", .groups = part_attr_groups, |
1da177e4c
|
358 |
.release = part_release, |
1da177e4c
|
359 |
}; |
e71bf0d0e
|
360 361 362 363 364 365 366 |
static void delete_partition_rcu_cb(struct rcu_head *head) { struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); part->start_sect = 0; part->nr_sects = 0; part_stat_set_all(part, 0); |
ed9e19823
|
367 |
put_device(part_to_dev(part)); |
e71bf0d0e
|
368 |
} |
cf771cb5a
|
369 |
void delete_partition(struct gendisk *disk, int partno) |
1da177e4c
|
370 |
{ |
540eed563
|
371 |
struct disk_part_tbl *ptbl = disk->part_tbl; |
e71bf0d0e
|
372 |
struct hd_struct *part; |
edfaa7c36
|
373 |
|
540eed563
|
374 375 376 377 |
if (partno >= ptbl->len) return; part = ptbl->part[partno]; |
e71bf0d0e
|
378 |
if (!part) |
1da177e4c
|
379 |
return; |
e71bf0d0e
|
380 |
|
bcce3de1b
|
381 |
blk_free_devt(part_devt(part)); |
540eed563
|
382 |
rcu_assign_pointer(ptbl->part[partno], NULL); |
54b0d1276
|
383 |
rcu_assign_pointer(ptbl->last_lookup, NULL); |
e71bf0d0e
|
384 |
kobject_put(part->holder_dir); |
ed9e19823
|
385 |
device_del(part_to_dev(part)); |
e71bf0d0e
|
386 387 |
call_rcu(&part->rcu_head, delete_partition_rcu_cb); |
1da177e4c
|
388 |
} |
f4a00a2c0
|
389 390 391 392 393 394 395 |
static ssize_t whole_disk_show(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, whole_disk_show, NULL); |
ba32929a9
|
396 397 |
struct hd_struct *add_partition(struct gendisk *disk, int partno, sector_t start, sector_t len, int flags) |
1da177e4c
|
398 399 |
{ struct hd_struct *p; |
bcce3de1b
|
400 |
dev_t devt = MKDEV(0, 0); |
ed9e19823
|
401 402 |
struct device *ddev = disk_to_dev(disk); struct device *pdev; |
540eed563
|
403 |
struct disk_part_tbl *ptbl; |
ed9e19823
|
404 |
const char *dname; |
edfaa7c36
|
405 |
int err; |
1da177e4c
|
406 |
|
540eed563
|
407 408 |
err = disk_expand_part_tbl(disk, partno); if (err) |
ba32929a9
|
409 |
return ERR_PTR(err); |
540eed563
|
410 411 412 |
ptbl = disk->part_tbl; if (ptbl->part[partno]) |
ba32929a9
|
413 |
return ERR_PTR(-EBUSY); |
88e341261
|
414 |
|
dd00cc486
|
415 |
p = kzalloc(sizeof(*p), GFP_KERNEL); |
1da177e4c
|
416 |
if (!p) |
ba32929a9
|
417 |
return ERR_PTR(-EBUSY); |
edfaa7c36
|
418 |
|
6f2576af5
|
419 |
if (!init_part_stats(p)) { |
d805dda41
|
420 |
err = -ENOMEM; |
88e341261
|
421 |
goto out_free; |
6f2576af5
|
422 |
} |
ed9e19823
|
423 |
pdev = part_to_dev(p); |
1da177e4c
|
424 |
p->start_sect = start; |
e03a72e13
|
425 426 427 428 |
p->alignment_offset = queue_limit_alignment_offset(&disk->queue->limits, start); p->discard_alignment = queue_limit_discard_alignment(&disk->queue->limits, start); |
1da177e4c
|
429 |
p->nr_sects = len; |
cf771cb5a
|
430 |
p->partno = partno; |
b7db9956e
|
431 |
p->policy = get_disk_ro(disk); |
1da177e4c
|
432 |
|
ed9e19823
|
433 434 |
dname = dev_name(ddev); if (isdigit(dname[strlen(dname) - 1])) |
3ada8b7e9
|
435 |
dev_set_name(pdev, "%sp%d", dname, partno); |
1da177e4c
|
436 |
else |
3ada8b7e9
|
437 |
dev_set_name(pdev, "%s%d", dname, partno); |
edfaa7c36
|
438 |
|
ed9e19823
|
439 440 441 442 |
device_initialize(pdev); pdev->class = &block_class; pdev->type = &part_type; pdev->parent = ddev; |
edfaa7c36
|
443 |
|
bcce3de1b
|
444 445 |
err = blk_alloc_devt(p, &devt); if (err) |
eb60fa106
|
446 |
goto out_free_stats; |
ed9e19823
|
447 |
pdev->devt = devt; |
bcce3de1b
|
448 |
|
edfaa7c36
|
449 |
/* delay uevent until 'holders' subdir is created */ |
f67f129e5
|
450 |
dev_set_uevent_suppress(pdev, 1); |
ed9e19823
|
451 |
err = device_add(pdev); |
d805dda41
|
452 |
if (err) |
88e341261
|
453 454 455 |
goto out_put; err = -ENOMEM; |
ed9e19823
|
456 |
p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); |
88e341261
|
457 458 |
if (!p->holder_dir) goto out_del; |
f67f129e5
|
459 |
dev_set_uevent_suppress(pdev, 0); |
d805dda41
|
460 |
if (flags & ADDPART_FLAG_WHOLEDISK) { |
ed9e19823
|
461 |
err = device_create_file(pdev, &dev_attr_whole_disk); |
d805dda41
|
462 |
if (err) |
88e341261
|
463 |
goto out_del; |
d805dda41
|
464 |
} |
1da177e4c
|
465 |
|
88e341261
|
466 |
/* everything is up and running, commence */ |
540eed563
|
467 |
rcu_assign_pointer(ptbl->part[partno], p); |
88e341261
|
468 |
|
edfaa7c36
|
469 |
/* suppress uevent if the disk supresses it */ |
f8c73c790
|
470 |
if (!dev_get_uevent_suppress(ddev)) |
ed9e19823
|
471 |
kobject_uevent(&pdev->kobj, KOBJ_ADD); |
d805dda41
|
472 |
|
ba32929a9
|
473 |
return p; |
d805dda41
|
474 |
|
eb60fa106
|
475 476 |
out_free_stats: free_part_stats(p); |
88e341261
|
477 478 |
out_free: kfree(p); |
ba32929a9
|
479 |
return ERR_PTR(err); |
88e341261
|
480 481 |
out_del: kobject_put(p->holder_dir); |
ed9e19823
|
482 |
device_del(pdev); |
88e341261
|
483 |
out_put: |
ed9e19823
|
484 |
put_device(pdev); |
bcce3de1b
|
485 |
blk_free_devt(devt); |
ba32929a9
|
486 |
return ERR_PTR(err); |
1da177e4c
|
487 488 489 490 491 |
} /* Not exported, helper to add_disk(). */ void register_disk(struct gendisk *disk) { |
ed9e19823
|
492 |
struct device *ddev = disk_to_dev(disk); |
1da177e4c
|
493 |
struct block_device *bdev; |
e71bf0d0e
|
494 495 |
struct disk_part_iter piter; struct hd_struct *part; |
1da177e4c
|
496 |
int err; |
ed9e19823
|
497 |
ddev->parent = disk->driverfs_dev; |
edfaa7c36
|
498 |
|
3ada8b7e9
|
499 |
dev_set_name(ddev, disk->disk_name); |
edfaa7c36
|
500 501 |
/* delay uevents, until we scanned partition table */ |
f67f129e5
|
502 |
dev_set_uevent_suppress(ddev, 1); |
edfaa7c36
|
503 |
|
ed9e19823
|
504 |
if (device_add(ddev)) |
1da177e4c
|
505 |
return; |
edfaa7c36
|
506 |
#ifndef CONFIG_SYSFS_DEPRECATED |
ed9e19823
|
507 508 |
err = sysfs_create_link(block_depr, &ddev->kobj, kobject_name(&ddev->kobj)); |
eee44cca6
|
509 |
if (err) { |
ed9e19823
|
510 |
device_del(ddev); |
eee44cca6
|
511 512 |
return; } |
edfaa7c36
|
513 |
#endif |
4c46501d1
|
514 515 |
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); |
1da177e4c
|
516 517 |
/* No minors to use for partitions */ |
b5d0b9df0
|
518 |
if (!disk_partitionable(disk)) |
d4d7e5dff
|
519 |
goto exit; |
1da177e4c
|
520 521 522 |
/* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) |
d4d7e5dff
|
523 |
goto exit; |
1da177e4c
|
524 525 526 |
bdev = bdget_disk(disk, 0); if (!bdev) |
d4d7e5dff
|
527 |
goto exit; |
1da177e4c
|
528 529 |
bdev->bd_invalidated = 1; |
572c48921
|
530 |
err = blkdev_get(bdev, FMODE_READ); |
d4d7e5dff
|
531 532 |
if (err < 0) goto exit; |
9a1c35427
|
533 |
blkdev_put(bdev, FMODE_READ); |
d4d7e5dff
|
534 535 |
exit: |
edfaa7c36
|
536 |
/* announce disk after possible partitions are created */ |
f67f129e5
|
537 |
dev_set_uevent_suppress(ddev, 0); |
ed9e19823
|
538 |
kobject_uevent(&ddev->kobj, KOBJ_ADD); |
d4d7e5dff
|
539 540 |
/* announce possible partitions */ |
e71bf0d0e
|
541 542 |
disk_part_iter_init(&piter, disk, 0); while ((part = disk_part_iter_next(&piter))) |
ed9e19823
|
543 |
kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); |
e71bf0d0e
|
544 |
disk_part_iter_exit(&piter); |
1da177e4c
|
545 |
} |
b403a98e2
|
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
static bool disk_unlock_native_capacity(struct gendisk *disk) { const struct block_device_operations *bdops = disk->fops; if (bdops->unlock_native_capacity && !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) { printk(KERN_CONT "enabling native capacity "); bdops->unlock_native_capacity(disk); disk->flags |= GENHD_FL_NATIVE_CAPACITY; return true; } else { printk(KERN_CONT "truncated "); return false; } } |
1da177e4c
|
563 564 |
int rescan_partitions(struct gendisk *disk, struct block_device *bdev) { |
b403a98e2
|
565 |
struct parsed_partitions *state = NULL; |
e71bf0d0e
|
566 567 |
struct disk_part_iter piter; struct hd_struct *part; |
540eed563
|
568 |
int p, highest, res; |
56bca0173
|
569 |
rescan: |
b403a98e2
|
570 571 572 573 |
if (state && !IS_ERR(state)) { kfree(state); state = NULL; } |
1da177e4c
|
574 575 576 577 578 |
if (bdev->bd_part_count) return -EBUSY; res = invalidate_partition(disk, 0); if (res) return res; |
e71bf0d0e
|
579 580 581 582 583 |
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); while ((part = disk_part_iter_next(&piter))) delete_partition(disk, part->partno); disk_part_iter_exit(&piter); |
1da177e4c
|
584 585 |
if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); |
9bc3ffbfb
|
586 587 |
check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0; |
1da177e4c
|
588 589 |
if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) return 0; |
b403a98e2
|
590 591 592 593 594 595 596 597 598 599 600 601 |
if (IS_ERR(state)) { /* * I/O error reading the partition table. If any * partition code tried to read beyond EOD, retry * after unlocking native capacity. */ if (PTR_ERR(state) == -ENOSPC) { printk(KERN_WARNING "%s: partition table beyond EOD, ", disk->disk_name); if (disk_unlock_native_capacity(disk)) goto rescan; } |
b74a2f091
|
602 |
return -EIO; |
b403a98e2
|
603 604 605 606 607 608 609 610 611 612 613 614 615 |
} /* * If any partition code tried to read beyond EOD, try * unlocking native capacity even if partition table is * sucessfully read as we could be missing some partitions. */ if (state->access_beyond_eod) { printk(KERN_WARNING "%s: partition table partially beyond EOD, ", disk->disk_name); if (disk_unlock_native_capacity(disk)) goto rescan; } |
6bcf19d02
|
616 617 |
/* tell userspace that the media / partition table may have changed */ |
ed9e19823
|
618 |
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); |
6bcf19d02
|
619 |
|
540eed563
|
620 621 622 623 624 625 626 627 628 629 630 |
/* Detect the highest partition number and preallocate * disk->part_tbl. This is an optimization and not strictly * necessary. */ for (p = 1, highest = 0; p < state->limit; p++) if (state->parts[p].size) highest = p; disk_expand_part_tbl(disk, highest); /* add partitions */ |
1da177e4c
|
631 |
for (p = 1; p < state->limit; p++) { |
db429e9ec
|
632 |
sector_t size, from; |
56bca0173
|
633 |
|
db429e9ec
|
634 |
size = state->parts[p].size; |
1da177e4c
|
635 636 |
if (!size) continue; |
db429e9ec
|
637 638 |
from = state->parts[p].from; |
ac0d86f58
|
639 640 |
if (from >= get_capacity(disk)) { printk(KERN_WARNING |
b403a98e2
|
641 |
"%s: p%d start %llu is beyond EOD, ", |
ac0d86f58
|
642 |
disk->disk_name, p, (unsigned long long) from); |
b403a98e2
|
643 644 |
if (disk_unlock_native_capacity(disk)) goto rescan; |
ac0d86f58
|
645 646 |
continue; } |
db429e9ec
|
647 |
|
98bd34eaf
|
648 |
if (from + size > get_capacity(disk)) { |
8d99f83b9
|
649 |
printk(KERN_WARNING |
b403a98e2
|
650 |
"%s: p%d size %llu extends beyond EOD, ", |
ac0d86f58
|
651 |
disk->disk_name, p, (unsigned long long) size); |
db429e9ec
|
652 |
|
b403a98e2
|
653 |
if (disk_unlock_native_capacity(disk)) { |
56bca0173
|
654 |
/* free state and restart */ |
56bca0173
|
655 |
goto rescan; |
db429e9ec
|
656 657 658 659 660 661 662 |
} else { /* * we can not ignore partitions of broken tables * created by for example camera firmware, but * we limit them to the end of the disk to avoid * creating invalid block devices */ |
db429e9ec
|
663 664 |
size = get_capacity(disk) - from; } |
04ebd4aee
|
665 |
} |
ba32929a9
|
666 667 668 669 670 671 |
part = add_partition(disk, p, from, size, state->parts[p].flags); if (IS_ERR(part)) { printk(KERN_ERR " %s: p%d could not be added: %ld ", disk->disk_name, p, -PTR_ERR(part)); |
04ebd4aee
|
672 |
continue; |
98bd34eaf
|
673 |
} |
1da177e4c
|
674 |
#ifdef CONFIG_BLK_DEV_MD |
d18d7682c
|
675 |
if (state->parts[p].flags & ADDPART_FLAG_RAID) |
55e8e30c3
|
676 |
md_autodetect_dev(part_to_dev(part)->devt); |
1da177e4c
|
677 678 679 680 681 682 683 684 685 686 |
#endif } kfree(state); return 0; } unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) { struct address_space *mapping = bdev->bd_inode->i_mapping; struct page *page; |
090d2b185
|
687 688 |
page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), NULL); |
1da177e4c
|
689 |
if (!IS_ERR(page)) { |
1da177e4c
|
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
if (PageError(page)) goto fail; p->v = page; return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9); fail: page_cache_release(page); } p->v = NULL; return NULL; } EXPORT_SYMBOL(read_dev_sector); void del_gendisk(struct gendisk *disk) { |
e71bf0d0e
|
705 706 |
struct disk_part_iter piter; struct hd_struct *part; |
1da177e4c
|
707 708 |
/* invalidate stuff */ |
e71bf0d0e
|
709 710 711 712 713 |
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); while ((part = disk_part_iter_next(&piter))) { invalidate_partition(disk, part->partno); delete_partition(disk, part->partno); |
1da177e4c
|
714 |
} |
e71bf0d0e
|
715 |
disk_part_iter_exit(&piter); |
1da177e4c
|
716 |
invalidate_partition(disk, 0); |
3e1a7ff8a
|
717 |
blk_free_devt(disk_to_dev(disk)->devt); |
80795aefb
|
718 |
set_capacity(disk, 0); |
1da177e4c
|
719 720 |
disk->flags &= ~GENHD_FL_UP; unlink_gendisk(disk); |
074a7aca7
|
721 722 |
part_stat_set_all(&disk->part0, 0); disk->part0.stamp = 0; |
1da177e4c
|
723 |
|
4c46501d1
|
724 |
kobject_put(disk->part0.holder_dir); |
197b12d67
|
725 |
kobject_put(disk->slave_dir); |
edfaa7c36
|
726 727 |
disk->driverfs_dev = NULL; #ifndef CONFIG_SYSFS_DEPRECATED |
ed9e19823
|
728 |
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); |
edfaa7c36
|
729 |
#endif |
ed9e19823
|
730 |
device_del(disk_to_dev(disk)); |
1da177e4c
|
731 |
} |