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.26-rc5 543 lines 13 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#include <linux/genhd.h> 22 23#include "check.h" 24 25#include "acorn.h" 26#include "amiga.h" 27#include "atari.h" 28#include "ldm.h" 29#include "mac.h" 30#include "msdos.h" 31#include "osf.h" 32#include "sgi.h" 33#include "sun.h" 34#include "ibm.h" 35#include "ultrix.h" 36#include "efi.h" 37#include "karma.h" 38#include "sysv68.h" 39 40#ifdef CONFIG_BLK_DEV_MD 41extern void md_autodetect_dev(dev_t dev); 42#endif 43 44int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ 45 46static int (*check_part[])(struct parsed_partitions *, struct block_device *) = { 47 /* 48 * Probe partition formats with tables at disk address 0 49 * that also have an ADFS boot block at 0xdc0. 50 */ 51#ifdef CONFIG_ACORN_PARTITION_ICS 52 adfspart_check_ICS, 53#endif 54#ifdef CONFIG_ACORN_PARTITION_POWERTEC 55 adfspart_check_POWERTEC, 56#endif 57#ifdef CONFIG_ACORN_PARTITION_EESOX 58 adfspart_check_EESOX, 59#endif 60 61 /* 62 * Now move on to formats that only have partition info at 63 * disk address 0xdc0. Since these may also have stale 64 * PC/BIOS partition tables, they need to come before 65 * the msdos entry. 66 */ 67#ifdef CONFIG_ACORN_PARTITION_CUMANA 68 adfspart_check_CUMANA, 69#endif 70#ifdef CONFIG_ACORN_PARTITION_ADFS 71 adfspart_check_ADFS, 72#endif 73 74#ifdef CONFIG_EFI_PARTITION 75 efi_partition, /* this must come before msdos */ 76#endif 77#ifdef CONFIG_SGI_PARTITION 78 sgi_partition, 79#endif 80#ifdef CONFIG_LDM_PARTITION 81 ldm_partition, /* this must come before msdos */ 82#endif 83#ifdef CONFIG_MSDOS_PARTITION 84 msdos_partition, 85#endif 86#ifdef CONFIG_OSF_PARTITION 87 osf_partition, 88#endif 89#ifdef CONFIG_SUN_PARTITION 90 sun_partition, 91#endif 92#ifdef CONFIG_AMIGA_PARTITION 93 amiga_partition, 94#endif 95#ifdef CONFIG_ATARI_PARTITION 96 atari_partition, 97#endif 98#ifdef CONFIG_MAC_PARTITION 99 mac_partition, 100#endif 101#ifdef CONFIG_ULTRIX_PARTITION 102 ultrix_partition, 103#endif 104#ifdef CONFIG_IBM_PARTITION 105 ibm_partition, 106#endif 107#ifdef CONFIG_KARMA_PARTITION 108 karma_partition, 109#endif 110#ifdef CONFIG_SYSV68_PARTITION 111 sysv68_partition, 112#endif 113 NULL 114}; 115 116/* 117 * disk_name() is used by partition check code and the genhd driver. 118 * It formats the devicename of the indicated disk into 119 * the supplied buffer (of size at least 32), and returns 120 * a pointer to that same buffer (for convenience). 121 */ 122 123char *disk_name(struct gendisk *hd, int part, char *buf) 124{ 125 if (!part) 126 snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); 127 else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) 128 snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part); 129 else 130 snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part); 131 132 return buf; 133} 134 135const char *bdevname(struct block_device *bdev, char *buf) 136{ 137 int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor; 138 return disk_name(bdev->bd_disk, part, buf); 139} 140 141EXPORT_SYMBOL(bdevname); 142 143/* 144 * There's very little reason to use this, you should really 145 * have a struct block_device just about everywhere and use 146 * bdevname() instead. 147 */ 148const char *__bdevname(dev_t dev, char *buffer) 149{ 150 scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", 151 MAJOR(dev), MINOR(dev)); 152 return buffer; 153} 154 155EXPORT_SYMBOL(__bdevname); 156 157static struct parsed_partitions * 158check_partition(struct gendisk *hd, struct block_device *bdev) 159{ 160 struct parsed_partitions *state; 161 int i, res, err; 162 163 state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); 164 if (!state) 165 return NULL; 166 167 disk_name(hd, 0, state->name); 168 printk(KERN_INFO " %s:", state->name); 169 if (isdigit(state->name[strlen(state->name)-1])) 170 sprintf(state->name, "p"); 171 172 state->limit = hd->minors; 173 i = res = err = 0; 174 while (!res && check_part[i]) { 175 memset(&state->parts, 0, sizeof(state->parts)); 176 res = check_part[i++](state, bdev); 177 if (res < 0) { 178 /* We have hit an I/O error which we don't report now. 179 * But record it, and let the others do their job. 180 */ 181 err = res; 182 res = 0; 183 } 184 185 } 186 if (res > 0) 187 return state; 188 if (err) 189 /* The partition is unrecognized. So report I/O errors if there were any */ 190 res = err; 191 if (!res) 192 printk(" unknown partition table\n"); 193 else if (warn_no_part) 194 printk(" unable to read partition table\n"); 195 kfree(state); 196 return ERR_PTR(res); 197} 198 199static ssize_t part_start_show(struct device *dev, 200 struct device_attribute *attr, char *buf) 201{ 202 struct hd_struct *p = dev_to_part(dev); 203 204 return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); 205} 206 207static ssize_t part_size_show(struct device *dev, 208 struct device_attribute *attr, char *buf) 209{ 210 struct hd_struct *p = dev_to_part(dev); 211 return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); 212} 213 214static ssize_t part_stat_show(struct device *dev, 215 struct device_attribute *attr, char *buf) 216{ 217 struct hd_struct *p = dev_to_part(dev); 218 219 preempt_disable(); 220 part_round_stats(p); 221 preempt_enable(); 222 return sprintf(buf, 223 "%8lu %8lu %8llu %8u " 224 "%8lu %8lu %8llu %8u " 225 "%8u %8u %8u" 226 "\n", 227 part_stat_read(p, ios[READ]), 228 part_stat_read(p, merges[READ]), 229 (unsigned long long)part_stat_read(p, sectors[READ]), 230 jiffies_to_msecs(part_stat_read(p, ticks[READ])), 231 part_stat_read(p, ios[WRITE]), 232 part_stat_read(p, merges[WRITE]), 233 (unsigned long long)part_stat_read(p, sectors[WRITE]), 234 jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), 235 p->in_flight, 236 jiffies_to_msecs(part_stat_read(p, io_ticks)), 237 jiffies_to_msecs(part_stat_read(p, time_in_queue))); 238} 239 240#ifdef CONFIG_FAIL_MAKE_REQUEST 241static ssize_t part_fail_show(struct device *dev, 242 struct device_attribute *attr, char *buf) 243{ 244 struct hd_struct *p = dev_to_part(dev); 245 246 return sprintf(buf, "%d\n", p->make_it_fail); 247} 248 249static ssize_t part_fail_store(struct device *dev, 250 struct device_attribute *attr, 251 const char *buf, size_t count) 252{ 253 struct hd_struct *p = dev_to_part(dev); 254 int i; 255 256 if (count > 0 && sscanf(buf, "%d", &i) > 0) 257 p->make_it_fail = (i == 0) ? 0 : 1; 258 259 return count; 260} 261#endif 262 263static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); 264static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); 265static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); 266#ifdef CONFIG_FAIL_MAKE_REQUEST 267static struct device_attribute dev_attr_fail = 268 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); 269#endif 270 271static struct attribute *part_attrs[] = { 272 &dev_attr_start.attr, 273 &dev_attr_size.attr, 274 &dev_attr_stat.attr, 275#ifdef CONFIG_FAIL_MAKE_REQUEST 276 &dev_attr_fail.attr, 277#endif 278 NULL 279}; 280 281static struct attribute_group part_attr_group = { 282 .attrs = part_attrs, 283}; 284 285static struct attribute_group *part_attr_groups[] = { 286 &part_attr_group, 287 NULL 288}; 289 290static void part_release(struct device *dev) 291{ 292 struct hd_struct *p = dev_to_part(dev); 293 free_part_stats(p); 294 kfree(p); 295} 296 297struct device_type part_type = { 298 .name = "partition", 299 .groups = part_attr_groups, 300 .release = part_release, 301}; 302 303static inline void partition_sysfs_add_subdir(struct hd_struct *p) 304{ 305 struct kobject *k; 306 307 k = kobject_get(&p->dev.kobj); 308 p->holder_dir = kobject_create_and_add("holders", k); 309 kobject_put(k); 310} 311 312static inline void disk_sysfs_add_subdirs(struct gendisk *disk) 313{ 314 struct kobject *k; 315 316 k = kobject_get(&disk->dev.kobj); 317 disk->holder_dir = kobject_create_and_add("holders", k); 318 disk->slave_dir = kobject_create_and_add("slaves", k); 319 kobject_put(k); 320} 321 322void delete_partition(struct gendisk *disk, int part) 323{ 324 struct hd_struct *p = disk->part[part-1]; 325 326 if (!p) 327 return; 328 if (!p->nr_sects) 329 return; 330 disk->part[part-1] = NULL; 331 p->start_sect = 0; 332 p->nr_sects = 0; 333 part_stat_set_all(p, 0); 334 kobject_put(p->holder_dir); 335 device_del(&p->dev); 336 put_device(&p->dev); 337} 338 339static ssize_t whole_disk_show(struct device *dev, 340 struct device_attribute *attr, char *buf) 341{ 342 return 0; 343} 344static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, 345 whole_disk_show, NULL); 346 347void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) 348{ 349 struct hd_struct *p; 350 int err; 351 352 p = kzalloc(sizeof(*p), GFP_KERNEL); 353 if (!p) 354 return; 355 356 if (!init_part_stats(p)) { 357 kfree(p); 358 return; 359 } 360 p->start_sect = start; 361 p->nr_sects = len; 362 p->partno = part; 363 p->policy = disk->policy; 364 365 if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1])) 366 snprintf(p->dev.bus_id, BUS_ID_SIZE, 367 "%sp%d", disk->dev.bus_id, part); 368 else 369 snprintf(p->dev.bus_id, BUS_ID_SIZE, 370 "%s%d", disk->dev.bus_id, part); 371 372 device_initialize(&p->dev); 373 p->dev.devt = MKDEV(disk->major, disk->first_minor + part); 374 p->dev.class = &block_class; 375 p->dev.type = &part_type; 376 p->dev.parent = &disk->dev; 377 disk->part[part-1] = p; 378 379 /* delay uevent until 'holders' subdir is created */ 380 p->dev.uevent_suppress = 1; 381 device_add(&p->dev); 382 partition_sysfs_add_subdir(p); 383 p->dev.uevent_suppress = 0; 384 if (flags & ADDPART_FLAG_WHOLEDISK) 385 err = device_create_file(&p->dev, &dev_attr_whole_disk); 386 387 /* suppress uevent if the disk supresses it */ 388 if (!disk->dev.uevent_suppress) 389 kobject_uevent(&p->dev.kobj, KOBJ_ADD); 390} 391 392/* Not exported, helper to add_disk(). */ 393void register_disk(struct gendisk *disk) 394{ 395 struct block_device *bdev; 396 char *s; 397 int i; 398 struct hd_struct *p; 399 int err; 400 401 disk->dev.parent = disk->driverfs_dev; 402 disk->dev.devt = MKDEV(disk->major, disk->first_minor); 403 404 strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN); 405 /* ewww... some of these buggers have / in the name... */ 406 s = strchr(disk->dev.bus_id, '/'); 407 if (s) 408 *s = '!'; 409 410 /* delay uevents, until we scanned partition table */ 411 disk->dev.uevent_suppress = 1; 412 413 if (device_add(&disk->dev)) 414 return; 415#ifndef CONFIG_SYSFS_DEPRECATED 416 err = sysfs_create_link(block_depr, &disk->dev.kobj, 417 kobject_name(&disk->dev.kobj)); 418 if (err) { 419 device_del(&disk->dev); 420 return; 421 } 422#endif 423 disk_sysfs_add_subdirs(disk); 424 425 /* No minors to use for partitions */ 426 if (disk->minors == 1) 427 goto exit; 428 429 /* No such device (e.g., media were just removed) */ 430 if (!get_capacity(disk)) 431 goto exit; 432 433 bdev = bdget_disk(disk, 0); 434 if (!bdev) 435 goto exit; 436 437 bdev->bd_invalidated = 1; 438 err = blkdev_get(bdev, FMODE_READ, 0); 439 if (err < 0) 440 goto exit; 441 blkdev_put(bdev); 442 443exit: 444 /* announce disk after possible partitions are created */ 445 disk->dev.uevent_suppress = 0; 446 kobject_uevent(&disk->dev.kobj, KOBJ_ADD); 447 448 /* announce possible partitions */ 449 for (i = 1; i < disk->minors; i++) { 450 p = disk->part[i-1]; 451 if (!p || !p->nr_sects) 452 continue; 453 kobject_uevent(&p->dev.kobj, KOBJ_ADD); 454 } 455} 456 457int rescan_partitions(struct gendisk *disk, struct block_device *bdev) 458{ 459 struct parsed_partitions *state; 460 int p, res; 461 462 if (bdev->bd_part_count) 463 return -EBUSY; 464 res = invalidate_partition(disk, 0); 465 if (res) 466 return res; 467 bdev->bd_invalidated = 0; 468 for (p = 1; p < disk->minors; p++) 469 delete_partition(disk, p); 470 if (disk->fops->revalidate_disk) 471 disk->fops->revalidate_disk(disk); 472 if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) 473 return 0; 474 if (IS_ERR(state)) /* I/O error reading the partition table */ 475 return -EIO; 476 477 /* tell userspace that the media / partition table may have changed */ 478 kobject_uevent(&disk->dev.kobj, KOBJ_CHANGE); 479 480 for (p = 1; p < state->limit; p++) { 481 sector_t size = state->parts[p].size; 482 sector_t from = state->parts[p].from; 483 if (!size) 484 continue; 485 if (from + size > get_capacity(disk)) { 486 printk(" %s: p%d exceeds device capacity\n", 487 disk->disk_name, p); 488 } 489 add_partition(disk, p, from, size, state->parts[p].flags); 490#ifdef CONFIG_BLK_DEV_MD 491 if (state->parts[p].flags & ADDPART_FLAG_RAID) 492 md_autodetect_dev(bdev->bd_dev+p); 493#endif 494 } 495 kfree(state); 496 return 0; 497} 498 499unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) 500{ 501 struct address_space *mapping = bdev->bd_inode->i_mapping; 502 struct page *page; 503 504 page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), 505 NULL); 506 if (!IS_ERR(page)) { 507 if (PageError(page)) 508 goto fail; 509 p->v = page; 510 return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9); 511fail: 512 page_cache_release(page); 513 } 514 p->v = NULL; 515 return NULL; 516} 517 518EXPORT_SYMBOL(read_dev_sector); 519 520void del_gendisk(struct gendisk *disk) 521{ 522 int p; 523 524 /* invalidate stuff */ 525 for (p = disk->minors - 1; p > 0; p--) { 526 invalidate_partition(disk, p); 527 delete_partition(disk, p); 528 } 529 invalidate_partition(disk, 0); 530 disk->capacity = 0; 531 disk->flags &= ~GENHD_FL_UP; 532 unlink_gendisk(disk); 533 disk_stat_set_all(disk, 0); 534 disk->stamp = 0; 535 536 kobject_put(disk->holder_dir); 537 kobject_put(disk->slave_dir); 538 disk->driverfs_dev = NULL; 539#ifndef CONFIG_SYSFS_DEPRECATED 540 sysfs_remove_link(block_depr, disk->dev.bus_id); 541#endif 542 device_del(&disk->dev); 543}