Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db429e9e authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz
Browse files

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
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -546,29 +546,50 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)

	/* add partitions */
	for (p = 1; p < state->limit; p++) {
		sector_t size = state->parts[p].size;
		sector_t from = state->parts[p].from;
		sector_t size, from;
try_scan:
		size = state->parts[p].size;
		if (!size)
			continue;

		from = state->parts[p].from;
		if (from >= get_capacity(disk)) {
			printk(KERN_WARNING
			       "%s: p%d ignored, start %llu is behind the end of the disk\n",
			       disk->disk_name, p, (unsigned long long) from);
			continue;
		}

		if (from + size > get_capacity(disk)) {
			struct block_device_operations *bdops = disk->fops;
			unsigned long long capacity;

			printk(KERN_WARNING
			       "%s: p%d size %llu exceeds device capacity, ",
			       disk->disk_name, p, (unsigned long long) size);

			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
				 * 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
			       "%s: p%d size %llu exceeds device capacity, "
			       "limited to end of disk\n",
			       disk->disk_name, p, (unsigned long long) size);
				printk(KERN_CONT "limited to end of disk\n");
				size = get_capacity(disk) - from;
			}
		}
		part = add_partition(disk, p, from, size,
				     state->parts[p].flags);
		if (IS_ERR(part)) {
+2 −0
Original line number Diff line number Diff line
@@ -1106,6 +1106,8 @@ struct block_device_operations {
	int (*direct_access) (struct block_device *, sector_t,
						void **, unsigned long *);
	int (*media_changed) (struct gendisk *);
	unsigned long long (*set_capacity) (struct gendisk *,
						unsigned long long);
	int (*revalidate_disk) (struct gendisk *);
	int (*getgeo)(struct block_device *, struct hd_geometry *);
	struct module *owner;
+1 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ struct hd_struct {
#define GENHD_FL_UP				16
#define GENHD_FL_SUPPRESS_PARTITION_INFO	32
#define GENHD_FL_EXT_DEVT			64 /* allow extended devt */
#define GENHD_FL_NATIVE_CAPACITY		128

#define BLK_SCSI_MAX_CMDS	(256)
#define BLK_SCSI_CMD_PER_LONG	(BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))