2013-06-05 16:19:31 +04:00
/*
* Command line utility to exercise the QEMU I / O path .
*
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
* Copyright ( C ) 2009 - 2016 Red Hat , Inc .
2013-06-05 16:19:31 +04:00
* Copyright ( c ) 2003 - 2005 Silicon Graphics , Inc .
*
* This work is licensed under the terms of the GNU GPL , version 2 or later .
* See the COPYING file in the top - level directory .
*/
2016-01-18 21:01:42 +03:00
# include "qemu/osdep.h"
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
# include "qapi/error.h"
2013-06-05 16:19:39 +04:00
# include "qemu-io.h"
2015-02-05 21:58:22 +03:00
# include "sysemu/block-backend.h"
# include "block/block.h"
# include "block/block_int.h" /* for info_f() */
2013-10-09 12:46:17 +04:00
# include "block/qapi.h"
2015-03-17 20:29:20 +03:00
# include "qemu/error-report.h"
2013-08-21 19:02:47 +04:00
# include "qemu/main-loop.h"
2014-01-15 18:39:10 +04:00
# include "qemu/timer.h"
2015-01-30 05:49:42 +03:00
# include "sysemu/block-backend.h"
2016-03-20 20:16:19 +03:00
# include "qemu/cutils.h"
2013-06-05 16:19:31 +04:00
# define CMD_NOFILE_OK 0x01
2014-03-06 01:23:00 +04:00
bool qemuio_misalign ;
2013-06-05 16:19:31 +04:00
2013-06-05 16:19:36 +04:00
static cmdinfo_t * cmdtab ;
static int ncmds ;
static int compare_cmdname ( const void * a , const void * b )
{
return strcmp ( ( ( const cmdinfo_t * ) a ) - > name ,
( ( const cmdinfo_t * ) b ) - > name ) ;
}
void qemuio_add_command ( const cmdinfo_t * ci )
{
2014-08-19 12:31:09 +04:00
cmdtab = g_renew ( cmdinfo_t , cmdtab , + + ncmds ) ;
2013-06-05 16:19:36 +04:00
cmdtab [ ncmds - 1 ] = * ci ;
qsort ( cmdtab , ncmds , sizeof ( * cmdtab ) , compare_cmdname ) ;
}
int qemuio_command_usage ( const cmdinfo_t * ci )
{
printf ( " %s %s -- %s \n " , ci - > name , ci - > args , ci - > oneline ) ;
return 0 ;
}
2015-02-05 21:58:22 +03:00
static int init_check_command ( BlockBackend * blk , const cmdinfo_t * ct )
2013-06-05 16:19:36 +04:00
{
if ( ct - > flags & CMD_FLAG_GLOBAL ) {
return 1 ;
}
2015-02-05 21:58:22 +03:00
if ( ! ( ct - > flags & CMD_NOFILE_OK ) & & ! blk ) {
2013-06-05 16:19:36 +04:00
fprintf ( stderr , " no file open, try 'help open' \n " ) ;
return 0 ;
}
return 1 ;
}
2015-02-05 21:58:22 +03:00
static int command ( BlockBackend * blk , const cmdinfo_t * ct , int argc ,
2013-06-05 16:19:39 +04:00
char * * argv )
2013-06-05 16:19:36 +04:00
{
char * cmd = argv [ 0 ] ;
2015-02-05 21:58:22 +03:00
if ( ! init_check_command ( blk , ct ) ) {
2013-06-05 16:19:36 +04:00
return 0 ;
}
if ( argc - 1 < ct - > argmin | | ( ct - > argmax ! = - 1 & & argc - 1 > ct - > argmax ) ) {
if ( ct - > argmax = = - 1 ) {
fprintf ( stderr ,
" bad argument count %d to %s, expected at least %d arguments \n " ,
argc - 1 , cmd , ct - > argmin ) ;
} else if ( ct - > argmin = = ct - > argmax ) {
fprintf ( stderr ,
" bad argument count %d to %s, expected %d arguments \n " ,
argc - 1 , cmd , ct - > argmin ) ;
} else {
fprintf ( stderr ,
" bad argument count %d to %s, expected between %d and %d arguments \n " ,
argc - 1 , cmd , ct - > argmin , ct - > argmax ) ;
}
return 0 ;
}
optind = 0 ;
2015-02-05 21:58:22 +03:00
return ct - > cfunc ( blk , argc , argv ) ;
2013-06-05 16:19:36 +04:00
}
static const cmdinfo_t * find_command ( const char * cmd )
{
cmdinfo_t * ct ;
for ( ct = cmdtab ; ct < & cmdtab [ ncmds ] ; ct + + ) {
if ( strcmp ( ct - > name , cmd ) = = 0 | |
( ct - > altname & & strcmp ( ct - > altname , cmd ) = = 0 ) )
{
return ( const cmdinfo_t * ) ct ;
}
}
return NULL ;
}
2013-11-14 14:54:18 +04:00
/* Invoke fn() for commands with a matching prefix */
void qemuio_complete_command ( const char * input ,
void ( * fn ) ( const char * cmd , void * opaque ) ,
void * opaque )
{
cmdinfo_t * ct ;
size_t input_len = strlen ( input ) ;
for ( ct = cmdtab ; ct < & cmdtab [ ncmds ] ; ct + + ) {
if ( strncmp ( input , ct - > name , input_len ) = = 0 ) {
fn ( ct - > name , opaque ) ;
}
}
}
2013-06-05 16:19:36 +04:00
static char * * breakline ( char * input , int * count )
{
int c = 0 ;
char * p ;
block: Use g_new() & friends where that makes obvious sense
g_new(T, n) is neater than g_malloc(sizeof(T) * n). It's also safer,
for two reasons. One, it catches multiplication overflowing size_t.
Two, it returns T * rather than void *, which lets the compiler catch
more type errors.
Patch created with Coccinelle, with two manual changes on top:
* Add const to bdrv_iterate_format() to keep the types straight
* Convert the allocation in bdrv_drop_intermediate(), which Coccinelle
inexplicably misses
Coccinelle semantic patch:
@@
type T;
@@
-g_malloc(sizeof(T))
+g_new(T, 1)
@@
type T;
@@
-g_try_malloc(sizeof(T))
+g_try_new(T, 1)
@@
type T;
@@
-g_malloc0(sizeof(T))
+g_new0(T, 1)
@@
type T;
@@
-g_try_malloc0(sizeof(T))
+g_try_new0(T, 1)
@@
type T;
expression n;
@@
-g_malloc(sizeof(T) * (n))
+g_new(T, n)
@@
type T;
expression n;
@@
-g_try_malloc(sizeof(T) * (n))
+g_try_new(T, n)
@@
type T;
expression n;
@@
-g_malloc0(sizeof(T) * (n))
+g_new0(T, n)
@@
type T;
expression n;
@@
-g_try_malloc0(sizeof(T) * (n))
+g_try_new0(T, n)
@@
type T;
expression p, n;
@@
-g_realloc(p, sizeof(T) * (n))
+g_renew(T, p, n)
@@
type T;
expression p, n;
@@
-g_try_realloc(p, sizeof(T) * (n))
+g_try_renew(T, p, n)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-08-19 12:31:08 +04:00
char * * rval = g_new0 ( char * , 1 ) ;
2013-06-05 16:19:36 +04:00
while ( rval & & ( p = qemu_strsep ( & input , " " ) ) ! = NULL ) {
if ( ! * p ) {
continue ;
}
c + + ;
2014-08-19 12:31:10 +04:00
rval = g_renew ( char * , rval , ( c + 1 ) ) ;
2013-06-05 16:19:36 +04:00
rval [ c - 1 ] = p ;
rval [ c ] = NULL ;
}
* count = c ;
return rval ;
}
2013-06-05 16:19:31 +04:00
static int64_t cvtnum ( const char * s )
{
char * end ;
2015-11-06 02:53:03 +03:00
int64_t ret ;
ret = qemu_strtosz_suffix ( s , & end , QEMU_STRTOSZ_DEFSUFFIX_B ) ;
if ( * end ! = ' \0 ' ) {
/* Detritus at the end of the string */
return - EINVAL ;
}
return ret ;
2013-06-05 16:19:31 +04:00
}
2015-11-06 02:53:04 +03:00
static void print_cvtnum_err ( int64_t rc , const char * arg )
{
switch ( rc ) {
case - EINVAL :
printf ( " Parsing error: non-numeric argument, "
" or extraneous/unrecognized suffix -- %s \n " , arg ) ;
break ;
case - ERANGE :
printf ( " Parsing error: argument too large -- %s \n " , arg ) ;
break ;
default :
printf ( " Parsing error: %s \n " , arg ) ;
}
}
2013-06-05 16:19:38 +04:00
# define EXABYTES(x) ((long long)(x) << 60)
# define PETABYTES(x) ((long long)(x) << 50)
# define TERABYTES(x) ((long long)(x) << 40)
# define GIGABYTES(x) ((long long)(x) << 30)
# define MEGABYTES(x) ((long long)(x) << 20)
# define KILOBYTES(x) ((long long)(x) << 10)
# define TO_EXABYTES(x) ((x) / EXABYTES(1))
# define TO_PETABYTES(x) ((x) / PETABYTES(1))
# define TO_TERABYTES(x) ((x) / TERABYTES(1))
# define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
# define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
# define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
static void cvtstr ( double value , char * str , size_t size )
{
char * trim ;
const char * suffix ;
if ( value > = EXABYTES ( 1 ) ) {
suffix = " EiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_EXABYTES ( value ) ) ;
} else if ( value > = PETABYTES ( 1 ) ) {
suffix = " PiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_PETABYTES ( value ) ) ;
} else if ( value > = TERABYTES ( 1 ) ) {
suffix = " TiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_TERABYTES ( value ) ) ;
} else if ( value > = GIGABYTES ( 1 ) ) {
suffix = " GiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_GIGABYTES ( value ) ) ;
} else if ( value > = MEGABYTES ( 1 ) ) {
suffix = " MiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_MEGABYTES ( value ) ) ;
} else if ( value > = KILOBYTES ( 1 ) ) {
suffix = " KiB " ;
snprintf ( str , size - 4 , " %.3f " , TO_KILOBYTES ( value ) ) ;
} else {
suffix = " bytes " ;
snprintf ( str , size - 6 , " %f " , value ) ;
}
trim = strstr ( str , " .000 " ) ;
if ( trim ) {
strcpy ( trim , suffix ) ;
} else {
strcat ( str , suffix ) ;
}
}
static struct timeval tsub ( struct timeval t1 , struct timeval t2 )
{
t1 . tv_usec - = t2 . tv_usec ;
if ( t1 . tv_usec < 0 ) {
t1 . tv_usec + = 1000000 ;
t1 . tv_sec - - ;
}
t1 . tv_sec - = t2 . tv_sec ;
return t1 ;
}
static double tdiv ( double value , struct timeval tv )
{
return value / ( ( double ) tv . tv_sec + ( ( double ) tv . tv_usec / 1000000.0 ) ) ;
}
# define HOURS(sec) ((sec) / (60 * 60))
# define MINUTES(sec) (((sec) % (60 * 60)) / 60)
# define SECONDS(sec) ((sec) % 60)
enum {
DEFAULT_TIME = 0x0 ,
TERSE_FIXED_TIME = 0x1 ,
VERBOSE_FIXED_TIME = 0x2 ,
} ;
static void timestr ( struct timeval * tv , char * ts , size_t size , int format )
{
double usec = ( double ) tv - > tv_usec / 1000000.0 ;
if ( format & TERSE_FIXED_TIME ) {
if ( ! HOURS ( tv - > tv_sec ) ) {
snprintf ( ts , size , " %u:%02u.%02u " ,
( unsigned int ) MINUTES ( tv - > tv_sec ) ,
( unsigned int ) SECONDS ( tv - > tv_sec ) ,
( unsigned int ) ( usec * 100 ) ) ;
return ;
}
format | = VERBOSE_FIXED_TIME ; /* fallback if hours needed */
}
if ( ( format & VERBOSE_FIXED_TIME ) | | tv - > tv_sec ) {
snprintf ( ts , size , " %u:%02u:%02u.%02u " ,
( unsigned int ) HOURS ( tv - > tv_sec ) ,
( unsigned int ) MINUTES ( tv - > tv_sec ) ,
( unsigned int ) SECONDS ( tv - > tv_sec ) ,
( unsigned int ) ( usec * 100 ) ) ;
} else {
snprintf ( ts , size , " 0.%04u sec " , ( unsigned int ) ( usec * 10000 ) ) ;
}
}
2013-06-05 16:19:31 +04:00
/*
* Parse the pattern argument to various sub - commands .
*
* Because the pattern is used as an argument to memset it must evaluate
* to an unsigned integer that fits into a single byte .
*/
static int parse_pattern ( const char * arg )
{
char * endptr = NULL ;
long pattern ;
pattern = strtol ( arg , & endptr , 0 ) ;
if ( pattern < 0 | | pattern > UCHAR_MAX | | * endptr ! = ' \0 ' ) {
printf ( " %s is not a valid pattern byte \n " , arg ) ;
return - 1 ;
}
return pattern ;
}
/*
* Memory allocation helpers .
*
* Make sure memory is aligned by default , or purposefully misaligned if
* that is specified on the command line .
*/
# define MISALIGN_OFFSET 16
2015-02-05 21:58:22 +03:00
static void * qemu_io_alloc ( BlockBackend * blk , size_t len , int pattern )
2013-06-05 16:19:31 +04:00
{
void * buf ;
if ( qemuio_misalign ) {
len + = MISALIGN_OFFSET ;
}
2015-02-05 21:58:22 +03:00
buf = blk_blockalign ( blk , len ) ;
2013-06-05 16:19:31 +04:00
memset ( buf , pattern , len ) ;
if ( qemuio_misalign ) {
buf + = MISALIGN_OFFSET ;
}
return buf ;
}
static void qemu_io_free ( void * p )
{
if ( qemuio_misalign ) {
p - = MISALIGN_OFFSET ;
}
qemu_vfree ( p ) ;
}
2015-11-06 02:53:02 +03:00
static void dump_buffer ( const void * buffer , int64_t offset , int64_t len )
2013-06-05 16:19:31 +04:00
{
2015-11-06 02:53:02 +03:00
uint64_t i ;
int j ;
2013-06-05 16:19:31 +04:00
const uint8_t * p ;
for ( i = 0 , p = buffer ; i < len ; i + = 16 ) {
const uint8_t * s = p ;
printf ( " %08 " PRIx64 " : " , offset + i ) ;
for ( j = 0 ; j < 16 & & i + j < len ; j + + , p + + ) {
printf ( " %02x " , * p ) ;
}
printf ( " " ) ;
for ( j = 0 ; j < 16 & & i + j < len ; j + + , s + + ) {
if ( isalnum ( * s ) ) {
printf ( " %c " , * s ) ;
} else {
printf ( " . " ) ;
}
}
printf ( " \n " ) ;
}
}
static void print_report ( const char * op , struct timeval * t , int64_t offset ,
2016-05-08 06:16:42 +03:00
int64_t count , int64_t total , int cnt , bool Cflag )
2013-06-05 16:19:31 +04:00
{
char s1 [ 64 ] , s2 [ 64 ] , ts [ 64 ] ;
timestr ( t , ts , sizeof ( ts ) , Cflag ? VERBOSE_FIXED_TIME : 0 ) ;
if ( ! Cflag ) {
cvtstr ( ( double ) total , s1 , sizeof ( s1 ) ) ;
cvtstr ( tdiv ( ( double ) total , * t ) , s2 , sizeof ( s2 ) ) ;
2015-11-06 02:53:02 +03:00
printf ( " %s % " PRId64 " /% " PRId64 " bytes at offset % " PRId64 " \n " ,
2013-06-05 16:19:31 +04:00
op , total , count , offset ) ;
printf ( " %s, %d ops; %s (%s/sec and %.4f ops/sec) \n " ,
s1 , cnt , ts , s2 , tdiv ( ( double ) cnt , * t ) ) ;
} else { /* bytes,ops,time,bytes/sec,ops/sec */
2015-11-06 02:53:02 +03:00
printf ( " % " PRId64 " ,%d,%s,%.3f,%.3f \n " ,
2013-06-05 16:19:31 +04:00
total , cnt , ts ,
tdiv ( ( double ) total , * t ) ,
tdiv ( ( double ) cnt , * t ) ) ;
}
}
/*
* Parse multiple length statements for vectored I / O , and construct an I / O
* vector matching it .
*/
static void *
2015-02-05 21:58:22 +03:00
create_iovec ( BlockBackend * blk , QEMUIOVector * qiov , char * * argv , int nr_iov ,
2013-06-05 16:19:31 +04:00
int pattern )
{
size_t * sizes = g_new0 ( size_t , nr_iov ) ;
size_t count = 0 ;
void * buf = NULL ;
void * p ;
int i ;
for ( i = 0 ; i < nr_iov ; i + + ) {
char * arg = argv [ i ] ;
int64_t len ;
len = cvtnum ( arg ) ;
if ( len < 0 ) {
2015-11-06 02:53:04 +03:00
print_cvtnum_err ( len , arg ) ;
2013-06-05 16:19:31 +04:00
goto fail ;
}
/* should be SIZE_T_MAX, but that doesn't exist */
if ( len > INT_MAX ) {
2015-11-06 02:53:04 +03:00
printf ( " Argument '%s' exceeds maximum size %d \n " , arg , INT_MAX ) ;
2013-06-05 16:19:31 +04:00
goto fail ;
}
sizes [ i ] = len ;
count + = len ;
}
qemu_iovec_init ( qiov , nr_iov ) ;
2015-02-05 21:58:22 +03:00
buf = p = qemu_io_alloc ( blk , count , pattern ) ;
2013-06-05 16:19:31 +04:00
for ( i = 0 ; i < nr_iov ; i + + ) {
qemu_iovec_add ( qiov , p , sizes [ i ] ) ;
p + = sizes [ i ] ;
}
fail :
g_free ( sizes ) ;
return buf ;
}
2015-11-06 02:53:02 +03:00
static int do_pread ( BlockBackend * blk , char * buf , int64_t offset ,
int64_t count , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2015-11-06 02:53:02 +03:00
if ( count > INT_MAX ) {
return - ERANGE ;
}
2015-02-05 21:58:22 +03:00
* total = blk_pread ( blk , offset , ( uint8_t * ) buf , count ) ;
2013-06-05 16:19:31 +04:00
if ( * total < 0 ) {
return * total ;
}
return 1 ;
}
2015-11-06 02:53:02 +03:00
static int do_pwrite ( BlockBackend * blk , char * buf , int64_t offset ,
2016-05-08 06:16:44 +03:00
int64_t count , int flags , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2015-11-06 02:53:02 +03:00
if ( count > INT_MAX ) {
return - ERANGE ;
}
2016-05-08 06:16:44 +03:00
* total = blk_pwrite ( blk , offset , ( uint8_t * ) buf , count , flags ) ;
2013-06-05 16:19:31 +04:00
if ( * total < 0 ) {
return * total ;
}
return 1 ;
}
typedef struct {
2015-02-05 21:58:22 +03:00
BlockBackend * blk ;
2013-06-05 16:19:31 +04:00
int64_t offset ;
2015-11-06 02:53:02 +03:00
int64_t count ;
int64_t * total ;
2016-05-08 06:16:44 +03:00
int flags ;
2013-06-05 16:19:31 +04:00
int ret ;
bool done ;
} CoWriteZeroes ;
2016-05-25 01:25:20 +03:00
static void coroutine_fn co_pwrite_zeroes_entry ( void * opaque )
2013-06-05 16:19:31 +04:00
{
CoWriteZeroes * data = opaque ;
2016-05-25 01:25:20 +03:00
data - > ret = blk_co_pwrite_zeroes ( data - > blk , data - > offset , data - > count ,
data - > flags ) ;
2013-06-05 16:19:31 +04:00
data - > done = true ;
if ( data - > ret < 0 ) {
* data - > total = data - > ret ;
return ;
}
* data - > total = data - > count ;
}
2016-05-25 01:25:20 +03:00
static int do_co_pwrite_zeroes ( BlockBackend * blk , int64_t offset ,
int64_t count , int flags , int64_t * total )
2013-06-05 16:19:31 +04:00
{
Coroutine * co ;
CoWriteZeroes data = {
2015-02-05 21:58:22 +03:00
. blk = blk ,
2013-06-05 16:19:31 +04:00
. offset = offset ,
. count = count ,
. total = total ,
2016-05-08 06:16:44 +03:00
. flags = flags ,
2013-06-05 16:19:31 +04:00
. done = false ,
} ;
2015-11-06 02:53:02 +03:00
if ( count > > BDRV_SECTOR_BITS > INT_MAX ) {
return - ERANGE ;
}
2016-05-25 01:25:20 +03:00
co = qemu_coroutine_create ( co_pwrite_zeroes_entry ) ;
2013-06-05 16:19:31 +04:00
qemu_coroutine_enter ( co , & data ) ;
while ( ! data . done ) {
2015-02-05 21:58:22 +03:00
aio_poll ( blk_get_aio_context ( blk ) , true ) ;
2013-06-05 16:19:31 +04:00
}
if ( data . ret < 0 ) {
return data . ret ;
} else {
return 1 ;
}
}
2015-02-05 21:58:22 +03:00
static int do_write_compressed ( BlockBackend * blk , char * buf , int64_t offset ,
2015-11-06 02:53:02 +03:00
int64_t count , int64_t * total )
2013-06-05 16:19:31 +04:00
{
int ret ;
2015-11-06 02:53:02 +03:00
if ( count > > 9 > INT_MAX ) {
return - ERANGE ;
}
2015-02-05 21:58:22 +03:00
ret = blk_write_compressed ( blk , offset > > 9 , ( uint8_t * ) buf , count > > 9 ) ;
2013-06-05 16:19:31 +04:00
if ( ret < 0 ) {
return ret ;
}
* total = count ;
return 1 ;
}
2015-02-05 21:58:22 +03:00
static int do_load_vmstate ( BlockBackend * blk , char * buf , int64_t offset ,
2015-11-06 02:53:02 +03:00
int64_t count , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2015-11-06 02:53:02 +03:00
if ( count > INT_MAX ) {
return - ERANGE ;
}
2015-02-05 21:58:22 +03:00
* total = blk_load_vmstate ( blk , ( uint8_t * ) buf , offset , count ) ;
2013-06-05 16:19:31 +04:00
if ( * total < 0 ) {
return * total ;
}
return 1 ;
}
2015-02-05 21:58:22 +03:00
static int do_save_vmstate ( BlockBackend * blk , char * buf , int64_t offset ,
2015-11-06 02:53:02 +03:00
int64_t count , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2015-11-06 02:53:02 +03:00
if ( count > INT_MAX ) {
return - ERANGE ;
}
2015-02-05 21:58:22 +03:00
* total = blk_save_vmstate ( blk , ( uint8_t * ) buf , offset , count ) ;
2013-06-05 16:19:31 +04:00
if ( * total < 0 ) {
return * total ;
}
return 1 ;
}
# define NOT_DONE 0x7fffffff
static void aio_rw_done ( void * opaque , int ret )
{
* ( int * ) opaque = ret ;
}
2015-02-05 21:58:22 +03:00
static int do_aio_readv ( BlockBackend * blk , QEMUIOVector * qiov ,
2013-06-05 16:19:31 +04:00
int64_t offset , int * total )
{
int async_ret = NOT_DONE ;
2016-05-06 19:26:44 +03:00
blk_aio_preadv ( blk , offset , qiov , 0 , aio_rw_done , & async_ret ) ;
2013-06-05 16:19:31 +04:00
while ( async_ret = = NOT_DONE ) {
main_loop_wait ( false ) ;
}
* total = qiov - > size ;
return async_ret < 0 ? async_ret : 1 ;
}
2015-02-05 21:58:22 +03:00
static int do_aio_writev ( BlockBackend * blk , QEMUIOVector * qiov ,
2016-05-08 06:16:44 +03:00
int64_t offset , int flags , int * total )
2013-06-05 16:19:31 +04:00
{
int async_ret = NOT_DONE ;
2016-05-08 06:16:44 +03:00
blk_aio_pwritev ( blk , offset , qiov , flags , aio_rw_done , & async_ret ) ;
2013-06-05 16:19:31 +04:00
while ( async_ret = = NOT_DONE ) {
main_loop_wait ( false ) ;
}
* total = qiov - > size ;
return async_ret < 0 ? async_ret : 1 ;
}
static void read_help ( void )
{
printf (
" \n "
" reads a range of bytes from the given offset \n "
" \n "
" Example: \n "
" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file \n "
" \n "
" Reads a segment of the currently open file, optionally dumping it to the \n "
" standard output stream (with -v option) for subsequent inspection. \n "
" -b, -- read from the VM state rather than the virtual disk \n "
" -C, -- report statistics in a machine parsable format \n "
" -l, -- length for pattern verification (only with -P) \n "
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
" -p, -- ignored for backwards compatibility \n "
2013-06-05 16:19:31 +04:00
" -P, -- use a pattern to verify read data \n "
" -q, -- quiet mode, do not show I/O statistics \n "
" -s, -- start offset for pattern verification (only with -P) \n "
" -v, -- dump buffer to standard output \n "
" \n " ) ;
}
2015-02-05 21:58:22 +03:00
static int read_f ( BlockBackend * blk , int argc , char * * argv ) ;
2013-06-05 16:19:31 +04:00
static const cmdinfo_t read_cmd = {
. name = " read " ,
. altname = " r " ,
. cfunc = read_f ,
. argmin = 2 ,
. argmax = - 1 ,
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
. args = " [-abCqv] [-P pattern [-s off] [-l len]] off len " ,
2013-06-05 16:19:31 +04:00
. oneline = " reads a number of bytes at a specified offset " ,
. help = read_help ,
} ;
2015-02-05 21:58:22 +03:00
static int read_f ( BlockBackend * blk , int argc , char * * argv )
2013-06-05 16:19:31 +04:00
{
struct timeval t1 , t2 ;
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
bool Cflag = false , qflag = false , vflag = false ;
2016-05-08 06:16:42 +03:00
bool Pflag = false , sflag = false , lflag = false , bflag = false ;
2013-06-05 16:19:31 +04:00
int c , cnt ;
char * buf ;
int64_t offset ;
2015-11-06 02:53:02 +03:00
int64_t count ;
2013-06-05 16:19:31 +04:00
/* Some compilers get confused and warn if this is not initialized. */
2015-11-06 02:53:02 +03:00
int64_t total = 0 ;
int pattern = 0 ;
int64_t pattern_offset = 0 , pattern_count = 0 ;
2013-06-05 16:19:31 +04:00
2015-05-12 18:10:56 +03:00
while ( ( c = getopt ( argc , argv , " bCl:pP:qs:v " ) ) ! = - 1 ) {
2013-06-05 16:19:31 +04:00
switch ( c ) {
case ' b ' :
2016-05-08 06:16:42 +03:00
bflag = true ;
2013-06-05 16:19:31 +04:00
break ;
case ' C ' :
2016-05-08 06:16:42 +03:00
Cflag = true ;
2013-06-05 16:19:31 +04:00
break ;
case ' l ' :
2016-05-08 06:16:42 +03:00
lflag = true ;
2013-06-05 16:19:31 +04:00
pattern_count = cvtnum ( optarg ) ;
if ( pattern_count < 0 ) {
2015-11-06 02:53:04 +03:00
print_cvtnum_err ( pattern_count , optarg ) ;
2013-06-05 16:19:31 +04:00
return 0 ;
}
break ;
case ' p ' :
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
/* Ignored for backwards compatibility */
2013-06-05 16:19:31 +04:00
break ;
case ' P ' :
2016-05-08 06:16:42 +03:00
Pflag = true ;
2013-06-05 16:19:31 +04:00
pattern = parse_pattern ( optarg ) ;
if ( pattern < 0 ) {
return 0 ;
}
break ;
case ' q ' :
2016-05-08 06:16:42 +03:00
qflag = true ;
2013-06-05 16:19:31 +04:00
break ;
case ' s ' :
2016-05-08 06:16:42 +03:00
sflag = true ;
2013-06-05 16:19:31 +04:00
pattern_offset = cvtnum ( optarg ) ;
if ( pattern_offset < 0 ) {
2015-11-06 02:53:04 +03:00
print_cvtnum_err ( pattern_offset , optarg ) ;
2013-06-05 16:19:31 +04:00
return 0 ;
}
break ;
case ' v ' :
2016-05-08 06:16:42 +03:00
vflag = true ;
2013-06-05 16:19:31 +04:00
break ;
default :
2013-06-05 16:19:36 +04:00
return qemuio_command_usage ( & read_cmd ) ;
2013-06-05 16:19:31 +04:00
}
}
if ( optind ! = argc - 2 ) {
2013-06-05 16:19:36 +04:00
return qemuio_command_usage ( & read_cmd ) ;
2013-06-05 16:19:31 +04:00
}
offset = cvtnum ( argv [ optind ] ) ;
if ( offset < 0 ) {
2015-11-06 02:53:04 +03:00
print_cvtnum_err ( offset , argv [ optind ] ) ;
2013-06-05 16:19:31 +04:00
return 0 ;
}
optind + + ;
count = cvtnum ( argv [ optind ] ) ;
if ( count < 0 ) {
2015-11-06 02:53:04 +03:00
print_cvtnum_err ( count , argv [ optind ] ) ;
2013-06-05 16:19:31 +04:00
return 0 ;
2015-11-06 02:53:02 +03:00
} else if ( count > SIZE_MAX ) {
printf ( " length cannot exceed % " PRIu64 " , given %s \n " ,
( uint64_t ) SIZE_MAX , argv [ optind ] ) ;
return 0 ;
2013-06-05 16:19:31 +04:00
}
if ( ! Pflag & & ( lflag | | sflag ) ) {
2013-06-05 16:19:36 +04:00
return qemuio_command_usage ( & read_cmd ) ;
2013-06-05 16:19:31 +04:00
}
if ( ! lflag ) {
pattern_count = count - pattern_offset ;
}
if ( ( pattern_count < 0 ) | | ( pattern_count + pattern_offset > count ) ) {
printf ( " pattern verification range exceeds end of read data \n " ) ;
return 0 ;
}
qemu-io: Allow unaligned access by default
There's no reason to require the user to specify a flag just so
they can pass in unaligned numbers. Keep 'read -p' and 'write -p'
as no-ops so that I don't have to hunt down and update all users
of qemu-io, but otherwise make their behavior default as 'read' and
'write'. Also fix 'write -z', 'readv', 'writev', 'writev',
'aio_read', 'aio_write', and 'aio_write -z'. For now, 'read -b',
'write -b', and 'write -c' still require alignment (and 'multiwrite',
but that's slated to die soon).
qemu-iotest 23 is updated to match, as the only test that was
previously explicitly expecting an error on an unaligned request.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-id: 1462677405-4752-5-git-send-email-eblake@redhat.com
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2016-05-08 06:16:43 +03:00
if ( bflag ) {
2013-06-05 16:19:31 +04:00
if ( offset & 0x1ff ) {
printf ( " offset % " PRId64 " is not sector aligned \n " ,
offset ) ;
return 0 ;
}
if ( count & 0x1ff ) {
2015-11-06 02:53:02 +03:00
printf ( " count % " PRId64 " is not sector aligned \n " ,
2013-06-05 16:19:31 +04:00
count ) ;
return 0 ;
}
}
2015-02-05 21:58:22 +03:00
buf = qemu_io_alloc ( blk , count , 0xab ) ;
2013-06-05 16:19:31 +04:00
gettimeofday ( & t1 , NULL ) ;
2016-05-06 19:26:44 +03:00
if ( bflag ) {
2015-02-05 21:58:22 +03:00
cnt = do_load_vmstate ( blk , buf , offset , count , & total ) ;
2013-06-05 16:19:31 +04:00
} else {