Index: sys/boot/efi/boot1/zfs_module.c =================================================================== --- sys/boot/efi/boot1/zfs_module.c +++ sys/boot/efi/boot1/zfs_module.c @@ -45,22 +45,48 @@ { dev_info_t *devinfo; off_t lba; + size_t size, reminder; + char *bouncebuf = NULL; EFI_STATUS status; devinfo = (dev_info_t *)priv; lba = off / devinfo->dev->Media->BlockSize; + reminder = off % devinfo->dev->Media->BlockSize; - status = devinfo->dev->ReadBlocks(devinfo->dev, - devinfo->dev->Media->MediaId, lba, bytes, buf); - if (status != EFI_SUCCESS) { - DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %jd, size: %zu," - " status: %lu\n", devinfo->dev, - devinfo->dev->Media->MediaId, (intmax_t)lba, bytes, - EFI_ERROR_CODE(status)); - return (-1); + /* + * If we have reminder from off, we need to add reminder part. + * Since buffer must be multiple of the BlockSize, round it all up. + */ + size = roundup2(bytes + reminder, devinfo->dev->Media->BlockSize); + + if (reminder != 0 || size != bytes) { + bouncebuf = malloc(size); + if (bouncebuf == NULL) { + printf("vdev_read: out of memory\n"); + return (-1); + } + status = devinfo->dev->ReadBlocks(devinfo->dev, + devinfo->dev->Media->MediaId, lba, size, bouncebuf); + if (EFI_ERROR(status)) { + free(bouncebuf); + goto error; + } + memcpy(buf, bouncebuf+reminder, bytes); + free(bouncebuf); + } else { + status = devinfo->dev->ReadBlocks(devinfo->dev, + devinfo->dev->Media->MediaId, lba, bytes, buf); + if (EFI_ERROR(status)) + goto error; } return (0); +error: + DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %jd, size: %zu," + " status: %lu\n", devinfo->dev, + devinfo->dev->Media->MediaId, (intmax_t)lba, bytes, + EFI_ERROR_CODE(status)); + return (-1); } static EFI_STATUS