Blame view
fs/partitions/check.c
16.6 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 |
|
dd7740933
|
239 240 |
static ssize_t part_ro_show(struct device *dev, struct device_attribute *attr, char *buf) |
34db1d595
|
241 242 243 244 245 |
{ struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%d ", p->policy ? 1 : 0); } |
dd7740933
|
246 247 |
static ssize_t part_alignment_offset_show(struct device *dev, struct device_attribute *attr, char *buf) |
c72758f33
|
248 249 250 251 252 |
{ struct hd_struct *p = dev_to_part(dev); return sprintf(buf, "%llu ", (unsigned long long)p->alignment_offset); } |
dd7740933
|
253 254 |
static ssize_t part_discard_alignment_show(struct device *dev, struct device_attribute *attr, char *buf) |
86b372814
|
255 256 |
{ struct hd_struct *p = dev_to_part(dev); |
a1706ac4c
|
257 258 |
return sprintf(buf, "%u ", p->discard_alignment); |
86b372814
|
259 |
} |
074a7aca7
|
260 261 |
ssize_t part_stat_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c
|
262 |
{ |
edfaa7c36
|
263 |
struct hd_struct *p = dev_to_part(dev); |
c99590591
|
264 |
int cpu; |
edfaa7c36
|
265 |
|
074a7aca7
|
266 |
cpu = part_stat_lock(); |
c99590591
|
267 |
part_round_stats(cpu, p); |
074a7aca7
|
268 |
part_stat_unlock(); |
34e8beac9
|
269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
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
|
283 |
part_in_flight(p), |
34e8beac9
|
284 285 |
jiffies_to_msecs(part_stat_read(p, io_ticks)), jiffies_to_msecs(part_stat_read(p, time_in_queue))); |
1da177e4c
|
286 |
} |
1da177e4c
|
287 |
|
316d315bf
|
288 289 290 291 |
ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hd_struct *p = dev_to_part(dev); |
1e9bb8808
|
292 293 294 |
return sprintf(buf, "%8u %8u ", atomic_read(&p->in_flight[0]), atomic_read(&p->in_flight[1])); |
316d315bf
|
295 |
} |
c17bb4951
|
296 |
#ifdef CONFIG_FAIL_MAKE_REQUEST |
eddb2e26b
|
297 298 |
ssize_t part_fail_show(struct device *dev, struct device_attribute *attr, char *buf) |
edfaa7c36
|
299 300 |
{ struct hd_struct *p = dev_to_part(dev); |
c17bb4951
|
301 |
|
edfaa7c36
|
302 303 304 |
return sprintf(buf, "%d ", p->make_it_fail); } |
eddb2e26b
|
305 306 307 |
ssize_t part_fail_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
c17bb4951
|
308 |
{ |
edfaa7c36
|
309 |
struct hd_struct *p = dev_to_part(dev); |
c17bb4951
|
310 311 312 313 314 315 316 |
int i; if (count > 0 && sscanf(buf, "%d", &i) > 0) p->make_it_fail = (i == 0) ? 0 : 1; return count; } |
edfaa7c36
|
317 |
#endif |
c17bb4951
|
318 |
|
0fc71e3d6
|
319 |
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); |
edfaa7c36
|
320 321 |
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
34db1d595
|
322 |
static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL); |
c72758f33
|
323 |
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); |
86b372814
|
324 325 |
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, NULL); |
edfaa7c36
|
326 |
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
316d315bf
|
327 |
static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); |
edfaa7c36
|
328 329 330 |
#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
|
331 |
#endif |
edfaa7c36
|
332 |
static struct attribute *part_attrs[] = { |
0fc71e3d6
|
333 |
&dev_attr_partition.attr, |
edfaa7c36
|
334 335 |
&dev_attr_start.attr, &dev_attr_size.attr, |
34db1d595
|
336 |
&dev_attr_ro.attr, |
c72758f33
|
337 |
&dev_attr_alignment_offset.attr, |
86b372814
|
338 |
&dev_attr_discard_alignment.attr, |
edfaa7c36
|
339 |
&dev_attr_stat.attr, |
316d315bf
|
340 |
&dev_attr_inflight.attr, |
c17bb4951
|
341 |
#ifdef CONFIG_FAIL_MAKE_REQUEST |
edfaa7c36
|
342 |
&dev_attr_fail.attr, |
c17bb4951
|
343 |
#endif |
edfaa7c36
|
344 |
NULL |
1da177e4c
|
345 |
}; |
edfaa7c36
|
346 347 348 |
static struct attribute_group part_attr_group = { .attrs = part_attrs, }; |
1da177e4c
|
349 |
|
a4dbd6740
|
350 |
static const struct attribute_group *part_attr_groups[] = { |
edfaa7c36
|
351 |
&part_attr_group, |
c71a89615
|
352 353 354 |
#ifdef CONFIG_BLK_DEV_IO_TRACE &blk_trace_attr_group, #endif |
edfaa7c36
|
355 356 357 358 |
NULL }; static void part_release(struct device *dev) |
1da177e4c
|
359 |
{ |
edfaa7c36
|
360 |
struct hd_struct *p = dev_to_part(dev); |
6f2576af5
|
361 |
free_part_stats(p); |
6d1d8050b
|
362 |
free_part_info(p); |
1da177e4c
|
363 364 |
kfree(p); } |
edfaa7c36
|
365 366 367 |
struct device_type part_type = { .name = "partition", .groups = part_attr_groups, |
1da177e4c
|
368 |
.release = part_release, |
1da177e4c
|
369 |
}; |
e71bf0d0e
|
370 371 372 373 374 375 376 |
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
|
377 |
put_device(part_to_dev(part)); |
e71bf0d0e
|
378 |
} |
6c23a9681
|
379 |
void __delete_partition(struct hd_struct *part) |
09e099d4b
|
380 |
{ |
09e099d4b
|
381 382 |
call_rcu(&part->rcu_head, delete_partition_rcu_cb); } |
cf771cb5a
|
383 |
void delete_partition(struct gendisk *disk, int partno) |
1da177e4c
|
384 |
{ |
540eed563
|
385 |
struct disk_part_tbl *ptbl = disk->part_tbl; |
e71bf0d0e
|
386 |
struct hd_struct *part; |
edfaa7c36
|
387 |
|
540eed563
|
388 389 390 391 |
if (partno >= ptbl->len) return; part = ptbl->part[partno]; |
e71bf0d0e
|
392 |
if (!part) |
1da177e4c
|
393 |
return; |
e71bf0d0e
|
394 |
|
bcce3de1b
|
395 |
blk_free_devt(part_devt(part)); |
540eed563
|
396 |
rcu_assign_pointer(ptbl->part[partno], NULL); |
54b0d1276
|
397 |
rcu_assign_pointer(ptbl->last_lookup, NULL); |
e71bf0d0e
|
398 |
kobject_put(part->holder_dir); |
ed9e19823
|
399 |
device_del(part_to_dev(part)); |
e71bf0d0e
|
400 |
|
6c23a9681
|
401 |
hd_struct_put(part); |
1da177e4c
|
402 |
} |
f4a00a2c0
|
403 404 405 406 407 408 409 |
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
|
410 |
struct hd_struct *add_partition(struct gendisk *disk, int partno, |
6d1d8050b
|
411 412 |
sector_t start, sector_t len, int flags, struct partition_meta_info *info) |
1da177e4c
|
413 414 |
{ struct hd_struct *p; |
bcce3de1b
|
415 |
dev_t devt = MKDEV(0, 0); |
ed9e19823
|
416 417 |
struct device *ddev = disk_to_dev(disk); struct device *pdev; |
540eed563
|
418 |
struct disk_part_tbl *ptbl; |
ed9e19823
|
419 |
const char *dname; |
edfaa7c36
|
420 |
int err; |
1da177e4c
|
421 |
|
540eed563
|
422 423 |
err = disk_expand_part_tbl(disk, partno); if (err) |
ba32929a9
|
424 |
return ERR_PTR(err); |
540eed563
|
425 426 427 |
ptbl = disk->part_tbl; if (ptbl->part[partno]) |
ba32929a9
|
428 |
return ERR_PTR(-EBUSY); |
88e341261
|
429 |
|
dd00cc486
|
430 |
p = kzalloc(sizeof(*p), GFP_KERNEL); |
1da177e4c
|
431 |
if (!p) |
ba32929a9
|
432 |
return ERR_PTR(-EBUSY); |
edfaa7c36
|
433 |
|
6f2576af5
|
434 |
if (!init_part_stats(p)) { |
d805dda41
|
435 |
err = -ENOMEM; |
88e341261
|
436 |
goto out_free; |
6f2576af5
|
437 |
} |
ed9e19823
|
438 |
pdev = part_to_dev(p); |
1da177e4c
|
439 |
p->start_sect = start; |
e03a72e13
|
440 441 |
p->alignment_offset = queue_limit_alignment_offset(&disk->queue->limits, start); |
a1706ac4c
|
442 443 |
p->discard_alignment = queue_limit_discard_alignment(&disk->queue->limits, start); |
1da177e4c
|
444 |
p->nr_sects = len; |
cf771cb5a
|
445 |
p->partno = partno; |
b7db9956e
|
446 |
p->policy = get_disk_ro(disk); |
1da177e4c
|
447 |
|
6d1d8050b
|
448 449 450 451 452 453 454 |
if (info) { struct partition_meta_info *pinfo = alloc_part_info(disk); if (!pinfo) goto out_free_stats; memcpy(pinfo, info, sizeof(*info)); p->info = pinfo; } |
ed9e19823
|
455 456 |
dname = dev_name(ddev); if (isdigit(dname[strlen(dname) - 1])) |
3ada8b7e9
|
457 |
dev_set_name(pdev, "%sp%d", dname, partno); |
1da177e4c
|
458 |
else |
3ada8b7e9
|
459 |
dev_set_name(pdev, "%s%d", dname, partno); |
edfaa7c36
|
460 |
|
ed9e19823
|
461 462 463 464 |
device_initialize(pdev); pdev->class = &block_class; pdev->type = &part_type; pdev->parent = ddev; |
edfaa7c36
|
465 |
|
bcce3de1b
|
466 467 |
err = blk_alloc_devt(p, &devt); if (err) |
6d1d8050b
|
468 |
goto out_free_info; |
ed9e19823
|
469 |
pdev->devt = devt; |
bcce3de1b
|
470 |
|
edfaa7c36
|
471 |
/* delay uevent until 'holders' subdir is created */ |
f67f129e5
|
472 |
dev_set_uevent_suppress(pdev, 1); |
ed9e19823
|
473 |
err = device_add(pdev); |
d805dda41
|
474 |
if (err) |
88e341261
|
475 476 477 |
goto out_put; err = -ENOMEM; |
ed9e19823
|
478 |
p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); |
88e341261
|
479 480 |
if (!p->holder_dir) goto out_del; |
f67f129e5
|
481 |
dev_set_uevent_suppress(pdev, 0); |
d805dda41
|
482 |
if (flags & ADDPART_FLAG_WHOLEDISK) { |
ed9e19823
|
483 |
err = device_create_file(pdev, &dev_attr_whole_disk); |
d805dda41
|
484 |
if (err) |
88e341261
|
485 |
goto out_del; |
d805dda41
|
486 |
} |
1da177e4c
|
487 |
|
88e341261
|
488 |
/* everything is up and running, commence */ |
540eed563
|
489 |
rcu_assign_pointer(ptbl->part[partno], p); |
88e341261
|
490 |
|
25985edce
|
491 |
/* suppress uevent if the disk suppresses it */ |
f8c73c790
|
492 |
if (!dev_get_uevent_suppress(ddev)) |
ed9e19823
|
493 |
kobject_uevent(&pdev->kobj, KOBJ_ADD); |
d805dda41
|
494 |
|
6c23a9681
|
495 |
hd_ref_init(p); |
ba32929a9
|
496 |
return p; |
d805dda41
|
497 |
|
6d1d8050b
|
498 499 |
out_free_info: free_part_info(p); |
eb60fa106
|
500 501 |
out_free_stats: free_part_stats(p); |
88e341261
|
502 503 |
out_free: kfree(p); |
ba32929a9
|
504 |
return ERR_PTR(err); |
88e341261
|
505 506 |
out_del: kobject_put(p->holder_dir); |
ed9e19823
|
507 |
device_del(pdev); |
88e341261
|
508 |
out_put: |
ed9e19823
|
509 |
put_device(pdev); |
bcce3de1b
|
510 |
blk_free_devt(devt); |
ba32929a9
|
511 |
return ERR_PTR(err); |
1da177e4c
|
512 |
} |
b403a98e2
|
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
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
|
530 531 |
int rescan_partitions(struct gendisk *disk, struct block_device *bdev) { |
b403a98e2
|
532 |
struct parsed_partitions *state = NULL; |
e71bf0d0e
|
533 534 |
struct disk_part_iter piter; struct hd_struct *part; |
540eed563
|
535 |
int p, highest, res; |
56bca0173
|
536 |
rescan: |
b403a98e2
|
537 538 539 540 |
if (state && !IS_ERR(state)) { kfree(state); state = NULL; } |
1da177e4c
|
541 542 543 544 545 |
if (bdev->bd_part_count) return -EBUSY; res = invalidate_partition(disk, 0); if (res) return res; |
e71bf0d0e
|
546 547 548 549 550 |
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
|
551 552 |
if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); |
9bc3ffbfb
|
553 554 |
check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0; |
1da177e4c
|
555 556 |
if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) return 0; |
b403a98e2
|
557 558 559 560 561 562 563 564 565 566 567 568 |
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
|
569 |
return -EIO; |
b403a98e2
|
570 571 572 573 |
} /* * If any partition code tried to read beyond EOD, try * unlocking native capacity even if partition table is |
25985edce
|
574 |
* successfully read as we could be missing some partitions. |
b403a98e2
|
575 576 577 578 579 580 581 582 |
*/ 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
|
583 584 |
/* tell userspace that the media / partition table may have changed */ |
ed9e19823
|
585 |
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); |
6bcf19d02
|
586 |
|
540eed563
|
587 588 589 590 591 592 593 594 595 596 597 |
/* 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
|
598 |
for (p = 1; p < state->limit; p++) { |
db429e9ec
|
599 |
sector_t size, from; |
6d1d8050b
|
600 |
struct partition_meta_info *info = NULL; |
56bca0173
|
601 |
|
db429e9ec
|
602 |
size = state->parts[p].size; |
1da177e4c
|
603 604 |
if (!size) continue; |
db429e9ec
|
605 606 |
from = state->parts[p].from; |
ac0d86f58
|
607 608 |
if (from >= get_capacity(disk)) { printk(KERN_WARNING |
b403a98e2
|
609 |
"%s: p%d start %llu is beyond EOD, ", |
ac0d86f58
|
610 |
disk->disk_name, p, (unsigned long long) from); |
b403a98e2
|
611 612 |
if (disk_unlock_native_capacity(disk)) goto rescan; |
ac0d86f58
|
613 614 |
continue; } |
db429e9ec
|
615 |
|
98bd34eaf
|
616 |
if (from + size > get_capacity(disk)) { |
8d99f83b9
|
617 |
printk(KERN_WARNING |
b403a98e2
|
618 |
"%s: p%d size %llu extends beyond EOD, ", |
ac0d86f58
|
619 |
disk->disk_name, p, (unsigned long long) size); |
db429e9ec
|
620 |
|
b403a98e2
|
621 |
if (disk_unlock_native_capacity(disk)) { |
56bca0173
|
622 |
/* free state and restart */ |
56bca0173
|
623 |
goto rescan; |
db429e9ec
|
624 625 626 627 628 629 630 |
} 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
|
631 632 |
size = get_capacity(disk) - from; } |
04ebd4aee
|
633 |
} |
6d1d8050b
|
634 635 636 |
if (state->parts[p].has_info) info = &state->parts[p].info; |
ba32929a9
|
637 |
part = add_partition(disk, p, from, size, |
6d1d8050b
|
638 639 |
state->parts[p].flags, &state->parts[p].info); |
ba32929a9
|
640 641 642 643 |
if (IS_ERR(part)) { printk(KERN_ERR " %s: p%d could not be added: %ld ", disk->disk_name, p, -PTR_ERR(part)); |
04ebd4aee
|
644 |
continue; |
98bd34eaf
|
645 |
} |
1da177e4c
|
646 |
#ifdef CONFIG_BLK_DEV_MD |
d18d7682c
|
647 |
if (state->parts[p].flags & ADDPART_FLAG_RAID) |
55e8e30c3
|
648 |
md_autodetect_dev(part_to_dev(part)->devt); |
1da177e4c
|
649 650 651 652 653 654 655 656 657 658 |
#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
|
659 660 |
page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), NULL); |
1da177e4c
|
661 |
if (!IS_ERR(page)) { |
1da177e4c
|
662 663 664 665 666 667 668 669 670 671 672 673 |
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); |