Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions qemu/tests/cfg/virtio_fs_rlimit_nofile.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
- virtio_fs_rlimit_nofile:
only Linux
no RHEL.6 RHEL.7 RHEL.8.0 RHEL.8.1
no Host_RHEL.m6 Host_RHEL.m7 Host_RHEL.m8.u0 Host_RHEL.m8.u1
type = virtio_fs_rlimit_nofile
required_virtiofsd_version = [1.13.2-1,)
virtiofsd_version_cmd = rpm -q virtiofsd | cut -d- -f2
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Version check may under-report: include release in rpm query

cut -d- -f2 returns only VERSION (e.g., 1.13.2), but required_virtiofsd_version = [1.13.2-1,) expects VERSION-RELEASE. Use rpm queryformat.

Apply:

-    virtiofsd_version_cmd = rpm -q virtiofsd | cut -d- -f2
+    virtiofsd_version_cmd = rpm -q --qf '%{VERSION}-%{RELEASE}\n' virtiofsd
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
virtiofsd_version_cmd = rpm -q virtiofsd | cut -d- -f2
virtiofsd_version_cmd = rpm -q --qf '%{VERSION}-%{RELEASE}\n' virtiofsd
🤖 Prompt for AI Agents
In qemu/tests/cfg/virtio_fs_rlimit_nofile.cfg around line 7, the rpm query uses
`cut -d- -f2` which returns only VERSION and omits RELEASE, causing
under-reporting against a required VERSION-RELEASE range; update the command to
use rpm's queryformat to emit both version and release (e.g. use rpm -q --qf
'%{VERSION}-%{RELEASE}\n' virtiofsd) so the produced value matches the
required_virtiofsd_version format.

Win10.i386:
mem = 4096
fs_source_dir = /var/tmp/virtiofs_rlimit_nofile
force_create_fs_source = no
remove_fs_source = yes

pre_command = "mkdir -p ${fs_source_dir} && cd ${fs_source_dir}"
pre_command += " && for i in $(seq 1 1024); do touch file_$i.txt; done"
virtiofs_socket_path = '/var/tmp/virtiofs_rlimit_nofile.sock'
cmd_run_virtiofsd = '/usr/libexec/virtiofsd --socket-path ${virtiofs_socket_path} --shared-dir ${fs_source_dir}'

