hw/9pfs: add max_xattr option

Previous patch introduced a limit of max. 1024 simultaneous xattr FIDs.

This patch introduces an option "max_attr" that allows to override this
limit, just for the case that some user might run into this limit for
some reason, even if unlikely; or for reducing the limit further down
(e.g. that default limit of 1024 would cap at max. 64 MiB host memory,
at least on Linux hosts where the limit per xattr is 64k).

This new "max_xattr" option can be specified with both -fsdev and
-virtfs command line options, with the "local" and the "synth" fs
drivers.

The previous limit of 1024 is preserved as the default value.

Link: https://lore.kernel.org/qemu-devel/b7631ac0d8dde0629bc7c4f2c4185d9f57b962b4.1781361555.git.qemu_oss@crudebyte.com
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
This commit is contained in:
Christian Schoenebeck
2026-06-13 16:55:49 +02:00
parent 693b296b17
commit e6116a81f0
7 changed files with 43 additions and 4 deletions

View File

@@ -101,6 +101,8 @@ typedef struct FsDriverEntry {
FsThrottle fst; FsThrottle fst;
mode_t fmode; mode_t fmode;
mode_t dmode; mode_t dmode;
/* temporary storage for parse_opts only */
uint32_t max_xattr;
} FsDriverEntry; } FsDriverEntry;
struct FsContext { struct FsContext {

View File

@@ -46,6 +46,9 @@ static QemuOptsList qemu_fsdev_opts = {
}, { }, {
.name = "dmode", .name = "dmode",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
}, {
.name = "max_xattr",
.type = QEMU_OPT_NUMBER,
}, },
THROTTLE_OPTS, THROTTLE_OPTS,
@@ -92,6 +95,9 @@ static QemuOptsList qemu_virtfs_opts = {
}, { }, {
.name = "dmode", .name = "dmode",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
}, {
.name = "max_xattr",
.type = QEMU_OPT_NUMBER,
}, },
{ /*End of list */ } { /*End of list */ }

View File

@@ -45,7 +45,7 @@ typedef struct FsDriverListEntry {
static QTAILQ_HEAD(, FsDriverListEntry) fsdriver_entries = static QTAILQ_HEAD(, FsDriverListEntry) fsdriver_entries =
QTAILQ_HEAD_INITIALIZER(fsdriver_entries); QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
#define COMMON_FS_DRIVER_OPTIONS "id", "fsdriver", "readonly" #define COMMON_FS_DRIVER_OPTIONS "id", "fsdriver", "readonly", "max_xattr"
static FsDriverTable FsDrivers[] = { static FsDriverTable FsDrivers[] = {
{ {

View File

@@ -1527,6 +1527,15 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
const char *path = qemu_opt_get(opts, "path"); const char *path = qemu_opt_get(opts, "path");
const char *multidevs = qemu_opt_get(opts, "multidevs"); const char *multidevs = qemu_opt_get(opts, "multidevs");
uint64_t val = qemu_opt_get_number(opts, "max_xattr",
V9FS_MAX_XATTR_DEFAULT);
if (val > UINT32_MAX) {
error_setg(errp, "max_xattr value '%s' too large",
qemu_opt_get(opts, "max_xattr"));
return -1;
}
fse->max_xattr = val;
if (!sec_model) { if (!sec_model) {
error_setg(errp, "security_model property not set"); error_setg(errp, "security_model property not set");
error_append_security_model_hint(errp); error_append_security_model_hint(errp);

View File

@@ -25,6 +25,8 @@
#include "qemu/rcu_queue.h" #include "qemu/rcu_queue.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "system/qtest.h" #include "system/qtest.h"
#include "qapi/error.h"
#include "qemu/option.h"
/* Root node for synth file system */ /* Root node for synth file system */
static V9fsSynthNode synth_root = { static V9fsSynthNode synth_root = {
@@ -629,12 +631,27 @@ static int synth_init(FsContext *ctx, Error **errp)
return 0; return 0;
} }
static int synth_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
{
uint64_t val = qemu_opt_get_number(opts, "max_xattr",
V9FS_MAX_XATTR_DEFAULT);
if (val > UINT32_MAX) {
error_setg(errp, "max_xattr value '%s' too large",
qemu_opt_get(opts, "max_xattr"));
return -1;
}
fse->max_xattr = val;
return 0;
}
static bool synth_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs) static bool synth_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs)
{ {
return false; return false;
} }
FileOperations synth_ops = { FileOperations synth_ops = {
.parse_opts = synth_parse_opts,
.init = synth_init, .init = synth_init,
.lstat = synth_lstat, .lstat = synth_lstat,
.readlink = synth_readlink, .readlink = synth_readlink,

View File

@@ -4483,8 +4483,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
s->reclaiming = false; s->reclaiming = false;
/* init xattr FID limit */ /* init xattr FID limit from fsdev config */
s->ctx.xattr_fid_limit = V9FS_MAX_XATTR_DEFAULT; s->ctx.xattr_fid_limit = fse->max_xattr;
s->ctx.xattr_fid_count = 0; s->ctx.xattr_fid_count = 0;
rc = 0; rc = 0;

View File

@@ -3260,7 +3260,7 @@ void qemu_init(int argc, char **argv)
QemuOpts *fsdev; QemuOpts *fsdev;
QemuOpts *device; QemuOpts *device;
const char *writeout, *sock_fd, *socket, *path, *security_model, const char *writeout, *sock_fd, *socket, *path, *security_model,
*multidevs; *multidevs, *max_xattr_str;
olist = qemu_find_opts("virtfs"); olist = qemu_find_opts("virtfs");
if (!olist) { if (!olist) {
@@ -3324,6 +3324,11 @@ void qemu_init(int argc, char **argv)
if (multidevs) { if (multidevs) {
qemu_opt_set(fsdev, "multidevs", multidevs, &error_abort); qemu_opt_set(fsdev, "multidevs", multidevs, &error_abort);
} }
max_xattr_str = qemu_opt_get(opts, "max_xattr");
if (max_xattr_str) {
qemu_opt_set(fsdev, "max_xattr", max_xattr_str,
&error_abort);
}
device = qemu_opts_create(qemu_find_opts("device"), NULL, 0, device = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
&error_abort); &error_abort);
qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort); qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort);