Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.20-rc2 613 lines 15 kB view raw
1/* 2 * fs/partitions/check.c 3 * 4 * Code extracted from drivers/block/genhd.c 5 * Copyright (C) 1991-1998 Linus Torvalds 6 * Re-organised Feb 1998 Russell King 7 * 8 * We now have independent partition support from the 9 * block drivers, which allows all the partition code to 10 * be grouped in one location, and it to be mostly self 11 * contained. 12 * 13 * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} 14 */ 15 16#include <linux/init.h> 17#include <linux/module.h> 18#include <linux/fs.h> 19#include <linux/kmod.h> 20#include <linux/ctype.h> 21 22#include "check.h" 23 24#include "acorn.h" 25#include "amiga.h" 26#include "atari.h" 27#include "ldm.h" 28#include "mac.h" 29#include "msdos.h" 30#include "osf.h" 31#include "sgi.h" 32#include "sun.h" 33#include "ibm.h" 34#include "ultrix.h" 35#include "efi.h" 36#include "karma.h" 37 38#ifdef CONFIG_BLK_DEV_MD 39extern void md_autodetect_dev(dev_t dev); 40#endif 41 42int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ 43 44static int (*check_part[])(struct parsed_partitions *, struct block_device *) = { 45 /* 46 * Probe partition formats with tables at disk address 0 47 * that also have an ADFS boot block at 0xdc0. 48 */ 49#ifdef CONFIG_ACORN_PARTITION_ICS 50 adfspart_check_ICS, 51#endif 52#ifdef CONFIG_ACORN_PARTITION_POWERTEC 53 adfspart_check_POWERTEC, 54#endif 55#ifdef CONFIG_ACORN_PARTITION_EESOX 56 adfspart_check_EESOX, 57#endif 58 59 /* 60 * Now move on to formats that only have partition info at 61 * disk address 0xdc0. Since these may also have stale 62 * PC/BIOS partition tables, they need to come before 63 * the msdos entry. 64 */ 65#ifdef CONFIG_ACORN_PARTITION_CUMANA 66 adfspart_check_CUMANA, 67#endif 68#ifdef CONFIG_ACORN_PARTITION_ADFS 69 adfspart_check_ADFS, 70#endif 71 72#ifdef CONFIG_EFI_PARTITION 73 efi_partition, /* this must come before msdos */ 74#endif 75#ifdef CONFIG_SGI_PARTITION 76 sgi_partition, 77#endif 78#ifdef CONFIG_LDM_PARTITION 79 ldm_partition, /* this must come before msdos */ 80#endif 81#ifdef CONFIG_MSDOS_PARTITION 82 msdos_partition, 83#endif 84#ifdef CONFIG_OSF_PARTITION 85 osf_partition, 86#endif 87#ifdef CONFIG_SUN_PARTITION 88 sun_partition, 89#endif 90#ifdef CONFIG_AMIGA_PARTITION 91 amiga_partition, 92#endif 93#ifdef CONFIG_ATARI_PARTITION 94 atari_partition, 95#endif 96#ifdef CONFIG_MAC_PARTITION 97 mac_partition, 98#endif 99#ifdef CONFIG_ULTRIX_PARTITION 100 ultrix_partition, 101#endif 102#ifdef CONFIG_IBM_PARTITION 103 ibm_partition, 104#endif 105#ifdef CONFIG_KARMA_PARTITION 106 karma_partition, 107#endif 108 NULL 109}; 110 111/* 112 * disk_name() is used by partition check code and the genhd driver. 113 * It formats the devicename of the indicated disk into 114 * the supplied buffer (of size at least 32), and returns 115 * a pointer to that same buffer (for convenience). 116 */ 117 118char *disk_name(struct gendisk *hd, int part, char *buf) 119{ 120 if (!part) 121 snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); 122 else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) 123 snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part); 124 else 125 snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part); 126 127 return buf; 128} 129 130const char *bdevname(struct block_device *bdev, char *buf) 131{ 132 int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor; 133 return disk_name(bdev->bd_disk, part, buf); 134} 135 136EXPORT_SYMBOL(bdevname); 137 138/* 139 * There's very little reason to use this, you should really 140 * have a struct block_device just about everywhere and use 141 * bdevname() instead. 142 */ 143const char *__bdevname(dev_t dev, char *buffer) 144{ 145 scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", 146 MAJOR(dev), MINOR(dev)); 147 return buffer; 148} 149 150EXPORT_SYMBOL(__bdevname); 151 152static struct parsed_partitions * 153check_partition(struct gendisk *hd, struct block_device *bdev) 154{ 155 struct parsed_partitions *state; 156 int i, res, err; 157 158 state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); 159 if (!state) 160 return NULL; 161 162 disk_name(hd, 0, state->name); 163 printk(KERN_INFO " %s:", state->name); 164 if (isdigit(state->name[strlen(state->name)-1])) 165 sprintf(state->name, "p"); 166 167 state->limit = hd->minors; 168 i = res = err = 0; 169 while (!res && check_part[i]) { 170 memset(&state->parts, 0, sizeof(state->parts)); 171 res = check_part[i++](state, bdev); 172 if (res < 0) { 173 /* We have hit an I/O error which we don't report now. 174 * But record it, and let the others do their job. 175 */ 176 err = res; 177 res = 0; 178 } 179 180 } 181 if (res > 0) 182 return state; 183 if (!err) 184 /* The partition is unrecognized. So report I/O errors if there were any */ 185 res = err; 186 if (!res) 187 printk(" unknown partition table\n"); 188 else if (warn_no_part) 189 printk(" unable to read partition table\n"); 190 kfree(state); 191 return ERR_PTR(res); 192} 193 194/* 195 * sysfs bindings for partitions 196 */ 197 198struct part_attribute { 199 struct attribute attr; 200 ssize_t (*show)(struct hd_struct *,char *); 201 ssize_t (*store)(struct hd_struct *,const char *, size_t); 202}; 203 204static ssize_t 205part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) 206{ 207 struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); 208 struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); 209 ssize_t ret = 0; 210 if (part_attr->show) 211 ret = part_attr->show(p, page); 212 return ret; 213} 214static ssize_t 215part_attr_store(struct kobject * kobj, struct attribute * attr, 216 const char *page, size_t count) 217{ 218 struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); 219 struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); 220 ssize_t ret = 0; 221 222 if (part_attr->store) 223 ret = part_attr->store(p, page, count); 224 return ret; 225} 226 227static struct sysfs_ops part_sysfs_ops = { 228 .show = part_attr_show, 229 .store = part_attr_store, 230}; 231 232static ssize_t part_uevent_store(struct hd_struct * p, 233 const char *page, size_t count) 234{ 235 kobject_uevent(&p->kobj, KOBJ_ADD); 236 return count; 237} 238static ssize_t part_dev_read(struct hd_struct * p, char *page) 239{ 240 struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); 241 dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); 242 return print_dev_t(page, dev); 243} 244static ssize_t part_start_read(struct hd_struct * p, char *page) 245{ 246 return sprintf(page, "%llu\n",(unsigned long long)p->start_sect); 247} 248static ssize_t part_size_read(struct hd_struct * p, char *page) 249{ 250 return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects); 251} 252static ssize_t part_stat_read(struct hd_struct * p, char *page) 253{ 254 return sprintf(page, "%8u %8llu %8u %8llu\n", 255 p->ios[0], (unsigned long long)p->sectors[0], 256 p->ios[1], (unsigned long long)p->sectors[1]); 257} 258static struct part_attribute part_attr_uevent = { 259 .attr = {.name = "uevent", .mode = S_IWUSR }, 260 .store = part_uevent_store 261}; 262static struct part_attribute part_attr_dev = { 263 .attr = {.name = "dev", .mode = S_IRUGO }, 264 .show = part_dev_read 265}; 266static struct part_attribute part_attr_start = { 267 .attr = {.name = "start", .mode = S_IRUGO }, 268 .show = part_start_read 269}; 270static struct part_attribute part_attr_size = { 271 .attr = {.name = "size", .mode = S_IRUGO }, 272 .show = part_size_read 273}; 274static struct part_attribute part_attr_stat = { 275 .attr = {.name = "stat", .mode = S_IRUGO }, 276 .show = part_stat_read 277}; 278 279#ifdef CONFIG_FAIL_MAKE_REQUEST 280 281static ssize_t part_fail_store(struct hd_struct * p, 282 const char *buf, size_t count) 283{ 284 int i; 285 286 if (count > 0 && sscanf(buf, "%d", &i) > 0) 287 p->make_it_fail = (i == 0) ? 0 : 1; 288 289 return count; 290} 291static ssize_t part_fail_read(struct hd_struct * p, char *page) 292{ 293 return sprintf(page, "%d\n", p->make_it_fail); 294} 295static struct part_attribute part_attr_fail = { 296 .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, 297 .store = part_fail_store, 298 .show = part_fail_read 299}; 300 301#endif 302 303static struct attribute * default_attrs[] = { 304 &part_attr_uevent.attr, 305 &part_attr_dev.attr, 306 &part_attr_start.attr, 307 &part_attr_size.attr, 308 &part_attr_stat.attr, 309#ifdef CONFIG_FAIL_MAKE_REQUEST 310 &part_attr_fail.attr, 311#endif 312 NULL, 313}; 314 315extern struct subsystem block_subsys; 316 317static void part_release(struct kobject *kobj) 318{ 319 struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); 320 kfree(p); 321} 322 323struct kobj_type ktype_part = { 324 .release = part_release, 325 .default_attrs = default_attrs, 326 .sysfs_ops = &part_sysfs_ops, 327}; 328 329static inline void partition_sysfs_add_subdir(struct hd_struct *p) 330{ 331 struct kobject *k; 332 333 k = kobject_get(&p->kobj); 334 p->holder_dir = kobject_add_dir(k, "holders"); 335 kobject_put(k); 336} 337 338static inline void disk_sysfs_add_subdirs(struct gendisk *disk) 339{ 340 struct kobject *k; 341 342 k = kobject_get(&disk->kobj); 343 disk->holder_dir = kobject_add_dir(k, "holders"); 344 disk->slave_dir = kobject_add_dir(k, "slaves"); 345 kobject_put(k); 346} 347 348void delete_partition(struct gendisk *disk, int part) 349{ 350 struct hd_struct *p = disk->part[part-1]; 351 if (!p) 352 return; 353 if (!p->nr_sects) 354 return; 355 disk->part[part-1] = NULL; 356 p->start_sect = 0; 357 p->nr_sects = 0; 358 p->ios[0] = p->ios[1] = 0; 359 p->sectors[0] = p->sectors[1] = 0; 360 sysfs_remove_link(&p->kobj, "subsystem"); 361 if (p->holder_dir) 362 kobject_unregister(p->holder_dir); 363 kobject_uevent(&p->kobj, KOBJ_REMOVE); 364 kobject_del(&p->kobj); 365 kobject_put(&p->kobj); 366} 367 368void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) 369{ 370 struct hd_struct *p; 371 372 p = kmalloc(sizeof(*p), GFP_KERNEL); 373 if (!p) 374 return; 375 376 memset(p, 0, sizeof(*p)); 377 p->start_sect = start; 378 p->nr_sects = len; 379 p->partno = part; 380 p->policy = disk->policy; 381 382 if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) 383 snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); 384 else 385 snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); 386 p->kobj.parent = &disk->kobj; 387 p->kobj.ktype = &ktype_part; 388 kobject_init(&p->kobj); 389 kobject_add(&p->kobj); 390 if (!disk->part_uevent_suppress) 391 kobject_uevent(&p->kobj, KOBJ_ADD); 392 sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem"); 393 partition_sysfs_add_subdir(p); 394 disk->part[part-1] = p; 395} 396 397static char *make_block_name(struct gendisk *disk) 398{ 399 char *name; 400 static char *block_str = "block:"; 401 int size; 402 char *s; 403 404 size = strlen(block_str) + strlen(disk->disk_name) + 1; 405 name = kmalloc(size, GFP_KERNEL); 406 if (!name) 407 return NULL; 408 strcpy(name, block_str); 409 strcat(name, disk->disk_name); 410 /* ewww... some of these buggers have / in name... */ 411 s = strchr(name, '/'); 412 if (s) 413 *s = '!'; 414 return name; 415} 416 417static int disk_sysfs_symlinks(struct gendisk *disk) 418{ 419 struct device *target = get_device(disk->driverfs_dev); 420 int err; 421 char *disk_name = NULL; 422 423 if (target) { 424 disk_name = make_block_name(disk); 425 if (!disk_name) { 426 err = -ENOMEM; 427 goto err_out; 428 } 429 430 err = sysfs_create_link(&disk->kobj, &target->kobj, "device"); 431 if (err) 432 goto err_out_disk_name; 433 434 err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name); 435 if (err) 436 goto err_out_dev_link; 437 } 438 439 err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, 440 "subsystem"); 441 if (err) 442 goto err_out_disk_name_lnk; 443 444 kfree(disk_name); 445 446 return 0; 447 448err_out_disk_name_lnk: 449 if (target) { 450 sysfs_remove_link(&target->kobj, disk_name); 451err_out_dev_link: 452 sysfs_remove_link(&disk->kobj, "device"); 453err_out_disk_name: 454 kfree(disk_name); 455err_out: 456 put_device(target); 457 } 458 return err; 459} 460 461/* Not exported, helper to add_disk(). */ 462void register_disk(struct gendisk *disk) 463{ 464 struct block_device *bdev; 465 char *s; 466 int i; 467 struct hd_struct *p; 468 int err; 469 470 strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); 471 /* ewww... some of these buggers have / in name... */ 472 s = strchr(disk->kobj.name, '/'); 473 if (s) 474 *s = '!'; 475 if ((err = kobject_add(&disk->kobj))) 476 return; 477 err = disk_sysfs_symlinks(disk); 478 if (err) { 479 kobject_del(&disk->kobj); 480 return; 481 } 482 disk_sysfs_add_subdirs(disk); 483 484 /* No minors to use for partitions */ 485 if (disk->minors == 1) 486 goto exit; 487 488 /* No such device (e.g., media were just removed) */ 489 if (!get_capacity(disk)) 490 goto exit; 491 492 bdev = bdget_disk(disk, 0); 493 if (!bdev) 494 goto exit; 495 496 /* scan partition table, but suppress uevents */ 497 bdev->bd_invalidated = 1; 498 disk->part_uevent_suppress = 1; 499 err = blkdev_get(bdev, FMODE_READ, 0); 500 disk->part_uevent_suppress = 0; 501 if (err < 0) 502 goto exit; 503 blkdev_put(bdev); 504 505exit: 506 /* announce disk after possible partitions are already created */ 507 kobject_uevent(&disk->kobj, KOBJ_ADD); 508 509 /* announce possible partitions */ 510 for (i = 1; i < disk->minors; i++) { 511 p = disk->part[i-1]; 512 if (!p || !p->nr_sects) 513 continue; 514 kobject_uevent(&p->kobj, KOBJ_ADD); 515 } 516} 517 518int rescan_partitions(struct gendisk *disk, struct block_device *bdev) 519{ 520 struct parsed_partitions *state; 521 int p, res; 522 523 if (bdev->bd_part_count) 524 return -EBUSY; 525 res = invalidate_partition(disk, 0); 526 if (res) 527 return res; 528 bdev->bd_invalidated = 0; 529 for (p = 1; p < disk->minors; p++) 530 delete_partition(disk, p); 531 if (disk->fops->revalidate_disk) 532 disk->fops->revalidate_disk(disk); 533 if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) 534 return 0; 535 if (IS_ERR(state)) /* I/O error reading the partition table */ 536 return PTR_ERR(state); 537 for (p = 1; p < state->limit; p++) { 538 sector_t size = state->parts[p].size; 539 sector_t from = state->parts[p].from; 540 if (!size) 541 continue; 542 if (from + size > get_capacity(disk)) { 543 printk(" %s: p%d exceeds device capacity\n", 544 disk->disk_name, p); 545 } 546 add_partition(disk, p, from, size); 547#ifdef CONFIG_BLK_DEV_MD 548 if (state->parts[p].flags) 549 md_autodetect_dev(bdev->bd_dev+p); 550#endif 551 } 552 kfree(state); 553 return 0; 554} 555 556unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) 557{ 558 struct address_space *mapping = bdev->bd_inode->i_mapping; 559 struct page *page; 560 561 page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), 562 NULL); 563 if (!IS_ERR(page)) { 564 wait_on_page_locked(page); 565 if (!PageUptodate(page)) 566 goto fail; 567 if (PageError(page)) 568 goto fail; 569 p->v = page; 570 return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9); 571fail: 572 page_cache_release(page); 573 } 574 p->v = NULL; 575 return NULL; 576} 577 578EXPORT_SYMBOL(read_dev_sector); 579 580void del_gendisk(struct gendisk *disk) 581{ 582 int p; 583 584 /* invalidate stuff */ 585 for (p = disk->minors - 1; p > 0; p--) { 586 invalidate_partition(disk, p); 587 delete_partition(disk, p); 588 } 589 invalidate_partition(disk, 0); 590 disk->capacity = 0; 591 disk->flags &= ~GENHD_FL_UP; 592 unlink_gendisk(disk); 593 disk_stat_set_all(disk, 0); 594 disk->stamp = 0; 595 596 kobject_uevent(&disk->kobj, KOBJ_REMOVE); 597 if (disk->holder_dir) 598 kobject_unregister(disk->holder_dir); 599 if (disk->slave_dir) 600 kobject_unregister(disk->slave_dir); 601 if (disk->driverfs_dev) { 602 char *disk_name = make_block_name(disk); 603 sysfs_remove_link(&disk->kobj, "device"); 604 if (disk_name) { 605 sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name); 606 kfree(disk_name); 607 } 608 put_device(disk->driverfs_dev); 609 disk->driverfs_dev = NULL; 610 } 611 sysfs_remove_link(&disk->kobj, "subsystem"); 612 kobject_del(&disk->kobj); 613}