@ -1276,10 +1276,10 @@ static int get_sysfs_zoned_model(struct stat *st, BlockZoneModel *zoned)
}
# endif /* defined(CONFIG_BLKZONED) */
# ifdef CONFIG_LINUX
/*
* Get a sysfs attribute value as a long integer .
*/
# ifdef CONFIG_LINUX
static long get_sysfs_long_val ( struct stat * st , const char * attribute )
{
g_autofree char * str = NULL ;
@ -1299,6 +1299,30 @@ static long get_sysfs_long_val(struct stat *st, const char *attribute)
}
return ret ;
}
/*
* Get a sysfs attribute value as a uint32_t .
*/
static int get_sysfs_u32_val ( struct stat * st , const char * attribute ,
uint32_t * u32 )
{
g_autofree char * str = NULL ;
const char * end ;
unsigned int val ;
int ret ;
ret = get_sysfs_str_val ( st , attribute , & str ) ;
if ( ret < 0 ) {
return ret ;
}
/* The file is ended with '\n', pass 'end' to accept that. */
ret = qemu_strtoui ( str , & end , 10 , & val ) ;
if ( ret = = 0 & & end & & * end = = ' \0 ' ) {
* u32 = val ;
}
return ret ;
}
# endif
static int hdev_get_max_segments ( int fd , struct stat * st )
@ -1318,6 +1342,23 @@ static int hdev_get_max_segments(int fd, struct stat *st)
# endif
}
/*
* Fills in * dalign with the discard alignment and returns 0 on success ,
* - errno otherwise .
*/
static int hdev_get_pdiscard_alignment ( struct stat * st , uint32_t * dalign )
{
# ifdef CONFIG_LINUX
/*
* Note that Linux " discard_granularity " is QEMU " discard_alignment " . Linux
* " discard_alignment " is something else .
*/
return get_sysfs_u32_val ( st , " discard_granularity " , dalign ) ;
# else
return - ENOTSUP ;
# endif
}
# if defined(CONFIG_BLKZONED)
/*
* If the reset_all flag is true , then the wps of zone whose state is
@ -1527,6 +1568,30 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
}
}
if ( S_ISBLK ( st . st_mode ) ) {
uint32_t dalign = 0 ;
int ret ;
ret = hdev_get_pdiscard_alignment ( & st , & dalign ) ;
if ( ret = = 0 ) {
uint32_t ralign = bs - > bl . request_alignment ;
/* Probably never happens, but handle it just in case */
if ( dalign < ralign & & ( ralign % dalign = = 0 ) ) {
dalign = ralign ;
}
/* The block layer requires a multiple of request_alignment */
if ( dalign % ralign ! = 0 ) {
error_setg ( errp , " Invalid pdiscard_alignment limit %u is not a "
" multiple of request_alignment %u " , dalign , ralign ) ;
return ;
}
bs - > bl . pdiscard_alignment = dalign ;
}
}
raw_refresh_zoned_limits ( bs , & st , errp ) ;
}