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: default avatarAl Viro <viro@zeniv.linux.org.uk>
Emphatically-Acked-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 02c33b12
...@@ -546,28 +546,49 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -546,28 +546,49 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
/* add partitions */ /* add partitions */
for (p = 1; p < state->limit; p++) { for (p = 1; p < state->limit; p++) {
sector_t size = state->parts[p].size; sector_t size, from;
sector_t from = state->parts[p].from; try_scan:
size = state->parts[p].size;
if (!size) if (!size)
continue; continue;
from = state->parts[p].from;
if (from >= get_capacity(disk)) { if (from >= get_capacity(disk)) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: p%d ignored, start %llu is behind the end of the disk\n", "%s: p%d ignored, start %llu is behind the end of the disk\n",
disk->disk_name, p, (unsigned long long) from); disk->disk_name, p, (unsigned long long) from);
continue; continue;
} }
if (from + size > get_capacity(disk)) { if (from + size > get_capacity(disk)) {
/* struct block_device_operations *bdops = disk->fops;
* we can not ignore partitions of broken tables unsigned long long capacity;
* created by for example camera firmware, but we
* limit them to the end of the disk to avoid
* creating invalid block devices
*/
printk(KERN_WARNING printk(KERN_WARNING
"%s: p%d size %llu exceeds device capacity, " "%s: p%d size %llu exceeds device capacity, ",
"limited to end of disk\n",
disk->disk_name, p, (unsigned long long) size); disk->disk_name, p, (unsigned long long) size);
size = get_capacity(disk) - from;
if (bdops->set_capacity &&
(disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) {
printk(KERN_CONT "enabling native capacity\n");
capacity = bdops->set_capacity(disk, ~0ULL);
disk->flags |= GENHD_FL_NATIVE_CAPACITY;
if (capacity > get_capacity(disk)) {
set_capacity(disk, capacity);
check_disk_size_change(disk, bdev);
bdev->bd_invalidated = 0;
}
goto try_scan;
} 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
*/
printk(KERN_CONT "limited to end of disk\n");
size = get_capacity(disk) - from;
}
} }
part = add_partition(disk, p, from, size, part = add_partition(disk, p, from, size,
state->parts[p].flags); state->parts[p].flags);
......
...@@ -1106,6 +1106,8 @@ struct block_device_operations { ...@@ -1106,6 +1106,8 @@ struct block_device_operations {
int (*direct_access) (struct block_device *, sector_t, int (*direct_access) (struct block_device *, sector_t,
void **, unsigned long *); void **, unsigned long *);
int (*media_changed) (struct gendisk *); int (*media_changed) (struct gendisk *);
unsigned long long (*set_capacity) (struct gendisk *,
unsigned long long);
int (*revalidate_disk) (struct gendisk *); int (*revalidate_disk) (struct gendisk *);
int (*getgeo)(struct block_device *, struct hd_geometry *); int (*getgeo)(struct block_device *, struct hd_geometry *);
struct module *owner; struct module *owner;
......
...@@ -113,6 +113,7 @@ struct hd_struct { ...@@ -113,6 +113,7 @@ struct hd_struct {
#define GENHD_FL_UP 16 #define GENHD_FL_UP 16
#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32
#define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */
#define GENHD_FL_NATIVE_CAPACITY 128
#define BLK_SCSI_MAX_CMDS (256) #define BLK_SCSI_MAX_CMDS (256)
#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment