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"
2018-11-12 17:00:42 +03:00
# include "qapi/qmp/qdict.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"
2018-02-01 14:18:46 +03:00
# include "qemu/option.h"
2014-01-15 18:39:10 +04:00
# include "qemu/timer.h"
2016-03-20 20:16:19 +03:00
# include "qemu/cutils.h"
2022-02-26 21:07:23 +03:00
# include "qemu/memalign.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 )
{
2017-03-31 16:38:49 +03:00
/* ci->perm assumes a file is open, but the GLOBAL and NOFILE_OK
* flags allow it not to be , so that combination is invalid .
* Catch it now rather than letting it manifest as a crash if a
* particular set of command line options are used .
*/
assert ( ci - > perm = = 0 | |
( ci - > flags & ( CMD_FLAG_GLOBAL | CMD_NOFILE_OK ) ) = = 0 ) ;
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 ) ;
}
2018-05-09 22:42:58 +03:00
void qemuio_command_usage ( const cmdinfo_t * ci )
2013-06-05 16:19:36 +04:00
{
printf ( " %s %s -- %s \n " , ci - > name , ci - > args , ci - > oneline ) ;
}
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 ;
}
2018-05-09 22:42:59 +03:00
static int command ( BlockBackend * blk , const cmdinfo_t * ct , int argc ,
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 ) ) {
2018-05-09 22:42:59 +03:00
return - EINVAL ;
2013-06-05 16:19:36 +04:00
}
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 ) ;
}
2018-05-09 22:42:59 +03:00
return - EINVAL ;
2013-06-05 16:19:36 +04:00
}
2017-02-10 18:24:56 +03:00
2021-05-19 12:05:32 +03:00
/*
* Request additional permissions if necessary for this command . The caller
2017-02-10 18:24:56 +03:00
* is responsible for restoring the original permissions afterwards if this
2021-05-19 12:05:32 +03:00
* is what it wants .
*
* Coverity thinks that blk may be NULL in the following if condition . It ' s
* not so : in init_check_command ( ) we fail if blk is NULL for command with
* both CMD_FLAG_GLOBAL and CMD_NOFILE_OK flags unset . And in
* qemuio_add_command ( ) we assert that command with non - zero . perm field
* doesn ' t set this flags . So , the following assertion is to silence
* Coverity :
*/
assert ( blk | | ! ct - > perm ) ;
2017-02-10 18:24:56 +03:00
if ( ct - > perm & & blk_is_available ( blk ) ) {
uint64_t orig_perm , orig_shared_perm ;
blk_get_perm ( blk , & orig_perm , & orig_shared_perm ) ;
if ( ct - > perm & ~ orig_perm ) {
uint64_t new_perm ;
Error * local_err = NULL ;
int ret ;
new_perm = orig_perm | ct - > perm ;
ret = blk_set_perm ( blk , new_perm , orig_shared_perm , & local_err ) ;
if ( ret < 0 ) {
error_report_err ( local_err ) ;
2018-05-09 22:42:59 +03:00
return ret ;
2017-02-10 18:24:56 +03:00
}
}
}
qemu-io: Add generic function for reinitializing optind.
On FreeBSD 11.2:
$ nbdkit memory size=1M --run './qemu-io -f raw -c "aio_write 0 512" $nbd'
Parsing error: non-numeric argument, or extraneous/unrecognized suffix -- aio_write
After main option parsing, we reinitialize optind so we can parse each
command. However reinitializing optind to 0 does not work on FreeBSD.
What happens when you do this is optind remains 0 after the option
parsing loop, and the result is we try to parse argv[optind] ==
argv[0] == "aio_write" as if it was the first parameter.
The FreeBSD manual page says:
In order to use getopt() to evaluate multiple sets of arguments, or to
evaluate a single set of arguments multiple times, the variable optreset
must be set to 1 before the second and each additional set of calls to
getopt(), and the variable optind must be reinitialized.
(From the rest of the man page it is clear that optind must be
reinitialized to 1).
The glibc man page says:
A program that scans multiple argument vectors, or rescans the same
vector more than once, and wants to make use of GNU extensions such as
'+' and '-' at the start of optstring, or changes the value of
POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting
optind to 0, rather than the traditional value of 1. (Resetting to 0
forces the invocation of an internal initialization routine that
rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.)
This commit introduces an OS-portability function called
qemu_reset_optind which provides a way of resetting optind that works
on FreeBSD and platforms that use optreset, while keeping it the same
as now on other platforms.
Note that the qemu codebase sets optind in many other places, but in
those other places it's setting a local variable and not using getopt.
This change is only needed in places where we are using getopt and the
associated global variable optind.
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Message-id: 20190118101114.11759-2-rjones@redhat.com
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2019-01-18 13:11:14 +03:00
qemu_reset_optind ( ) ;
2018-05-09 22:42:59 +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 )
{
2017-02-21 23:14:06 +03:00
int err ;
2017-02-21 23:14:07 +03:00
uint64_t value ;
2015-11-06 02:53:03 +03:00
2017-02-21 23:14:06 +03:00
err = qemu_strtosz ( s , NULL , & value ) ;
if ( err < 0 ) {
return err ;
}
2017-02-21 23:14:07 +03:00
if ( value > INT64_MAX ) {
return - ERANGE ;
}
2017-02-21 23:14:06 +03:00
return value ;
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 ) ;
}
}
2019-05-29 19:16:32 +03:00
static struct timespec tsub ( struct timespec t1 , struct timespec t2 )
2013-06-05 16:19:38 +04:00
{
2019-05-29 19:16:32 +03:00
t1 . tv_nsec - = t2 . tv_nsec ;
if ( t1 . tv_nsec < 0 ) {
t1 . tv_nsec + = NANOSECONDS_PER_SECOND ;
2013-06-05 16:19:38 +04:00
t1 . tv_sec - - ;
}
t1 . tv_sec - = t2 . tv_sec ;
return t1 ;
}
2019-05-29 19:16:32 +03:00
static double tdiv ( double value , struct timespec tv )
2013-06-05 16:19:38 +04:00
{
2019-05-29 19:16:32 +03:00
double seconds = tv . tv_sec + ( tv . tv_nsec / 1e9 ) ;
return value / seconds ;
2013-06-05 16:19:38 +04:00
}
# 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 ,
} ;
2019-05-29 19:16:32 +03:00
static void timestr ( struct timespec * tv , char * ts , size_t size , int format )
2013-06-05 16:19:38 +04:00
{
2019-05-29 19:16:32 +03:00
double frac_sec = tv - > tv_nsec / 1e9 ;
2013-06-05 16:19:38 +04:00
if ( format & TERSE_FIXED_TIME ) {
if ( ! HOURS ( tv - > tv_sec ) ) {
2019-05-29 19:16:32 +03:00
snprintf ( ts , size , " %u:%05.2f " ,
( unsigned int ) MINUTES ( tv - > tv_sec ) ,
SECONDS ( tv - > tv_sec ) + frac_sec ) ;
2013-06-05 16:19:38 +04:00
return ;
}
format | = VERBOSE_FIXED_TIME ; /* fallback if hours needed */
}
if ( ( format & VERBOSE_FIXED_TIME ) | | tv - > tv_sec ) {
2019-05-29 19:16:32 +03:00
snprintf ( ts , size , " %u:%02u:%05.2f " ,
2013-06-05 16:19:38 +04:00
( unsigned int ) HOURS ( tv - > tv_sec ) ,
( unsigned int ) MINUTES ( tv - > tv_sec ) ,
2019-05-29 19:16:32 +03:00
SECONDS ( tv - > tv_sec ) + frac_sec ) ;
2013-06-05 16:19:38 +04:00
} else {
2019-05-29 19:16:32 +03:00
snprintf ( ts , size , " %05.2f sec " , frac_sec ) ;
2013-06-05 16:19:38 +04:00
}
}
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
2023-02-07 23:37:18 +03:00
static void * qemu_io_alloc ( BlockBackend * blk , size_t len , int pattern ,
bool register_buf )
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 ) ;
2023-02-07 23:37:18 +03:00
if ( register_buf ) {
blk_register_buf ( blk , buf , len , & error_abort ) ;
}
2013-06-05 16:19:31 +04:00
if ( qemuio_misalign ) {
buf + = MISALIGN_OFFSET ;
}
return buf ;
}
2023-02-07 23:37:18 +03:00
static void qemu_io_free ( BlockBackend * blk , void * p , size_t len ,
bool unregister_buf )
2013-06-05 16:19:31 +04:00
{
if ( qemuio_misalign ) {
p - = MISALIGN_OFFSET ;
2023-02-07 23:37:18 +03:00
len + = MISALIGN_OFFSET ;
}
if ( unregister_buf ) {
blk_unregister_buf ( blk , p , len ) ;
2013-06-05 16:19:31 +04:00
}
qemu_vfree ( p ) ;
}
2019-08-20 19:46:16 +03:00
/*
* qemu_io_alloc_from_file ( )
*
* Allocates the buffer and populates it with the content of the given file
* up to @ len bytes . If the file length is less than @ len , then the buffer
* is populated with the file content cyclically .
*
* @ blk - the block backend where the buffer content is going to be written to
* @ len - the buffer length
* @ file_name - the file to read the content from
2023-02-07 23:37:18 +03:00
* @ register_buf - call blk_register_buf ( )
2019-08-20 19:46:16 +03:00
*
* Returns : the buffer pointer on success
* NULL on error
*/
static void * qemu_io_alloc_from_file ( BlockBackend * blk , size_t len ,
2023-02-07 23:37:18 +03:00
const char * file_name , bool register_buf )
2019-08-20 19:46:16 +03:00
{
2023-02-07 23:37:18 +03:00
size_t alloc_len = len + ( qemuio_misalign ? MISALIGN_OFFSET : 0 ) ;
char * alloc_buf , * buf , * end ;
2019-08-20 19:46:16 +03:00
FILE * f = fopen ( file_name , " r " ) ;
int pattern_len ;
if ( ! f ) {
perror ( file_name ) ;
return NULL ;
}
2023-02-07 23:37:18 +03:00
alloc_buf = buf = blk_blockalign ( blk , alloc_len ) ;
2019-08-20 19:46:16 +03:00
if ( qemuio_misalign ) {
buf + = MISALIGN_OFFSET ;
}
2023-02-07 23:37:18 +03:00
pattern_len = fread ( buf , 1 , len , f ) ;
2019-08-20 19:46:16 +03:00
if ( ferror ( f ) ) {
perror ( file_name ) ;
goto error ;
}
if ( pattern_len = = 0 ) {
fprintf ( stderr , " %s: file is empty \n " , file_name ) ;
goto error ;
}
fclose ( f ) ;
2019-09-10 10:03:06 +03:00
f = NULL ;
2019-08-20 19:46:16 +03:00
2023-02-07 23:37:18 +03:00
if ( register_buf ) {
blk_register_buf ( blk , alloc_buf , alloc_len , & error_abort ) ;
}
2019-08-20 19:46:16 +03:00
2023-02-07 23:37:18 +03:00
end = buf + len ;
for ( char * p = buf + pattern_len ; p < end ; p + = pattern_len ) {
memcpy ( p , buf , MIN ( pattern_len , end - p ) ) ;
2019-08-20 19:46:16 +03:00
}
2023-02-07 23:37:18 +03:00
return buf ;
2019-08-20 19:46:16 +03:00
error :
2023-02-07 23:37:18 +03:00
/*
* This code path is only taken before blk_register_buf ( ) is called , so
* hardcode the qemu_io_free ( ) unregister_buf argument to false .
*/
qemu_io_free ( blk , alloc_buf , alloc_len , false ) ;
2019-09-10 10:03:06 +03:00
if ( f ) {
fclose ( f ) ;
}
2019-08-20 19:46:16 +03:00
return NULL ;
}
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 " ) ;
}
}
2019-05-29 19:16:32 +03:00
static void print_report ( const char * op , struct timespec * 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 ,
2023-02-07 23:37:18 +03:00
int pattern , bool register_buf )
2013-06-05 16:19:31 +04:00
{
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 ;
}
2017-01-31 19:09:54 +03:00
if ( len > BDRV_REQUEST_MAX_BYTES ) {
printf ( " Argument '%s' exceeds maximum size % " PRIu64 " \n " , arg ,
( uint64_t ) BDRV_REQUEST_MAX_BYTES ) ;
goto fail ;
}
if ( count > BDRV_REQUEST_MAX_BYTES - len ) {
printf ( " The total number of bytes exceed the maximum size % " PRIu64
" \n " , ( uint64_t ) BDRV_REQUEST_MAX_BYTES ) ;
2013-06-05 16:19:31 +04:00
goto fail ;
}
sizes [ i ] = len ;
count + = len ;
}
qemu_iovec_init ( qiov , nr_iov ) ;
2023-02-07 23:37:18 +03:00
buf = p = qemu_io_alloc ( blk , count , pattern , register_buf ) ;
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 ,
2023-02-07 23:37:18 +03:00
int64_t bytes , BdrvRequestFlags flags , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2022-07-05 19:15:09 +03:00
int ret ;
2017-06-09 13:18:08 +03:00
if ( bytes > INT_MAX ) {
2015-11-06 02:53:02 +03:00
return - ERANGE ;
}
2023-02-07 23:37:18 +03:00
ret = blk_pread ( blk , offset , bytes , ( uint8_t * ) buf , flags ) ;
2022-07-05 19:15:09 +03:00
if ( ret < 0 ) {
return ret ;
2013-06-05 16:19:31 +04:00
}
2022-07-05 19:15:09 +03:00
* total = bytes ;
2013-06-05 16:19:31 +04:00
return 1 ;
}
2015-11-06 02:53:02 +03:00
static int do_pwrite ( BlockBackend * blk , char * buf , int64_t offset ,
2023-02-07 23:37:17 +03:00
int64_t bytes , BdrvRequestFlags flags , int64_t * total )
2013-06-05 16:19:31 +04:00
{
2022-07-05 19:15:09 +03:00
int ret ;
2017-06-09 13:18:08 +03:00
if ( bytes > INT_MAX ) {
2015-11-06 02:53:02 +03:00
return - ERANGE ;
}
block: Change blk_{pread,pwrite}() param order
Swap 'buf' and 'bytes' around for consistency with
blk_co_{pread,pwrite}(), and in preparation to implement these functions
using generated_co_wrapper.
Callers were updated using this Coccinelle script:
@@ expression blk, offset, buf, bytes, flags; @@
- blk_pread(blk, offset, buf, bytes, flags)
+ blk_pread(blk, offset, bytes, buf, flags)
@@ expression blk, offset, buf, bytes, flags; @@
- blk_pwrite(blk, offset, buf, bytes, flags)
+ blk_pwrite(blk, offset, bytes, buf, flags)
It had no effect on hw/block/nand.c, presumably due to the #if, so that
file was updated manually.
Overly-long lines were then fixed by hand.
Signed-off-by: Alberto Faria <afaria@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Message-Id: <20220705161527.1054072-4-afaria@redhat.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
2022-07-05 19:15:11 +03:00
ret = blk_pwrite ( blk , offset , bytes , ( uint8_t * ) buf , flags ) ;
2022-07-05 19:15:09 +03:00
if ( ret < 0 ) {
return ret ;
2013-06-05 16:19:31 +04:00
}
2022-07-05 19:15:09 +03:00
* total = bytes ;
2013-06-05 16:19:31 +04:00
return 1 ;
}
2022-12-15 16:02:23 +03:00
static int do_pwrite_zeroes ( BlockBackend * blk , int64_t offset ,
2023-02-07 23:37:17 +03:00
int64_t bytes , BdrvRequestFlags flags ,
int64_t * total )
2013-06-05 16:19:31 +04:00
{
2022-12-15 16:02:23 +03:00
int ret = blk_pwrite_zeroes ( blk , offset , bytes ,
flags | BDRV_REQ_ZERO_WRITE ) ;
if ( ret < 0 ) {
return ret ;
2013-06-05 16:19:31 +04:00
}
2022-12-15 16:02:23 +03:00
* total = bytes ;
return 1 ;
2013-06-05 16:19:31 +04:00
}
2015-02-05 21:58:22 +03:00
static int do_write_compressed ( BlockBackend * blk , char * buf , int64_t offset ,
2017-06-09 13:18:08 +03:00
int64_t bytes , int64_t * total )
2013-06-05 16:19:31 +04:00
{
int ret ;
2019-05-14 16:57:35 +03:00
if ( bytes > BDRV_REQUEST_MAX_BYTES ) {
2015-11-06 02:53:02 +03:00
return - ERANGE ;
}
2022-07-05 19:15:18 +03:00
ret = blk_pwrite_compressed ( blk , offset , bytes , buf ) ;
2013-06-05 16:19:31 +04:00
if ( ret < 0 ) {
return ret ;
}
2017-06-09 13:18:08 +03:00
* total = bytes ;
2013-06-05 16:19:31 +04:00
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 ,
2023-02-07 23:37:18 +03:00
int64_t offset , BdrvRequestFlags flags , int * total )
2013-06-05 16:19:31 +04:00
{
int async_ret = NOT_DONE ;
2023-02-07 23:37:18 +03:00
blk_aio_preadv ( 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 ;
}
2015-02-05 21:58:22 +03:00
static int do_aio_writev ( BlockBackend * blk , QEMUIOVector * qiov ,
2023-02-07 23:37:17 +03:00
int64_t offset , BdrvRequestFlags 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 )