|
@@ -161,7 +161,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
|
|
|
struct parsed_partitions *state;
|
|
|
int i, res, err;
|
|
|
|
|
|
- state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
|
|
|
+ state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
|
|
|
if (!state)
|
|
|
return NULL;
|
|
|
|
|
@@ -187,6 +187,8 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
|
|
|
}
|
|
|
if (res > 0)
|
|
|
return state;
|
|
|
+ if (state->access_beyond_eod)
|
|
|
+ err = -ENOSPC;
|
|
|
if (err)
|
|
|
/* The partition is unrecognized. So report I/O errors if there were any */
|
|
|
res = err;
|
|
@@ -539,13 +541,34 @@ exit:
|
|
|
disk_part_iter_exit(&piter);
|
|
|
}
|
|
|
|
|
|
+static bool disk_unlock_native_capacity(struct gendisk *disk)
|
|
|
+{
|
|
|
+ const struct block_device_operations *bdops = disk->fops;
|
|
|
+
|
|
|
+ if (bdops->unlock_native_capacity &&
|
|
|
+ !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
|
|
|
+ printk(KERN_CONT "enabling native capacity\n");
|
|
|
+ bdops->unlock_native_capacity(disk);
|
|
|
+ disk->flags |= GENHD_FL_NATIVE_CAPACITY;
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ printk(KERN_CONT "truncated\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
|
|
|
{
|
|
|
+ struct parsed_partitions *state = NULL;
|
|
|
struct disk_part_iter piter;
|
|
|
struct hd_struct *part;
|
|
|
- struct parsed_partitions *state;
|
|
|
int p, highest, res;
|
|
|
rescan:
|
|
|
+ if (state && !IS_ERR(state)) {
|
|
|
+ kfree(state);
|
|
|
+ state = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
if (bdev->bd_part_count)
|
|
|
return -EBUSY;
|
|
|
res = invalidate_partition(disk, 0);
|
|
@@ -563,8 +586,32 @@ rescan:
|
|
|
bdev->bd_invalidated = 0;
|
|
|
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
|
|
|
return 0;
|
|
|
- if (IS_ERR(state)) /* I/O error reading the partition table */
|
|
|
+ if (IS_ERR(state)) {
|
|
|
+ /*
|
|
|
+ * I/O error reading the partition table. If any
|
|
|
+ * partition code tried to read beyond EOD, retry
|
|
|
+ * after unlocking native capacity.
|
|
|
+ */
|
|
|
+ if (PTR_ERR(state) == -ENOSPC) {
|
|
|
+ printk(KERN_WARNING "%s: partition table beyond EOD, ",
|
|
|
+ disk->disk_name);
|
|
|
+ if (disk_unlock_native_capacity(disk))
|
|
|
+ goto rescan;
|
|
|
+ }
|
|
|
return -EIO;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * If any partition code tried to read beyond EOD, try
|
|
|
+ * unlocking native capacity even if partition table is
|
|
|
+ * sucessfully read as we could be missing some partitions.
|
|
|
+ */
|
|
|
+ if (state->access_beyond_eod) {
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "%s: partition table partially beyond EOD, ",
|
|
|
+ disk->disk_name);
|
|
|
+ if (disk_unlock_native_capacity(disk))
|
|
|
+ goto rescan;
|
|
|
+ }
|
|
|
|
|
|
/* tell userspace that the media / partition table may have changed */
|
|
|
kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
|
|
@@ -590,25 +637,20 @@ rescan:
|
|
|
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",
|
|
|
+ "%s: p%d start %llu is beyond EOD, ",
|
|
|
disk->disk_name, p, (unsigned long long) from);
|
|
|
+ if (disk_unlock_native_capacity(disk))
|
|
|
+ goto rescan;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (from + size > get_capacity(disk)) {
|
|
|
- const struct block_device_operations *bdops = disk->fops;
|
|
|
-
|
|
|
printk(KERN_WARNING
|
|
|
- "%s: p%d size %llu exceeds device capacity, ",
|
|
|
+ "%s: p%d size %llu extends beyond EOD, ",
|
|
|
disk->disk_name, p, (unsigned long long) size);
|
|
|
|
|
|
- if (bdops->unlock_native_capacity &&
|
|
|
- (disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) {
|
|
|
- printk(KERN_CONT "enabling native capacity\n");
|
|
|
- bdops->unlock_native_capacity(disk);
|
|
|
- disk->flags |= GENHD_FL_NATIVE_CAPACITY;
|
|
|
+ if (disk_unlock_native_capacity(disk)) {
|
|
|
/* free state and restart */
|
|
|
- kfree(state);
|
|
|
goto rescan;
|
|
|
} else {
|
|
|
/*
|
|
@@ -617,7 +659,6 @@ rescan:
|
|
|
* 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;
|
|
|
}
|
|
|
}
|