sma: support bdev-based QoS for vhost_blk devices

test/sma verifies that bdev-based QoS settings are correctly applied on
vhost devices.

Signed-off-by: Sebastian Brzezinka <sebastian.brzezinka@intel.com>
Change-Id: I1b66275dcf457295e6ae58814f1d08ed319fb52a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14338
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Sebastian Brzezinka 2022-09-02 15:19:38 +02:00 committed by Tomasz Zawadzki
parent 2a6f3d9753
commit 4291ed5130
2 changed files with 163 additions and 0 deletions

View File

@ -1,9 +1,11 @@
import logging import logging
import os import os
import uuid
from socket import AddressFamily from socket import AddressFamily
import grpc import grpc
from spdk.rpc.client import JSONRPCException from spdk.rpc.client import JSONRPCException
from spdk.sma import qos
from ..common import format_volume_id, volume_id_to_nguid from ..common import format_volume_id, volume_id_to_nguid
from ..proto import sma_pb2, virtio_blk_pb2 from ..proto import sma_pb2, virtio_blk_pb2
@ -188,3 +190,33 @@ class VhostBlkDeviceManager(DeviceManager):
if not self._delete_controller(client, ctrlr): if not self._delete_controller(client, ctrlr):
raise DeviceException(grpc.StatusCode.INTERNAL, raise DeviceException(grpc.StatusCode.INTERNAL,
'Failed to delete vhost device') 'Failed to delete vhost device')
def set_qos(self, request):
ctrlr = request.device_handle[len(f'{self._prefix}:'):]
volume = format_volume_id(request.volume_id)
try:
with self._client() as client:
nctrlr = self._find_controller(client, ctrlr)
if nctrlr is None:
raise DeviceException(grpc.StatusCode.INVALID_ARGUMENT,
'No device associated with device_handle could be found')
nbdev = nctrlr['backend_specific']['block']['bdev']
if len(request.volume_id) == 0:
id = self._find_bdev(client, nbdev)['uuid']
request.volume_id = uuid.UUID(id).bytes
elif volume is not None:
if not self._bdev_cmp(client, nbdev, volume):
raise DeviceException(grpc.StatusCode.INVALID_ARGUMENT,
'Specified volume is not attached to the device')
else:
raise DeviceException(grpc.StatusCode.INVALID_ARGUMENT,
'Invalid volume uuid')
qos.set_volume_bdev_qos(client, request)
except qos.QosException as ex:
raise DeviceException(ex.code, ex.message)
except JSONRPCException:
raise DeviceException(grpc.StatusCode.INTERNAL,
'Failed to set QoS')
def get_qos_capabilities(self, request):
return qos.get_bdev_qos_capabilities()

View File

@ -195,5 +195,136 @@ crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "cry
delete_device $devid0 delete_device $devid0
[[ $(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")' | jq -r length) -eq 0 ]] [[ $(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")' | jq -r length) -eq 0 ]]
# Test qos
device_vhost=2
device=$(create_device 0 $uuid | jq -r '.handle')
# First check the capabilities
diff <(get_qos_caps $device_vhost | jq --sort-keys) <(
jq --sort-keys <<- CAPS
{
"max_volume_caps": {
"rw_iops": true,
"rd_bandwidth": true,
"wr_bandwidth": true,
"rw_bandwidth": true
}
}
CAPS
)
"$rootdir/scripts/sma-client.py" <<- EOF
{
"method": "SetQos",
"params": {
"device_handle": "$device",
"volume_id": "$(uuid2base64 $uuid)",
"maximum": {
"rd_iops": 0,
"wr_iops": 0,
"rw_iops": 3,
"rd_bandwidth": 4,
"wr_bandwidth": 5,
"rw_bandwidth": 6
}
}
}
EOF
# Make sure that limits were changed
diff <(rpc_cmd bdev_get_bdevs -b null63 | jq --sort-keys '.[].assigned_rate_limits') <(
jq --sort-keys <<- EOF
{
"rw_ios_per_sec": 3000,
"rw_mbytes_per_sec": 6,
"r_mbytes_per_sec": 4,
"w_mbytes_per_sec": 5
}
EOF
)
# Try to set capabilities with empty volume id
"$rootdir/scripts/sma-client.py" <<- EOF
{
"method": "SetQos",
"params": {
"device_handle": "$device",
"volume_id": "",
"maximum": {
"rd_iops": 0,
"wr_iops": 0,
"rw_iops": 4,
"rd_bandwidth": 5,
"wr_bandwidth": 6,
"rw_bandwidth": 7
}
}
}
EOF
# Make sure that limits were changed even if volume id is not set
diff <(rpc_cmd bdev_get_bdevs -b null63 | jq --sort-keys '.[].assigned_rate_limits') <(
jq --sort-keys <<- EOF
{
"rw_ios_per_sec": 4000,
"rw_mbytes_per_sec": 7,
"r_mbytes_per_sec": 5,
"w_mbytes_per_sec": 6
}
EOF
)
# Try none-existing volume uuid
NOT "$rootdir/scripts/sma-client.py" <<- EOF
{
"method": "SetQos",
"params": {
"device_handle": "$device",
"volume_id": "$(uuid2base64 $(uuidgen))",
"maximum": {
"rd_iops": 0,
"wr_iops": 0,
"rw_iops": 5,
"rd_bandwidth": 6,
"wr_bandwidth": 7,
"rw_bandwidth": 8
}
}
}
EOF
# Try invalid (too short) volume uuid
NOT "$rootdir/scripts/sma-client.py" <<- EOF
{
"method": "SetQos",
"params": {
"device_handle": "$device",
"volume_id": "$(base64 <<<'invalid'))",
"maximum": {
"rd_iops": 0,
"wr_iops": 0,
"rw_iops": 5,
"rd_bandwidth": 6,
"wr_bandwidth": 7,
"rw_bandwidth": 8
}
}
}
EOF
# Values remain unchanged
diff <(rpc_cmd bdev_get_bdevs -b null63 | jq --sort-keys '.[].assigned_rate_limits') <(
jq --sort-keys <<- EOF
{
"rw_ios_per_sec": 4000,
"rw_mbytes_per_sec": 7,
"r_mbytes_per_sec": 5,
"w_mbytes_per_sec": 6
}
EOF
)
delete_device "$device"
cleanup cleanup
trap - SIGINT SIGTERM EXIT trap - SIGINT SIGTERM EXIT