block: Add driver methods to probe blocksizes and geometry

Introduce driver methods of defining disk blocksizes (physical and
logical) and hard drive geometry.
Methods are only implemented for "host_device". For "raw" devices
driver calls child's method.

For now geometry detection will only work for DASD devices. To check
that a local check_for_dasd function was introduced. It calls BIODASDINFO2
ioctl and returns its rc.

Blocksizes detection function will probe sizes for DASD devices.

Signed-off-by: Ekaterina Tumanova <tumanova@linux.vnet.ibm.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1424087278-49393-4-git-send-email-tumanova@linux.vnet.ibm.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Ekaterina Tumanova 2015-02-16 12:47:56 +01:00 committed by Kevin Wolf
parent 8a4ed0d1b1
commit 1a9335e4a9
2 changed files with 115 additions and 0 deletions

View File

@ -56,6 +56,10 @@
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/fd.h> #include <linux/fd.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/hdreg.h>
#ifdef __s390__
#include <asm/dasd.h>
#endif
#ifndef FS_NOCOW_FL #ifndef FS_NOCOW_FL
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */ #define FS_NOCOW_FL 0x00800000 /* Do not cow file */
#endif #endif
@ -251,6 +255,23 @@ static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
return success ? 0 : -errno; return success ? 0 : -errno;
} }
/**
* Get physical block size of @fd.
* On success, store it in @blk_size and return 0.
* On failure, return -errno.
*/
static int probe_physical_blocksize(int fd, unsigned int *blk_size)
{
#ifdef BLKPBSZGET
if (ioctl(fd, BLKPBSZGET, blk_size) < 0) {
return -errno;
}
return 0;
#else
return -ENOTSUP;
#endif
}
static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp) static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -674,6 +695,86 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.opt_mem_alignment = s->buf_align; bs->bl.opt_mem_alignment = s->buf_align;
} }
static int check_for_dasd(int fd)
{
#ifdef BIODASDINFO2
struct dasd_information2_t info = {0};
return ioctl(fd, BIODASDINFO2, &info);
#else
return -1;
#endif
}
/**
* Try to get @bs's logical and physical block size.
* On success, store them in @bsz and return zero.
* On failure, return negative errno.
*/
static int hdev_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
{
BDRVRawState *s = bs->opaque;
int ret;
/* If DASD, get blocksizes */
if (check_for_dasd(s->fd) < 0) {
return -ENOTSUP;
}
ret = probe_logical_blocksize(s->fd, &bsz->log);
if (ret < 0) {
return ret;
}
return probe_physical_blocksize(s->fd, &bsz->phys);
}
/**
* Try to get @bs's geometry: cyls, heads, sectors.
* On success, store them in @geo and return 0.
* On failure return -errno.
* (Allows block driver to assign default geometry values that guest sees)
*/
#ifdef __linux__
static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{
BDRVRawState *s = bs->opaque;
struct hd_geometry ioctl_geo = {0};
uint32_t blksize;
/* If DASD, get its geometry */
if (check_for_dasd(s->fd) < 0) {
return -ENOTSUP;
}
if (ioctl(s->fd, HDIO_GETGEO, &ioctl_geo) < 0) {
return -errno;
}
/* HDIO_GETGEO may return success even though geo contains zeros
(e.g. certain multipath setups) */
if (!ioctl_geo.heads || !ioctl_geo.sectors || !ioctl_geo.cylinders) {
return -ENOTSUP;
}
/* Do not return a geometry for partition */
if (ioctl_geo.start != 0) {
return -ENOTSUP;
}
geo->heads = ioctl_geo.heads;
geo->sectors = ioctl_geo.sectors;
if (!probe_physical_blocksize(s->fd, &blksize)) {
/* overwrite cyls: HDIO_GETGEO result is incorrect for big drives */
geo->cylinders = bdrv_nb_sectors(bs) / (blksize / BDRV_SECTOR_SIZE)
/ (geo->heads * geo->sectors);
return 0;
}
geo->cylinders = ioctl_geo.cylinders;
return 0;
}
#else /* __linux__ */
static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{
return -ENOTSUP;
}
#endif
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb) static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
{ {
int ret; int ret;
@ -2215,6 +2316,8 @@ static BlockDriver bdrv_host_device = {
.bdrv_get_info = raw_get_info, .bdrv_get_info = raw_get_info,
.bdrv_get_allocated_file_size .bdrv_get_allocated_file_size
= raw_get_allocated_file_size, = raw_get_allocated_file_size,
.bdrv_probe_blocksizes = hdev_probe_blocksizes,
.bdrv_probe_geometry = hdev_probe_geometry,
.bdrv_detach_aio_context = raw_detach_aio_context, .bdrv_detach_aio_context = raw_detach_aio_context,
.bdrv_attach_aio_context = raw_attach_aio_context, .bdrv_attach_aio_context = raw_attach_aio_context,

View File

@ -235,6 +235,16 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
return 1; return 1;
} }
static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
{
return bdrv_probe_blocksizes(bs->file, bsz);
}
static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{
return bdrv_probe_geometry(bs->file, geo);
}
BlockDriver bdrv_raw = { BlockDriver bdrv_raw = {
.format_name = "raw", .format_name = "raw",
.bdrv_probe = &raw_probe, .bdrv_probe = &raw_probe,
@ -252,6 +262,8 @@ BlockDriver bdrv_raw = {
.has_variable_length = true, .has_variable_length = true,
.bdrv_get_info = &raw_get_info, .bdrv_get_info = &raw_get_info,
.bdrv_refresh_limits = &raw_refresh_limits, .bdrv_refresh_limits = &raw_refresh_limits,
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
.bdrv_probe_geometry = &raw_probe_geometry,
.bdrv_is_inserted = &raw_is_inserted, .bdrv_is_inserted = &raw_is_inserted,
.bdrv_media_changed = &raw_media_changed, .bdrv_media_changed = &raw_media_changed,
.bdrv_eject = &raw_eject, .bdrv_eject = &raw_eject,