vm_mem_share = yes
vm_mem_backend = memory-backend-file
vm_mem_backend_path = /dev/shm
share_mem = yes
!s390, s390x:
mem_devs = mem1
backend_mem_mem1 = memory-backend-file
mem-path_mem1 = /dev/shm
size_mem1 = ${mem}M
use_mem_mem1 = no
guest_numa_nodes = shm0
numa_memdev_shm0 = mem-mem1
numa_nodeid_shm0 = 0
Windows:
# install winfsp tool
i386, i686:
install_winfsp_path = 'C:\Program Files'
devcon_dirname = 'x86'
x86_64:
install_winfsp_path = 'C:\Program Files (x86)'
devcon_dirname = 'amd64'
install_winfsp_cmd = 'msiexec /i WIN_UTILS:\winfsp.msi /qn'
check_installed_cmd = 'dir "%s" |findstr /I winfsp'
viofs_log_file = C:\viofs_log.txt
viofs_svc_name = VirtioFsSvc
viofs_exe_path = C:\virtiofs.exe
viofs_exe_copy_cmd = xcopy %s C:\ /Y
viofs_sc_create_cmd = 'sc create ${viofs_svc_name} binpath=${viofs_exe_path} start=auto'
viofs_sc_create_cmd += ' depend="WinFsp.Launcher/VirtioFsDrv" DisplayName="Virtio FS Service"'
viofs_sc_start_cmd = 'sc start ${viofs_svc_name}'
viofs_sc_query_cmd = 'sc query ${viofs_svc_name}'
viofs_sc_delete_cmd = 'sc delete ${viofs_svc_name}'
debug_log_operation = 'enable'
viofs_debug_enable_cmd = 'reg add HKLM\Software\VirtIO-FS /v DebugFlags /d 0xFFFFFFFF /t REG_DWORD'
viofs_log_enable_cmd = 'reg add HKLM\Software\VirtIO-FS /v DebugLogFile /d ${viofs_log_file} /t REG_SZ'
viofs_debug_delete_cmd = 'reg delete HKLM\Software\VirtIO-FS /v DebugFlags /f'
viofs_log_delete_cmd = 'reg delete HKLM\Software\VirtIO-FS /v DebugLogFile /f'
viofs_reg_query_cmd = 'reg query HKLM\Software\VirtIO-FS'
virtio_win_media_type = iso
cdroms += " virtio"
list_file_cmd = "dir %s"
variants:
- rlimit_nofile_512:
start_vm = no
rlimit_nofile = 512
cmd_run_virtiofsd += " --rlimit-nofile ${rlimit_nofile}"
expected_msg = "Maximum number of file descriptors too small: Limit is 512, must be at least 610"
- rlimit_nofile_610:
start_vm = no
rlimit_nofile = 610
cmd_run_virtiofsd += " --rlimit-nofile ${rlimit_nofile}"
expected_msg = "File descriptor count limit is very small, leaving only 0 file descriptors for the guest"
- rlimit_nofile_1000:
kill_vm = yes
start_vm = yes
filesystems = fs
fs_driver = virtio-fs
fs_source_type = mount
fs_target = 'myfs'
fs_driver_props = {"queue-size": 1024}
fs_dest = '/mnt/${fs_target}'
driver_name = viofs
rlimit_nofile = 1000
fs_binary_extra_options += " --rlimit-nofile ${rlimit_nofile}"
list_file_cmd = "ls %s"
qemu_check_content = "No more file descriptors available to the guest (0 available out of 390 initially), consider increasing the --rlimit-nofile value"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Regex vs literal: escape parentheses and make counts flexible.
The Python test uses re.search; unescaped parentheses won’t match the logged text and the exact numbers can vary. Use a regex with escaped parens and \d+.

-            qemu_check_content = "No more file descriptors available to the guest (0 available out of 390 initially), consider increasing the --rlimit-nofile value"
+            qemu_check_content = r"No more file descriptors available to the guest \(\d+ available out of \d+ initially\), consider increasing the --rlimit-nofile value"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
qemu_check_content = "No more file descriptors available to the guest (0 available out of 390 initially), consider increasing the --rlimit-nofile value"
qemu_check_content = r"No more file descriptors available to the guest \(\d+ available out of \d+ initially\), consider increasing the --rlimit-nofile value"
🤖 Prompt for AI Agents
In qemu/tests/cfg/virtio_fs_rlimit_nofile.cfg around line 84, the test's
expected string is treated as a regex via re.search so unescaped parentheses and
fixed numbers will fail; update the pattern to escape the literal parentheses
and replace the exact counts with \d+ (one-or-more-digit placeholders) so the
regex matches variable numeric values and the parentheses in the logged message.

- rlimit_nofile_2048:
kill_vm = yes
start_vm = yes
filesystems = fs
fs_driver = virtio-fs
fs_source_type = mount
fs_target = 'myfs'
fs_driver_props = {"queue-size": 1024}
fs_dest = '/mnt/${fs_target}'
driver_name = viofs
rlimit_nofile = 2048
fs_binary_extra_options += " --rlimit-nofile ${rlimit_nofile}"
list_file_cmd = "ls %s"
194 changes: 194 additions & 0 deletions qemu/tests/virtio_fs_rlimit_nofile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import os
import re

import aexpect
from avocado.utils import process
from virttest import error_context, utils_disk, utils_misc, utils_test

from provider import virtio_fs_utils


