35
#define tclunk(...) v9fs_tclunk((TClunkOpt) __VA_ARGS__)
36
#define txattrcreate(...) v9fs_txattrcreate((TXattrCreateOpt) __VA_ARGS__)
37
38
+/*
39
+ * xattr size to be used for xattr tests
40
+ *
41
+ * 64k is the max. xattr size supported by the Linux kernel, However btrfs
42
+ * for instance supports only 16219 bytes. So let's be conservative and
43
+ * just use 8k for the xattr tests.
44
+ */
45
+#define TEST_XATTR_SIZE (8 * 1024)
46
+
47
static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
48
{
49
QVirtio9P *v9p = obj;
116
return false;
117
}
118
119
+/*
120
+ * Returns the current internal xattr FID count (works with synth driver only).
121
+ */
122
+static size_t get_xattr_count(QVirtio9P *v9p)
123
+{
124
+ uint16_t nwqid;
125
+ v9fs_qid *wqid;
126
+ const char *xattr_count_path[] = { "stat", "xattr_count" };
127
+ size_t xattr_count;
128
+ uint32_t bytes_read;
129
+
130
+ /* walk to /stat/xattr_count file */
131
+ uint32_t fid = twalk({
132
+ .client = v9p, .fid = 0,
133
+ .nwname = 2, .wnames = (char **)xattr_count_path,
134
+ .rwalk = { .nwqid = &nwqid, .wqid = &wqid }
135
+ }).newfid;
136
+
137
+ /* open for read */
138
+ tlopen({
139
+ .client = v9p, .fid = fid, .flags = O_RDONLY,
140
+ .rlopen = { .qid = NULL, .iounit = NULL }
141
+ });
142
+
143
+ /* read the internal xattr FID count */
144
+ tread({
145
+ .client = v9p, .fid = fid, .offset = 0, .count = sizeof(xattr_count),
146
+ .rread = { .count = &bytes_read, .data = &xattr_count }
147
+ });
148
+
149
+ /* cleanup */
150
+ tclunk({ .client = v9p, .fid = fid });
151
+
152
+ return xattr_count;
153
+}
154
+
155
/* basic readdir test where reply fits into a single response message */
156
static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
157
{
293
g_free(wnames[0]);
294
}
295
296
+/*
297
+ * Test 9p server's xattr FID count limit enforcement.
298
+ *
299
+ * Shared test code for both 'synth' and 'local' driver to verify correct
300
+ * behaviour of 9p server enforcing preconfigured xattr FID count limit
301
+ * correctly.
302
+ *
303
+ * @v9p: 9pfs client
304
+ *
305
+ * @max_xattr: max. allowed xattr FIDs, or -1 for infinite
306
+ *
307
+ * @check_counter: whether to verify 9p server internal xattr FID counter
308
+ * (only works with 'synth' fs driver)
309
+ */
310
+static void do_xattr_limit(QVirtio9P *v9p, int max_xattr, bool check_counter)
311
+{
312
+ size_t count;
313
+ int i;
314
+ int limit = (max_xattr != -1) ? max_xattr : V9FS_MAX_XATTR_DEFAULT + 100;
315
+ g_autofree uint32_t *fids = g_new0(uint32_t, limit);
316
+ uint32_t err_fid = 0;
317
+ const char *file_path[] = { QTEST_V9FS_SYNTH_WRITE_FILE };
318
+ g_autofree uint8_t *xattr_data = g_malloc(TEST_XATTR_SIZE);
319
+
320
+ if (!g_test_slow()) {
321
+ g_test_skip("This is a slow test, run with -m slow");
322
+ return;
323
+ }
324
+
325
+ /* prepare xattr data with 'X' characters */
326
+ memset(xattr_data, 'X', TEST_XATTR_SIZE);
327
+
328
+ tattach({ .client = v9p });
329
+
330
+ /* create max. amount of permitted xattrs */
331
+ for (i = 0; i < limit; i++) {
332
+ /* walk to create a new fid */
333
+ fids[i] = twalk({
334
+ .client = v9p, .fid = 0,
335
+ .nwname = 1, .wnames = (char **) file_path
336
+ }).newfid;
337
+
338
+ /* create new xattr fid */
339
+ txattrcreate({
340
+ .client = v9p, .fid = fids[i], .name = "user.test",
341
+ .size = TEST_XATTR_SIZE, .flags = 0
342
+ });
343
+
344
+ /* transfer the xattr data */
345
+ twrite({
346
+ .client = v9p, .fid = fids[i], .offset = 0,
347
+ .count = TEST_XATTR_SIZE, .data = xattr_data
348
+ });
349
+
350
+ /* verify server internal xattr counter */
351
+ if (check_counter) {
352
+ count = get_xattr_count(v9p);
353
+ g_assert_cmpuint(count, ==, (i + 1));
354
+ }
355
+
356
+ /* avoid virtio descriptor exhaustion */
357
+ qvirtqueue_reset_pool(v9p->vq);
358
+ }
359
+
360
+ /* if xattrs are limited, the next xattr should fail */
361
+ if (max_xattr != -1) {
362
+ /* walk to create another fid */
363
+ err_fid = twalk({
364
+ .client = v9p, .fid = 0,
365
+ .nwname = 1, .wnames = (char **) file_path
366
+ }).newfid;
367
+
368
+ /* try to create one more xattr fid - should fail */
369
+ txattrcreate({
370
+ .client = v9p, .fid = err_fid, .name = "user.test_exceed",
371
+ .size = TEST_XATTR_SIZE, .flags = 0,
372
+ .expectErr = ENOSPC
373
+ });
374
+
375
+ /* verify internal xattr counter hasn't changed */
376
+ if (check_counter) {
377
+ count = get_xattr_count(v9p);
378
+ g_assert_cmpuint(count, ==, limit);
379
+ }
380
+ }
381
+
382
+ /* clunk all fids (should decrement xattr counter) */
383
+ for (i = 0; i < limit; i++) {
384
+ tclunk({ .client = v9p, .fid = fids[i] });
385
+ qvirtqueue_reset_pool(v9p->vq);
386
+ }
387
+ if (err_fid) {
388
+ tclunk({ .client = v9p, .fid = err_fid });
389
+ }
390
+
391
+ /* verify internal xattr counter is zero */
392
+ if (check_counter) {
393
+ count = get_xattr_count(v9p);
394
+ g_assert_cmpuint(count, ==, 0);
395
+ }
396
+}
397
+
398
static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc)
399
{
400
QVirtio9P *v9p = obj;
655
do_readdir_split(obj, 512);
656
}
657
658
+static void fs_synth_xattr_limit_default(void *obj, void *data,
659
+ QGuestAllocator *t_alloc)
660
+{
661
+ v9fs_set_allocator(t_alloc);
662
+ do_xattr_limit(obj, V9FS_MAX_XATTR_DEFAULT, true);
663
+}
664
+
665
+static void fs_synth_xattr_limit_custom(void *obj, void *data,
666
+ QGuestAllocator *t_alloc)
667
+{
668
+ v9fs_set_allocator(t_alloc);
669
+ do_xattr_limit(obj, 100, true);
670
+}
671
+
672
+static void fs_synth_xattr_limit_unlimited(void *obj, void *data,
673
+ QGuestAllocator *t_alloc)
674
+{
675
+ v9fs_set_allocator(t_alloc);
676
+ do_xattr_limit(obj, -1, true);
677
+}
678
+
679
680
/* tests using the 9pfs 'local' fs driver */
681
990
g_string_free(path, TRUE);
991
}
992
993
+static void *synth_max_xattr_custom_opt(GString *cmd_line, void *arg)
994
+{
995
+ virtio_9p_add_synth_driver_args(cmd_line, "max_xattr=100");
996
+ return arg;
997
+}
998
+
999
+static void *synth_max_xattr_unlimited_opt(GString *cmd_line, void *arg)
1000
+{
1001
+ virtio_9p_add_synth_driver_args(cmd_line, "max_xattr=0");
1002
+ return arg;
1003
+}
1004
+
1005
static void cleanup_9p_local_driver(void *data)
1006
{
1007
/* remove previously created test dir when test is completed */
1052
fs_readdir_split_256, &opts);
1053
qos_add_test("synth/readdir/split_128", "virtio-9p",
1054
fs_readdir_split_128, &opts);
875
-
1055
+ qos_add_test("synth/xattr_limit/default", "virtio-9p",
1056
+ fs_synth_xattr_limit_default, &opts);
1057
+ opts.before = synth_max_xattr_custom_opt;
1058
+ qos_add_test("synth/xattr_limit/custom", "virtio-9p",
1059
+ fs_synth_xattr_limit_custom, &opts);
1060
+ opts.before = synth_max_xattr_unlimited_opt;
1061
+ qos_add_test("synth/xattr_limit/unlimited", "virtio-9p",
1062
+ fs_synth_xattr_limit_unlimited, &opts);
1063
1064
/* 9pfs test cases using the 'local' filesystem driver */
1065
opts.before = assign_9p_local_driver;