diff options
| author | Toomas Soome <tsoome@me.com> | 2016-11-21 00:29:06 +0200 |
|---|---|---|
| committer | Dan McDonald <danmcd@omniti.com> | 2017-01-23 13:59:29 -0500 |
| commit | 252244c3410eebc24658f285a920786b16c56862 (patch) | |
| tree | 37d098d32a59029be6cb1a1d8b4b40b5da9adebb /usr/src | |
| parent | 1ab55c5b11c6901ca810d93fdd657fb57ca800f1 (diff) | |
| download | illumos-joyent-252244c3410eebc24658f285a920786b16c56862.tar.gz | |
7598 loader: Implement disk_ioctl() to support DIOCGSECTORSIZE and DIOCGMEDIASIZE.
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Juraj Lutter <juraj@lutter.sk>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/boot/sys/boot/common/disk.c | 45 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/part.c | 33 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/common/part.h | 1 |
3 files changed, 71 insertions, 8 deletions
diff --git a/usr/src/boot/sys/boot/common/disk.c b/usr/src/boot/sys/boot/common/disk.c index bad0a700c4..088013b0c6 100644 --- a/usr/src/boot/sys/boot/common/disk.c +++ b/usr/src/boot/sys/boot/common/disk.c @@ -45,7 +45,8 @@ __FBSDID("$FreeBSD$"); struct open_disk { struct ptable *table; - off_t mediasize; + uint64_t mediasize; + uint64_t entrysize; u_int sectorsize; u_int flags; int rcnt; @@ -64,7 +65,7 @@ struct dentry { int d_partition; struct open_disk *od; - off_t d_offset; + uint64_t d_offset; STAILQ_ENTRY(dentry) entry; #ifdef DISK_DEBUG uint32_t count; @@ -263,13 +264,28 @@ disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) } int -disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *buf) +disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data) { + struct open_disk *od = dev->d_opendata; + + if (od == NULL) + return (ENOTTY); + + switch (cmd) { + case DIOCGSECTORSIZE: + *(u_int *)data = od->sectorsize; + break; + case DIOCGMEDIASIZE: + if (dev->d_offset == 0) + *(uint64_t *)data = od->mediasize; + else + *(uint64_t *)data = od->entrysize * od->sectorsize; + break; + default: + return (ENOTTY); + } - if (dev->d_dev->dv_ioctl) - return ((*dev->d_dev->dv_ioctl)(dev->d_opendata, cmd, buf)); - - return (ENXIO); + return (0); } int @@ -314,6 +330,7 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize, } dev->d_opendata = od; od->rcnt = 0; + od->entrysize = 0; } od->mediasize = mediasize; od->sectorsize = sectorsize; @@ -329,14 +346,24 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize, rc = ENXIO; goto out; } + + if (ptable_getsize(od->table, &mediasize) != 0) { + rc = ENXIO; + goto out; + } + if (mediasize > od->mediasize) { + od->mediasize = mediasize; + } opened: rc = 0; if (ptable_gettype(od->table) == PTABLE_BSD && partition >= 0) { /* It doesn't matter what value has d_slice */ rc = ptable_getpart(od->table, &part, partition); - if (rc == 0) + if (rc == 0) { dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; + } } else if (slice >= 0) { /* Try to get information about partition */ if (slice == 0) @@ -346,6 +373,7 @@ opened: if (rc != 0) /* Partition doesn't exist */ goto out; dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; slice = part.index; if (ptable_gettype(od->table) == PTABLE_GPT) { partition = 255; @@ -389,6 +417,7 @@ opened: if (rc != 0) goto out; dev->d_offset += part.start; + od->entrysize = part.end - part.start + 1; } out: if (table != NULL) diff --git a/usr/src/boot/sys/boot/common/part.c b/usr/src/boot/sys/boot/common/part.c index 800641bd86..4539c9c4b7 100644 --- a/usr/src/boot/sys/boot/common/part.c +++ b/usr/src/boot/sys/boot/common/part.c @@ -330,10 +330,30 @@ ptable_gptread(struct ptable *table, void *dev, diskread_t dread) DEBUG("GPT detected"); size = MIN(hdr.hdr_entries * hdr.hdr_entsz, MAXTBLSZ * table->sectorsize); + + /* + * If the disk's sector count is smaller than the sector count recorded + * in the disk's GPT table header, set the table->sectors to the value + * recorded in GPT tables. This is done to work around buggy firmware + * that returns truncated disk sizes. + * + * Note, this is still not a foolproof way to get disk's size. For + * example, an image file can be truncated when copied to smaller media. + */ + if (hdr.hdr_lba_alt + 1 > table->sectors) + table->sectors = hdr.hdr_lba_alt + 1; + for (i = 0; i < size / hdr.hdr_entsz; i++) { ent = (struct gpt_ent *)(tbl + i * hdr.hdr_entsz); if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) continue; + + /* Simple sanity checks. */ + if (ent->ent_lba_start < hdr.hdr_lba_start || + ent->ent_lba_end > hdr.hdr_lba_end || + ent->ent_lba_start > ent->ent_lba_end) + continue; + entry = malloc(sizeof(*entry)); if (entry == NULL) break; @@ -846,6 +866,19 @@ ptable_gettype(const struct ptable *table) } int +ptable_getsize(const struct ptable *table, uint64_t *sizep) +{ + uint64_t tmp = table->sectors * table->sectorsize; + + if (tmp < table->sectors) + return (EOVERFLOW); + + if (sizep != NULL) + *sizep = tmp; + return (0); +} + +int ptable_getpart(const struct ptable *table, struct ptable_entry *part, int idx) { struct pentry *entry; diff --git a/usr/src/boot/sys/boot/common/part.h b/usr/src/boot/sys/boot/common/part.h index 1dc83815b9..a554016d92 100644 --- a/usr/src/boot/sys/boot/common/part.h +++ b/usr/src/boot/sys/boot/common/part.h @@ -83,6 +83,7 @@ struct ptable *ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, diskread_t *dread); void ptable_close(struct ptable *table); enum ptable_type ptable_gettype(const struct ptable *table); +int ptable_getsize(const struct ptable *table, uint64_t *sizep); int ptable_getpart(const struct ptable *table, struct ptable_entry *part, int index); |