@error_context.context_aware
def run(test, params, env):
"""
Test virtio-fs rlimit-nofile.
Steps:
1. Create a shared directory for testing on the host.
2. Touch 1024 files in the shared directory.
3. Start the virtiofsd daemon with rlimit-nofile and check.

:param test: QEMU test object.
:param params: Dictionary with the test parameters.
:param env: Dictionary with test environment.
"""

def create_service(session):
if os_type == "windows":
error_context.context("Create virtiofs service in guest.", test.log.info)

driver_name = params["driver_name"]

session = utils_test.qemu.windrv_check_running_verifier(
session, vm, test, driver_name
)
viofs_svc_name = params["viofs_svc_name"]
virtio_fs_utils.create_viofs_service(
test, params, session, service=viofs_svc_name
)
return session

def delete_service():
if os_type == "windows":
error_context.context("Delete virtiofs service in guest.", test.log.info)
session = vm.wait_for_login()
virtio_fs_utils.delete_viofs_serivce(test, params, session)
session.close()

def start_service(session):
fs = params["filesystems"]
fs_params = params.object_params(fs)

fs_target = fs_params["fs_target"]
fs_dest = fs_params["fs_dest"]

if os_type == "linux":
utils_misc.make_dirs(fs_dest, session)
error_context.context(
"Mount virtiofs target %s to %s inside guest." % (fs_target, fs_dest),
test.log.info,
)
if not utils_disk.mount(fs_target, fs_dest, "virtiofs", session=session):
utils_misc.safe_rmdir(fs_dest, session=session)
test.fail("Failed to mount virtiofs %s." % fs_target)
else:
error_context.context("Start virtiofs service in guest.", test.log.info)
debug_log_operation = params.get("debug_log_operation")
if debug_log_operation:
session = virtio_fs_utils.operate_debug_log(
test, params, session, vm, debug_log_operation
)
virtio_fs_utils.start_viofs_service(test, params, session)

fs_dest = "%s:" % virtio_fs_utils.get_virtiofs_driver_letter(
test, fs_target, session
)

guest_mnts[fs_target] = fs_dest
return session

def stop_service(session):
error_context.context("Stop virtiofs service in guest.", test.log.info)

if os_type == "linux":
for fs_target, fs_dest in guest_mnts.items():
utils_disk.umount(fs_target, fs_dest, "virtiofs", session=session)
utils_misc.safe_rmdir(fs_dest, session=session)
else:
if guest_mnts:
virtio_fs_utils.stop_viofs_service(test, params, session)
session.close()

rlimit_nofile = params.get("rlimit_nofile")
cmd_run_virtiofsd = params["cmd_run_virtiofsd"]
guest_mnts = dict()
os_type = params["os_type"]

