Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/i386/zfsboot/zfsboot.c
Show First 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* A wrapper for dskread that doesn't have to worry about whether the | * A wrapper for dskread that doesn't have to worry about whether the | ||||
* buffer pointer crosses a 64k boundary. | * buffer pointer crosses a 64k boundary. | ||||
*/ | */ | ||||
static int | static int | ||||
vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | ||||
{ | { | ||||
char *p; | char *p; | ||||
daddr_t lba, alignlba; | daddr_t lba; | ||||
off_t diff; | unsigned int nb; | ||||
unsigned int nb, alignnb; | |||||
struct dsk *dsk = (struct dsk *) priv; | struct dsk *dsk = (struct dsk *) priv; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
daddr_t alignlba; | |||||
off_t diff; | |||||
unsigned int alignnb; | |||||
#endif | |||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | ||||
return -1; | return -1; | ||||
p = buf; | p = buf; | ||||
lba = off / DEV_BSIZE; | lba = off / DEV_BSIZE; | ||||
lba += dsk->start; | lba += dsk->start; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
/* | /* | ||||
* Align reads to 4k else 4k sector GELIs will not decrypt. | * Align reads to 4k else 4k sector GELIs will not decrypt. | ||||
* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. | * Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. | ||||
*/ | */ | ||||
alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; | alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; | ||||
/* | /* | ||||
* The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the | * The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the | ||||
* start of the GELI partition, not the start of the actual disk. | * start of the GELI partition, not the start of the actual disk. | ||||
*/ | */ | ||||
alignlba += dsk->start; | alignlba += dsk->start; | ||||
diff = (lba - alignlba) * DEV_BSIZE; | diff = (lba - alignlba) * DEV_BSIZE; | ||||
#endif | |||||
while (bytes > 0) { | while (bytes > 0) { | ||||
nb = bytes / DEV_BSIZE; | nb = bytes / DEV_BSIZE; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
/* | /* | ||||
* Ensure that the read size plus the leading offset does not | * Ensure that the read size plus the leading offset does not | ||||
* exceed the size of the read buffer. | * exceed the size of the read buffer. | ||||
*/ | */ | ||||
if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) | if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) | ||||
nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; | nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; | ||||
/* | /* | ||||
* Round the number of blocks to read up to the nearest multiple | * Round the number of blocks to read up to the nearest multiple | ||||
* of DEV_GELIBOOT_BSIZE. | * of DEV_GELIBOOT_BSIZE. | ||||
*/ | */ | ||||
alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) | alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) | ||||
/ DEV_BSIZE; | / DEV_BSIZE; | ||||
if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb)) | if (drvread(dsk, dmadat->rdbuf, alignlba, alignnb)) | ||||
return -1; | return -1; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
/* decrypt */ | /* decrypt */ | ||||
if (is_geli(dsk) == 0) { | if (is_geli(dsk) == 0) { | ||||
if (geli_read(dsk, ((alignlba - dsk->start) * | if (geli_io(dsk, GELI_DECRYPT, ((alignlba - dsk->start) | ||||
DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) | * DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) | ||||
return (-1); | return (-1); | ||||
} | } | ||||
#endif | |||||
memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE); | memcpy(p, dmadat->rdbuf + diff, nb * DEV_BSIZE); | ||||
p += nb * DEV_BSIZE; | |||||
lba += nb; | |||||
alignlba += alignnb; | alignlba += alignnb; | ||||
bytes -= nb * DEV_BSIZE; | |||||
/* Don't need the leading offset after the first block. */ | /* Don't need the leading offset after the first block. */ | ||||
diff = 0; | diff = 0; | ||||
#else | |||||
if (nb > READ_BUF_SIZE / DEV_BSIZE) | |||||
nb = READ_BUF_SIZE / DEV_BSIZE; | |||||
if (drvread(dsk, dmadat->rdbuf, lba, nb)) | |||||
return -1; | |||||
memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE); | |||||
#endif | |||||
p += nb * DEV_BSIZE; | |||||
lba += nb; | |||||
bytes -= nb * DEV_BSIZE; | |||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | vdev_write(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) | ||||
{ | { | ||||
char *p; | char *p; | ||||
daddr_t lba; | daddr_t lba; | ||||
unsigned int nb; | unsigned int nb; | ||||
struct dsk *dsk = (struct dsk *) priv; | struct dsk *dsk = (struct dsk *) priv; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
daddr_t alignlba; | |||||
off_t diff; | |||||
unsigned int alignnb; | |||||
#endif | |||||
if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) | ||||
return -1; | return -1; | ||||
p = buf; | p = buf; | ||||
lba = off / DEV_BSIZE; | lba = off / DEV_BSIZE; | ||||
lba += dsk->start; | lba += dsk->start; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
/* | |||||
* Align writes to 4k else 4k sector GELIs will not decrypt. | |||||
* Round LBA down to nearest multiple of DEV_GELIBOOT_BSIZE bytes. | |||||
*/ | |||||
alignlba = rounddown2(off, DEV_GELIBOOT_BSIZE) / DEV_BSIZE; | |||||
/* | |||||
* The read must be aligned to DEV_GELIBOOT_BSIZE bytes relative to the | |||||
* start of the GELI partition, not the start of the actual disk. | |||||
*/ | |||||
alignlba += dsk->start; | |||||
diff = (lba - alignlba) * DEV_BSIZE; | |||||
#endif | |||||
while (bytes > 0) { | while (bytes > 0) { | ||||
nb = bytes / DEV_BSIZE; | nb = bytes / DEV_BSIZE; | ||||
#ifdef LOADER_GELI_SUPPORT | |||||
/* | |||||
* Ensure that the write size plus the leading offset does not | |||||
* exceed the size of the buffer. | |||||
*/ | |||||
if (nb > (READ_BUF_SIZE - diff) / DEV_BSIZE) | |||||
nb = (READ_BUF_SIZE - diff) / DEV_BSIZE; | |||||
/* | |||||
* Round the number of blocks to read up to the nearest multiple | |||||
* of DEV_GELIBOOT_BSIZE. | |||||
*/ | |||||
alignnb = roundup2(nb * DEV_BSIZE + diff, DEV_GELIBOOT_BSIZE) | |||||
/ DEV_BSIZE; | |||||
/* | |||||
* Unaligned writes require read/modify/write. | |||||
*/ | |||||
if (diff > 0) { | |||||
vdev_read(vdev, priv, alignlba * DEV_BSIZE, | |||||
dmadat->rdbuf, DEV_GELIBOOT_BSIZE); | |||||
if (is_geli(dsk) == 0) { | |||||
if (geli_io(dsk, GELI_DECRYPT, | |||||
((alignlba - dsk->start) * | |||||
DEV_BSIZE), dmadat->rdbuf, | |||||
DEV_GELIBOOT_BSIZE)) | |||||
return (-1); | |||||
} | |||||
} | |||||
memcpy(dmadat->rdbuf + diff, p, nb * DEV_BSIZE); | |||||
/* encrypt */ | |||||
if (is_geli(dsk) == 0) { | |||||
if (geli_io(dsk, GELI_ENCRYPT, ((alignlba - dsk->start) | |||||
* DEV_BSIZE), dmadat->rdbuf, alignnb * DEV_BSIZE)) | |||||
return (-1); | |||||
} | |||||
if (drvwrite(dsk, dmadat->rdbuf, alignlba, alignnb)) | |||||
return -1; | |||||
alignlba += alignnb; | |||||
/* Don't need the leading offset after the first block. */ | |||||
diff = 0; | |||||
#else | |||||
if (nb > READ_BUF_SIZE / DEV_BSIZE) | if (nb > READ_BUF_SIZE / DEV_BSIZE) | ||||
nb = READ_BUF_SIZE / DEV_BSIZE; | nb = READ_BUF_SIZE / DEV_BSIZE; | ||||
memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); | memcpy(dmadat->rdbuf, p, nb * DEV_BSIZE); | ||||
if (drvwrite(dsk, dmadat->rdbuf, lba, nb)) | if (drvwrite(dsk, dmadat->rdbuf, lba, nb)) | ||||
return -1; | return -1; | ||||
#endif | |||||
p += nb * DEV_BSIZE; | p += nb * DEV_BSIZE; | ||||
lba += nb; | lba += nb; | ||||
bytes -= nb * DEV_BSIZE; | bytes -= nb * DEV_BSIZE; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 438 Lines • ▼ Show 20 Lines | #endif | ||||
for (;;) | for (;;) | ||||
; | ; | ||||
} | } | ||||
primary_spa = spa; | primary_spa = spa; | ||||
primary_vdev = spa_get_primary_vdev(spa); | primary_vdev = spa_get_primary_vdev(spa); | ||||
nextboot = 0; | nextboot = 0; | ||||
rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd)); | rc = vdev_read_pad2(primary_vdev, cmd, sizeof(cmd)); | ||||
if (vdev_clear_pad2(primary_vdev)) | if (vdev_clear_pad2(primary_vdev)) | ||||
printf("failed to clear pad2 area of primary vdev\n"); | printf("failed to clear pad2 area of primary vdev\n"); | ||||
if (rc == 0) { | if (rc == 0) { | ||||
if (*cmd) { | if (*cmd) { | ||||
/* | /* | ||||
* We could find an old-style ZFS Boot Block header here. | * We could find an old-style ZFS Boot Block header here. | ||||
* Simply ignore it. | * Simply ignore it. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 352 Lines • Show Last 20 Lines |