diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-07 07:52:52 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-07 07:52:52 -0400 |
commit | db429e9ec0f9dee2d8e50c154f04f29f880fc9d6 (patch) | |
tree | 363328c6aa85f7a15cc061f7c71f3cc3a8cde970 | |
parent | 02c33b123e59cab5771e52a012aeb810500260a2 (diff) |
partitions: add ->set_capacity block device method
* Add ->set_capacity block device method and use it in rescan_partitions()
to attempt enabling native capacity of the device upon detecting the
partition which exceeds device capacity.
* Add GENHD_FL_NATIVE_CAPACITY flag to try limit attempts of enabling
native capacity during partition scan.
Together with the consecutive patch implementing ->set_capacity method in
ide-gd device driver this allows automatic disabling of Host Protected Area
(HPA) if any partitions overlapping HPA are detected.
Cc: Robert Hancock <hancockrwd@gmail.com>
Cc: Frans Pop <elendil@planet.nl>
Cc: "Andries E. Brouwer" <Andries.Brouwer@cwi.nl>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Emphatically-Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-rw-r--r-- | fs/partitions/check.c | 43 | ||||
-rw-r--r-- | include/linux/blkdev.h | 2 | ||||
-rw-r--r-- | include/linux/genhd.h | 1 |
3 files changed, 35 insertions, 11 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 137a708bb215..4bc2c43fa083 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -546,28 +546,49 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | |||
546 | 546 | ||
547 | /* add partitions */ | 547 | /* add partitions */ |
548 | for (p = 1; p < state->limit; p++) { | 548 | for (p = 1; p < state->limit; p++) { |
549 | sector_t size = state->parts[p].size; | 549 | sector_t size, from; |
550 | sector_t from = state->parts[p].from; | 550 | try_scan: |
551 | size = state->parts[p].size; | ||
551 | if (!size) | 552 | if (!size) |
552 | continue; | 553 | continue; |
554 | |||
555 | from = state->parts[p].from; | ||
553 | if (from >= get_capacity(disk)) { | 556 | if (from >= get_capacity(disk)) { |
554 | printk(KERN_WARNING | 557 | printk(KERN_WARNING |
555 | "%s: p%d ignored, start %llu is behind the end of the disk\n", | 558 | "%s: p%d ignored, start %llu is behind the end of the disk\n", |
556 | disk->disk_name, p, (unsigned long long) from); | 559 | disk->disk_name, p, (unsigned long long) from); |
557 | continue; | 560 | continue; |
558 | } | 561 | } |
562 | |||
559 | if (from + size > get_capacity(disk)) { | 563 | if (from + size > get_capacity(disk)) { |
560 | /* | 564 | struct block_device_operations *bdops = disk->fops; |
561 | * we can not ignore partitions of broken tables | 565 | unsigned long long capacity; |
562 | * created by for example camera firmware, but we | 566 | |
563 | * limit them to the end of the disk to avoid | ||
564 | * creating invalid block devices | ||
565 | */ | ||
566 | printk(KERN_WARNING | 567 | printk(KERN_WARNING |
567 | "%s: p%d size %llu exceeds device capacity, " | 568 | "%s: p%d size %llu exceeds device capacity, ", |
568 | "limited to end of disk\n", | ||
569 | disk->disk_name, p, (unsigned long long) size); | 569 | disk->disk_name, p, (unsigned long long) size); |
570 | size = get_capacity(disk) - from; | 570 | |
571 | if (bdops->set_capacity && | ||
572 | (disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) { | ||
573 | printk(KERN_CONT "enabling native capacity\n"); | ||
574 | capacity = bdops->set_capacity(disk, ~0ULL); | ||
575 | disk->flags |= GENHD_FL_NATIVE_CAPACITY; | ||
576 | if (capacity > get_capacity(disk)) { | ||
577 | set_capacity(disk, capacity); | ||
578 | check_disk_size_change(disk, bdev); | ||
579 | bdev->bd_invalidated = 0; | ||
580 | } | ||
581 | goto try_scan; | ||
582 | } else { | ||
583 | /* | ||
584 | * we can not ignore partitions of broken tables | ||
585 | * created by for example camera firmware, but | ||
586 | * we limit them to the end of the disk to avoid | ||
587 | * creating invalid block devices | ||
588 | */ | ||
589 | printk(KERN_CONT "limited to end of disk\n"); | ||
590 | size = get_capacity(disk) - from; | ||
591 | } | ||
571 | } | 592 | } |
572 | part = add_partition(disk, p, from, size, | 593 | part = add_partition(disk, p, from, size, |
573 | state->parts[p].flags); | 594 | state->parts[p].flags); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6f841fb1be30..a2d7298be351 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -1106,6 +1106,8 @@ struct block_device_operations { | |||
1106 | int (*direct_access) (struct block_device *, sector_t, | 1106 | int (*direct_access) (struct block_device *, sector_t, |
1107 | void **, unsigned long *); | 1107 | void **, unsigned long *); |
1108 | int (*media_changed) (struct gendisk *); | 1108 | int (*media_changed) (struct gendisk *); |
1109 | unsigned long long (*set_capacity) (struct gendisk *, | ||
1110 | unsigned long long); | ||
1109 | int (*revalidate_disk) (struct gendisk *); | 1111 | int (*revalidate_disk) (struct gendisk *); |
1110 | int (*getgeo)(struct block_device *, struct hd_geometry *); | 1112 | int (*getgeo)(struct block_device *, struct hd_geometry *); |
1111 | struct module *owner; | 1113 | struct module *owner; |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 634c53028fb8..239e24b081a9 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -113,6 +113,7 @@ struct hd_struct { | |||
113 | #define GENHD_FL_UP 16 | 113 | #define GENHD_FL_UP 16 |
114 | #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 | 114 | #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 |
115 | #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ | 115 | #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ |
116 | #define GENHD_FL_NATIVE_CAPACITY 128 | ||
116 | 117 | ||
117 | #define BLK_SCSI_MAX_CMDS (256) | 118 | #define BLK_SCSI_MAX_CMDS (256) |
118 | #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) | 119 | #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) |