Commit 4291ed51 authored by Sebastian Brzezinka's avatar Sebastian Brzezinka Committed by Tomasz Zawadzki
Browse files

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: default avatarSebastian Brzezinka <sebastian.brzezinka@intel.com>
Change-Id: I1b66275dcf457295e6ae58814f1d08ed319fb52a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14338


Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 2a6f3d97
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
import logging
import os
import uuid
from socket import AddressFamily

import grpc
from spdk.rpc.client import JSONRPCException
from spdk.sma import qos

from ..common import format_volume_id, volume_id_to_nguid
from ..proto import sma_pb2, virtio_blk_pb2
@@ -188,3 +190,33 @@ class VhostBlkDeviceManager(DeviceManager):
            if not self._delete_controller(client, ctrlr):
                raise DeviceException(grpc.StatusCode.INTERNAL,
                                      '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()
+131 −0
Original line number Diff line number Diff line
@@ -195,5 +195,136 @@ crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "cry
delete_device $devid0
[[ $(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
trap - SIGINT SIGTERM EXIT