Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 196876
b: refs/heads/master
c: b403a98
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Jens Axboe committed May 21, 2010
1 parent ffbf4f7 commit e204cd2
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1493bf217f7f59a5d9e2095a7dbcec00fb36ca8b
refs/heads/master: b403a98e260f3a8c7c33f58a07c7ae549852170f
69 changes: 55 additions & 14 deletions trunk/fs/partitions/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -539,13 +541,34 @@ void register_disk(struct gendisk *disk)
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);
Expand All @@ -563,8 +586,32 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
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);
Expand All @@ -590,25 +637,20 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
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 {
/*
Expand All @@ -617,7 +659,6 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
* 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;
}
}
Expand Down
5 changes: 5 additions & 0 deletions trunk/fs/partitions/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ struct parsed_partitions {
} parts[DISK_MAX_PARTS];
int next;
int limit;
bool access_beyond_eod;
};

static inline void *read_part_sector(struct parsed_partitions *state,
sector_t n, Sector *p)
{
if (n >= get_capacity(state->bdev->bd_disk)) {
state->access_beyond_eod = true;
return NULL;
}
return read_dev_sector(state->bdev, n, p);
}

Expand Down

0 comments on commit e204cd2

Please sign in to comment.