aboutsummaryrefslogtreecommitdiffstats
path: root/fs/partitions
diff options
context:
space:
mode:
Diffstat (limited to 'fs/partitions')
-rw-r--r--fs/partitions/check.c69
-rw-r--r--fs/partitions/check.h5
2 files changed, 60 insertions, 14 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index a19995c6f6af..5dcd4b0c5533 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -161,7 +161,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
161 struct parsed_partitions *state; 161 struct parsed_partitions *state;
162 int i, res, err; 162 int i, res, err;
163 163
164 state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); 164 state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
165 if (!state) 165 if (!state)
166 return NULL; 166 return NULL;
167 167
@@ -187,6 +187,8 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
187 } 187 }
188 if (res > 0) 188 if (res > 0)
189 return state; 189 return state;
190 if (state->access_beyond_eod)
191 err = -ENOSPC;
190 if (err) 192 if (err)
191 /* The partition is unrecognized. So report I/O errors if there were any */ 193 /* The partition is unrecognized. So report I/O errors if there were any */
192 res = err; 194 res = err;
@@ -539,13 +541,34 @@ exit:
539 disk_part_iter_exit(&piter); 541 disk_part_iter_exit(&piter);
540} 542}
541 543
544static bool disk_unlock_native_capacity(struct gendisk *disk)
545{
546 const struct block_device_operations *bdops = disk->fops;
547
548 if (bdops->unlock_native_capacity &&
549 !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
550 printk(KERN_CONT "enabling native capacity\n");
551 bdops->unlock_native_capacity(disk);
552 disk->flags |= GENHD_FL_NATIVE_CAPACITY;
553 return true;
554 } else {
555 printk(KERN_CONT "truncated\n");
556 return false;
557 }
558}
559
542int rescan_partitions(struct gendisk *disk, struct block_device *bdev) 560int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
543{ 561{
562 struct parsed_partitions *state = NULL;
544 struct disk_part_iter piter; 563 struct disk_part_iter piter;
545 struct hd_struct *part; 564 struct hd_struct *part;
546 struct parsed_partitions *state;
547 int p, highest, res; 565 int p, highest, res;
548rescan: 566rescan:
567 if (state && !IS_ERR(state)) {
568 kfree(state);
569 state = NULL;
570 }
571
549 if (bdev->bd_part_count) 572 if (bdev->bd_part_count)
550 return -EBUSY; 573 return -EBUSY;
551 res = invalidate_partition(disk, 0); 574 res = invalidate_partition(disk, 0);
@@ -563,8 +586,32 @@ rescan:
563 bdev->bd_invalidated = 0; 586 bdev->bd_invalidated = 0;
564 if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) 587 if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
565 return 0; 588 return 0;
566 if (IS_ERR(state)) /* I/O error reading the partition table */ 589 if (IS_ERR(state)) {
590 /*
591 * I/O error reading the partition table. If any
592 * partition code tried to read beyond EOD, retry
593 * after unlocking native capacity.
594 */
595 if (PTR_ERR(state) == -ENOSPC) {
596 printk(KERN_WARNING "%s: partition table beyond EOD, ",
597 disk->disk_name);
598 if (disk_unlock_native_capacity(disk))
599 goto rescan;
600 }
567 return -EIO; 601 return -EIO;
602 }
603 /*
604 * If any partition code tried to read beyond EOD, try
605 * unlocking native capacity even if partition table is
606 * sucessfully read as we could be missing some partitions.
607 */
608 if (state->access_beyond_eod) {
609 printk(KERN_WARNING
610 "%s: partition table partially beyond EOD, ",
611 disk->disk_name);
612 if (disk_unlock_native_capacity(disk))
613 goto rescan;
614 }
568 615
569 /* tell userspace that the media / partition table may have changed */ 616 /* tell userspace that the media / partition table may have changed */
570 kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); 617 kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
@@ -590,25 +637,20 @@ rescan:
590 from = state->parts[p].from; 637 from = state->parts[p].from;
591 if (from >= get_capacity(disk)) { 638 if (from >= get_capacity(disk)) {
592 printk(KERN_WARNING 639 printk(KERN_WARNING
593 "%s: p%d ignored, start %llu is behind the end of the disk\n", 640 "%s: p%d start %llu is beyond EOD, ",
594 disk->disk_name, p, (unsigned long long) from); 641 disk->disk_name, p, (unsigned long long) from);
642 if (disk_unlock_native_capacity(disk))
643 goto rescan;
595 continue; 644 continue;
596 } 645 }
597 646
598 if (from + size > get_capacity(disk)) { 647 if (from + size > get_capacity(disk)) {
599 const struct block_device_operations *bdops = disk->fops;
600
601 printk(KERN_WARNING 648 printk(KERN_WARNING
602 "%s: p%d size %llu exceeds device capacity, ", 649 "%s: p%d size %llu extends beyond EOD, ",
603 disk->disk_name, p, (unsigned long long) size); 650 disk->disk_name, p, (unsigned long long) size);
604 651
605 if (bdops->unlock_native_capacity && 652 if (disk_unlock_native_capacity(disk)) {
606 (disk->flags & GENHD_FL_NATIVE_CAPACITY) == 0) {
607 printk(KERN_CONT "enabling native capacity\n");
608 bdops->unlock_native_capacity(disk);
609 disk->flags |= GENHD_FL_NATIVE_CAPACITY;
610 /* free state and restart */ 653 /* free state and restart */
611 kfree(state);
612 goto rescan; 654 goto rescan;
613 } else { 655 } else {
614 /* 656 /*
@@ -617,7 +659,6 @@ rescan:
617 * we limit them to the end of the disk to avoid 659 * we limit them to the end of the disk to avoid
618 * creating invalid block devices 660 * creating invalid block devices
619 */ 661 */
620 printk(KERN_CONT "limited to end of disk\n");
621 size = get_capacity(disk) - from; 662 size = get_capacity(disk) - from;
622 } 663 }
623 } 664 }
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
index 4b31a97775be..52f8bd399396 100644
--- a/fs/partitions/check.h
+++ b/fs/partitions/check.h
@@ -15,11 +15,16 @@ struct parsed_partitions {
15 } parts[DISK_MAX_PARTS]; 15 } parts[DISK_MAX_PARTS];
16 int next; 16 int next;
17 int limit; 17 int limit;
18 bool access_beyond_eod;
18}; 19};
19 20
20static inline void *read_part_sector(struct parsed_partitions *state, 21static inline void *read_part_sector(struct parsed_partitions *state,
21 sector_t n, Sector *p) 22 sector_t n, Sector *p)
22{ 23{
24 if (n >= get_capacity(state->bdev->bd_disk)) {
25 state->access_beyond_eod = true;
26 return NULL;
27 }
23 return read_dev_sector(state->bdev, n, p); 28 return read_dev_sector(state->bdev, n, p);
24} 29}
25 30