if rlimit_nofile == "512":
expected_msg = params["expected_msg"]
error_context.context(
"Starting virtiofsd with rlimit-nofile=%s" % rlimit_nofile, test.log.info
)
result = process.run(
cmd_run_virtiofsd,
shell=True,
ignore_status=True,
verbose=True,
)
# Prefer text-safe access for command output (stderr for failure path)
status = result.exit_status
err_out = getattr(result, "stderr_text", None)
if err_out is None:
raw_err = getattr(result, "stderr", b"")
err_out = (
raw_err.decode()
if isinstance(raw_err, (bytes, bytearray))
else str(raw_err)
)
if status == 0:
test.fail(
"virtiofsd unexpectedly started successfully with rlimit-nofile=512"
)
elif expected_msg not in err_out:
test.fail(
"virtiofsd failed but without expected message. Output: %s" % err_out
)
error_context.context(
"virtiofsd failed as expected with the required message present",
test.log.info,
)
elif rlimit_nofile == "610":
expected_msg = params["expected_msg"]
error_context.context(
"Starting virtiofsd with rlimit-nofile=%s" % rlimit_nofile, test.log.info
)
session = aexpect.ShellSession(
cmd_run_virtiofsd,
auto_close=False,
output_func=utils_misc.log_line,
output_params=("virtiofs_fs-virtiofs.log",),
prompt=r"^\[.*\][\#\$]\s*$",
)
try:
session.read_until_any_line_matches([expected_msg], timeout=10)
test.log.info(
"virtiofsd started successfully with the required message present"
)
except aexpect.ExpectTimeoutError as e:
test.fail("Timeout for virtiofsd start with rlimit-nofile=610: %s" % e)
finally:
session.close()
elif rlimit_nofile == "1000":
error_context.context(
"Starting virtiofsd with rlimit-nofile=%s" % rlimit_nofile, test.log.info
)
vm = env.get_vm(params.get("main_vm"))
vm.verify_alive()
session = vm.wait_for_login()
try:
session = create_service(session)
session = start_service(session)
for fs_dest in guest_mnts.values():
# ls the dir in guest
out = session.cmd_output(params["list_file_cmd"] % fs_dest).strip()
test.log.debug("The dir output in guest: %s", out)
# check the qemu log whether there is the proper information
log_file = os.path.join(
test.resultsdir, params.get("debug_log_file", "debug.log")
)
with open(log_file, "r") as f:
out = f.read().strip()
m = re.search(params["qemu_check_content"], out, re.M)
if m is None:
test.fail("The qemu log does not correct, check please.")
finally:
Comment on lines +165 to +173
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Regex bug: parentheses in pattern aren’t escaped; match will fail.
Either treat the config value as a literal or allow an explicit regex param.

-                    out = f.read().strip()
-                    m = re.search(params["qemu_check_content"], out, re.M)
+                    out = f.read().strip()
+                    pattern = params.get("qemu_check_content_regex")
+                    if not pattern:
+                        pattern = re.escape(params["qemu_check_content"])
+                    m = re.search(pattern, out, re.M)
                     if m is None:
-                        test.fail("The qemu log does not correct, check please.")
+                        test.fail("Expected QEMU log not found. Pattern: %s" % pattern)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
log_file = os.path.join(
test.resultsdir, params.get("debug_log_file", "debug.log")
)
with open(log_file, "r") as f:
out = f.read().strip()
m = re.search(params["qemu_check_content"], out, re.M)
if m is None:
test.fail("The qemu log does not correct, check please.")
finally:
log_file = os.path.join(
test.resultsdir, params.get("debug_log_file", "debug.log")
)
with open(log_file, "r") as f:
out = f.read().strip()
pattern = params.get("qemu_check_content_regex")
if not pattern:
pattern = re.escape(params["qemu_check_content"])
m = re.search(pattern, out, re.M)
if m is None:
test.fail("Expected QEMU log not found. Pattern: %s" % pattern)
finally:
🤖 Prompt for AI Agents
In qemu/tests/virtio_fs_rlimit_nofile.py around lines 165 to 173, the regex
pattern taken from params["qemu_check_content"] may contain unescaped
parentheses causing the search to fail; change the logic to treat the config
value as a literal by default (wrap it with re.escape before calling re.search)
and/or add an optional param (e.g. "qemu_check_is_regex" boolean) so when true
the value is used as a raw regex; update the call to re.search accordingly and
document the new param so existing configs keep working.

stop_service(session)
delete_service()
elif rlimit_nofile == "2048":
error_context.context(
"Starting virtiofsd with rlimit-nofile=%s" % rlimit_nofile, test.log.info
)
vm = env.get_vm(params.get("main_vm"))
vm.verify_alive()
session = vm.wait_for_login()
try:
session = create_service(session)
session = start_service(session)
for fs_dest in guest_mnts.values():
cmd = params["list_file_cmd"] % fs_dest
status, output = session.cmd_status_output(cmd)
output = output.strip()
if status != 0:
test.fail("list failed: %s" % output)
finally:
stop_service(session)
delete_service()