Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_input_check.c
48529 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* CDDL HEADER START
4
*
5
* This file and its contents are supplied under the terms of the
6
* Common Development and Distribution License ("CDDL"), version 1.0.
7
* You may only use this file in accordance with the terms of version
8
* 1.0 of the CDDL.
9
*
10
* A full copy of the text of the CDDL should have accompanied this
11
* source. A copy of the CDDL is also available via the Internet at
12
* http://www.illumos.org/license/CDDL.
13
*
14
* CDDL HEADER END
15
*/
16
17
/*
18
* Copyright (c) 2018 by Delphix. All rights reserved.
19
*/
20
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <libzfs_core.h>
25
#include <libzutil.h>
26
27
#include <sys/nvpair.h>
28
#include <sys/vdev_impl.h>
29
#include <sys/zfs_ioctl.h>
30
#include <sys/zfs_bootenv.h>
31
#include <sys/fs/zfs.h>
32
33
/*
34
* Test the nvpair inputs for the non-legacy zfs ioctl commands.
35
*/
36
37
static boolean_t unexpected_failures;
38
static int zfs_fd;
39
static const char *active_test;
40
41
/*
42
* Tracks which zfs_ioc_t commands were tested
43
*/
44
static boolean_t ioc_tested[ZFS_IOC_LAST - ZFS_IOC_FIRST];
45
46
/*
47
* Legacy ioctls that are skipped (for now)
48
*/
49
static const zfs_ioc_t ioc_skip[] = {
50
ZFS_IOC_POOL_CREATE,
51
ZFS_IOC_POOL_DESTROY,
52
ZFS_IOC_POOL_IMPORT,
53
ZFS_IOC_POOL_EXPORT,
54
ZFS_IOC_POOL_CONFIGS,
55
ZFS_IOC_POOL_STATS,
56
ZFS_IOC_POOL_TRYIMPORT,
57
ZFS_IOC_POOL_SCAN,
58
ZFS_IOC_POOL_FREEZE,
59
ZFS_IOC_POOL_UPGRADE,
60
ZFS_IOC_POOL_GET_HISTORY,
61
62
ZFS_IOC_VDEV_ADD,
63
ZFS_IOC_VDEV_REMOVE,
64
ZFS_IOC_VDEV_SET_STATE,
65
ZFS_IOC_VDEV_ATTACH,
66
ZFS_IOC_VDEV_DETACH,
67
ZFS_IOC_VDEV_SETPATH,
68
ZFS_IOC_VDEV_SETFRU,
69
70
ZFS_IOC_OBJSET_STATS,
71
ZFS_IOC_OBJSET_ZPLPROPS,
72
ZFS_IOC_DATASET_LIST_NEXT,
73
ZFS_IOC_SNAPSHOT_LIST_NEXT,
74
ZFS_IOC_SET_PROP,
75
ZFS_IOC_DESTROY,
76
ZFS_IOC_RENAME,
77
ZFS_IOC_RECV,
78
ZFS_IOC_SEND,
79
ZFS_IOC_INJECT_FAULT,
80
ZFS_IOC_CLEAR_FAULT,
81
ZFS_IOC_INJECT_LIST_NEXT,
82
ZFS_IOC_ERROR_LOG,
83
ZFS_IOC_CLEAR,
84
ZFS_IOC_PROMOTE,
85
ZFS_IOC_DSOBJ_TO_DSNAME,
86
ZFS_IOC_OBJ_TO_PATH,
87
ZFS_IOC_POOL_SET_PROPS,
88
ZFS_IOC_POOL_GET_PROPS,
89
ZFS_IOC_SET_FSACL,
90
ZFS_IOC_GET_FSACL,
91
ZFS_IOC_SHARE,
92
ZFS_IOC_INHERIT_PROP,
93
ZFS_IOC_SMB_ACL,
94
ZFS_IOC_USERSPACE_ONE,
95
ZFS_IOC_USERSPACE_MANY,
96
ZFS_IOC_USERSPACE_UPGRADE,
97
ZFS_IOC_OBJSET_RECVD_PROPS,
98
ZFS_IOC_VDEV_SPLIT,
99
ZFS_IOC_NEXT_OBJ,
100
ZFS_IOC_DIFF,
101
ZFS_IOC_TMP_SNAPSHOT,
102
ZFS_IOC_OBJ_TO_STATS,
103
ZFS_IOC_SPACE_WRITTEN,
104
ZFS_IOC_POOL_REGUID,
105
ZFS_IOC_SEND_PROGRESS,
106
ZFS_IOC_EVENTS_NEXT,
107
ZFS_IOC_EVENTS_CLEAR,
108
ZFS_IOC_EVENTS_SEEK,
109
ZFS_IOC_NEXTBOOT,
110
ZFS_IOC_JAIL,
111
ZFS_IOC_UNJAIL,
112
};
113
114
115
#define IOC_INPUT_TEST(ioc, name, req, opt, err) \
116
IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_FALSE)
117
118
#define IOC_INPUT_TEST_WILD(ioc, name, req, opt, err) \
119
IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_TRUE)
120
121
#define IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, wild) \
122
do { \
123
active_test = __func__ + 5; \
124
ioc_tested[ioc - ZFS_IOC_FIRST] = B_TRUE; \
125
lzc_ioctl_test(ioc, name, req, opt, err, wild); \
126
} while (0)
127
128
/*
129
* run a zfs ioctl command, verify expected results and log failures
130
*/
131
static void
132
lzc_ioctl_run(zfs_ioc_t ioc, const char *name, nvlist_t *innvl, int expected)
133
{
134
zfs_cmd_t zc = {"\0"};
135
char *packed = NULL;
136
const char *variant;
137
size_t size = 0;
138
int error = 0;
139
140
switch (expected) {
141
case ZFS_ERR_IOC_ARG_UNAVAIL:
142
variant = "unsupported input";
143
break;
144
case ZFS_ERR_IOC_ARG_REQUIRED:
145
variant = "missing input";
146
break;
147
case ZFS_ERR_IOC_ARG_BADTYPE:
148
variant = "invalid input type";
149
break;
150
default:
151
variant = "valid input";
152
break;
153
}
154
155
packed = fnvlist_pack(innvl, &size);
156
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
157
zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
158
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
159
zc.zc_nvlist_src_size = size;
160
zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
161
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size);
162
163
if (lzc_ioctl_fd(zfs_fd, ioc, &zc) != 0)
164
error = errno;
165
166
if (error != expected) {
167
unexpected_failures = B_TRUE;
168
(void) fprintf(stderr, "%s: Unexpected result with %s, "
169
"error %d (expecting %d)\n",
170
active_test, variant, error, expected);
171
}
172
173
fnvlist_pack_free(packed, size);
174
free((void *)(uintptr_t)zc.zc_nvlist_dst);
175
}
176
177
/*
178
* Test each ioc for the following ioctl input errors:
179
* ZFS_ERR_IOC_ARG_UNAVAIL an input argument is not supported by kernel
180
* ZFS_ERR_IOC_ARG_REQUIRED a required input argument is missing
181
* ZFS_ERR_IOC_ARG_BADTYPE an input argument has an invalid type
182
*/
183
static int
184
lzc_ioctl_test(zfs_ioc_t ioc, const char *name, nvlist_t *required,
185
nvlist_t *optional, int expected_error, boolean_t wildcard)
186
{
187
nvlist_t *input = fnvlist_alloc();
188
nvlist_t *future = fnvlist_alloc();
189
int error = 0;
190
191
if (required != NULL) {
192
for (nvpair_t *pair = nvlist_next_nvpair(required, NULL);
193
pair != NULL; pair = nvlist_next_nvpair(required, pair)) {
194
fnvlist_add_nvpair(input, pair);
195
}
196
}
197
if (optional != NULL) {
198
for (nvpair_t *pair = nvlist_next_nvpair(optional, NULL);
199
pair != NULL; pair = nvlist_next_nvpair(optional, pair)) {
200
fnvlist_add_nvpair(input, pair);
201
}
202
}
203
204
/*
205
* Generic input run with 'optional' nvlist pair
206
*/
207
if (!wildcard)
208
fnvlist_add_nvlist(input, "optional", future);
209
lzc_ioctl_run(ioc, name, input, expected_error);
210
if (!wildcard)
211
fnvlist_remove(input, "optional");
212
213
/*
214
* Bogus input value
215
*/
216
if (!wildcard) {
217
fnvlist_add_string(input, "bogus_input", "bogus");
218
lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_UNAVAIL);
219
fnvlist_remove(input, "bogus_input");
220
}
221
222
/*
223
* Missing required inputs
224
*/
225
if (required != NULL) {
226
nvlist_t *empty = fnvlist_alloc();
227
lzc_ioctl_run(ioc, name, empty, ZFS_ERR_IOC_ARG_REQUIRED);
228
nvlist_free(empty);
229
}
230
231
/*
232
* Wrong nvpair type
233
*/
234
if (required != NULL || optional != NULL) {
235
/*
236
* switch the type of one of the input pairs
237
*/
238
for (nvpair_t *pair = nvlist_next_nvpair(input, NULL);
239
pair != NULL; pair = nvlist_next_nvpair(input, pair)) {
240
char pname[MAXNAMELEN];
241
data_type_t ptype;
242
243
strlcpy(pname, nvpair_name(pair), sizeof (pname));
244
pname[sizeof (pname) - 1] = '\0';
245
ptype = nvpair_type(pair);
246
fnvlist_remove_nvpair(input, pair);
247
248
switch (ptype) {
249
case DATA_TYPE_STRING:
250
fnvlist_add_uint64(input, pname, 42);
251
break;
252
default:
253
fnvlist_add_string(input, pname, "bogus");
254
break;
255
}
256
}
257
lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_BADTYPE);
258
}
259
260
nvlist_free(future);
261
nvlist_free(input);
262
263
return (error);
264
}
265
266
static void
267
test_pool_sync(const char *pool)
268
{
269
nvlist_t *required = fnvlist_alloc();
270
271
fnvlist_add_boolean_value(required, "force", B_TRUE);
272
273
IOC_INPUT_TEST(ZFS_IOC_POOL_SYNC, pool, required, NULL, 0);
274
275
nvlist_free(required);
276
}
277
278
static void
279
test_pool_reopen(const char *pool)
280
{
281
nvlist_t *optional = fnvlist_alloc();
282
283
fnvlist_add_boolean_value(optional, "scrub_restart", B_FALSE);
284
285
IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, NULL, optional, 0);
286
287
nvlist_free(optional);
288
}
289
290
static void
291
test_pool_checkpoint(const char *pool)
292
{
293
IOC_INPUT_TEST(ZFS_IOC_POOL_CHECKPOINT, pool, NULL, NULL, 0);
294
}
295
296
static void
297
test_pool_discard_checkpoint(const char *pool)
298
{
299
int err = lzc_pool_checkpoint(pool);
300
if (err == 0 || err == ZFS_ERR_CHECKPOINT_EXISTS)
301
IOC_INPUT_TEST(ZFS_IOC_POOL_DISCARD_CHECKPOINT, pool, NULL,
302
NULL, 0);
303
}
304
305
static void
306
test_log_history(const char *pool)
307
{
308
nvlist_t *required = fnvlist_alloc();
309
310
fnvlist_add_string(required, "message", "input check");
311
312
IOC_INPUT_TEST(ZFS_IOC_LOG_HISTORY, pool, required, NULL, 0);
313
314
nvlist_free(required);
315
}
316
317
static void
318
test_create(const char *pool)
319
{
320
char dataset[MAXNAMELEN + 32];
321
322
(void) snprintf(dataset, sizeof (dataset), "%s/create-fs", pool);
323
324
nvlist_t *required = fnvlist_alloc();
325
nvlist_t *optional = fnvlist_alloc();
326
nvlist_t *props = fnvlist_alloc();
327
328
fnvlist_add_int32(required, "type", DMU_OST_ZFS);
329
fnvlist_add_uint64(props, "recordsize", 8192);
330
fnvlist_add_nvlist(optional, "props", props);
331
332
IOC_INPUT_TEST(ZFS_IOC_CREATE, dataset, required, optional, 0);
333
334
nvlist_free(required);
335
nvlist_free(optional);
336
}
337
338
static void
339
test_snapshot(const char *pool, const char *snapshot)
340
{
341
nvlist_t *required = fnvlist_alloc();
342
nvlist_t *optional = fnvlist_alloc();
343
nvlist_t *snaps = fnvlist_alloc();
344
nvlist_t *props = fnvlist_alloc();
345
346
fnvlist_add_boolean(snaps, snapshot);
347
fnvlist_add_nvlist(required, "snaps", snaps);
348
349
fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");
350
fnvlist_add_nvlist(optional, "props", props);
351
352
IOC_INPUT_TEST(ZFS_IOC_SNAPSHOT, pool, required, optional, 0);
353
354
nvlist_free(props);
355
nvlist_free(snaps);
356
nvlist_free(optional);
357
nvlist_free(required);
358
}
359
360
static void
361
test_space_snaps(const char *snapshot)
362
{
363
nvlist_t *required = fnvlist_alloc();
364
fnvlist_add_string(required, "firstsnap", snapshot);
365
366
IOC_INPUT_TEST(ZFS_IOC_SPACE_SNAPS, snapshot, required, NULL, 0);
367
368
nvlist_free(required);
369
}
370
371
static void
372
test_destroy_snaps(const char *pool, const char *snapshot)
373
{
374
nvlist_t *required = fnvlist_alloc();
375
nvlist_t *snaps = fnvlist_alloc();
376
377
fnvlist_add_boolean(snaps, snapshot);
378
fnvlist_add_nvlist(required, "snaps", snaps);
379
380
IOC_INPUT_TEST(ZFS_IOC_DESTROY_SNAPS, pool, required, NULL, 0);
381
382
nvlist_free(snaps);
383
nvlist_free(required);
384
}
385
386
387
static void
388
test_bookmark(const char *pool, const char *snapshot, const char *bookmark)
389
{
390
nvlist_t *required = fnvlist_alloc();
391
392
fnvlist_add_string(required, bookmark, snapshot);
393
394
IOC_INPUT_TEST_WILD(ZFS_IOC_BOOKMARK, pool, required, NULL, 0);
395
396
nvlist_free(required);
397
}
398
399
static void
400
test_get_bookmarks(const char *dataset)
401
{
402
nvlist_t *optional = fnvlist_alloc();
403
404
fnvlist_add_boolean(optional, "guid");
405
fnvlist_add_boolean(optional, "createtxg");
406
fnvlist_add_boolean(optional, "creation");
407
408
IOC_INPUT_TEST_WILD(ZFS_IOC_GET_BOOKMARKS, dataset, NULL, optional, 0);
409
410
nvlist_free(optional);
411
}
412
413
static void
414
test_destroy_bookmarks(const char *pool, const char *bookmark)
415
{
416
nvlist_t *required = fnvlist_alloc();
417
418
fnvlist_add_boolean(required, bookmark);
419
420
IOC_INPUT_TEST_WILD(ZFS_IOC_DESTROY_BOOKMARKS, pool, required, NULL, 0);
421
422
nvlist_free(required);
423
}
424
425
static void
426
test_clone(const char *snapshot, const char *clone)
427
{
428
nvlist_t *required = fnvlist_alloc();
429
nvlist_t *optional = fnvlist_alloc();
430
nvlist_t *props = fnvlist_alloc();
431
432
fnvlist_add_string(required, "origin", snapshot);
433
434
IOC_INPUT_TEST(ZFS_IOC_CLONE, clone, required, NULL, 0);
435
436
nvlist_free(props);
437
nvlist_free(optional);
438
nvlist_free(required);
439
}
440
441
static void
442
test_rollback(const char *dataset, const char *snapshot)
443
{
444
nvlist_t *optional = fnvlist_alloc();
445
446
fnvlist_add_string(optional, "target", snapshot);
447
448
IOC_INPUT_TEST(ZFS_IOC_ROLLBACK, dataset, NULL, optional, B_FALSE);
449
450
nvlist_free(optional);
451
}
452
453
static void
454
test_hold(const char *pool, const char *snapshot)
455
{
456
nvlist_t *required = fnvlist_alloc();
457
nvlist_t *optional = fnvlist_alloc();
458
nvlist_t *holds = fnvlist_alloc();
459
460
fnvlist_add_string(holds, snapshot, "libzfs_check_hold");
461
fnvlist_add_nvlist(required, "holds", holds);
462
fnvlist_add_int32(optional, "cleanup_fd", zfs_fd);
463
464
IOC_INPUT_TEST(ZFS_IOC_HOLD, pool, required, optional, 0);
465
466
nvlist_free(holds);
467
nvlist_free(optional);
468
nvlist_free(required);
469
}
470
471
static void
472
test_get_holds(const char *snapshot)
473
{
474
IOC_INPUT_TEST(ZFS_IOC_GET_HOLDS, snapshot, NULL, NULL, 0);
475
}
476
477
static void
478
test_release(const char *pool, const char *snapshot)
479
{
480
nvlist_t *required = fnvlist_alloc();
481
nvlist_t *release = fnvlist_alloc();
482
483
fnvlist_add_boolean(release, "libzfs_check_hold");
484
fnvlist_add_nvlist(required, snapshot, release);
485
486
IOC_INPUT_TEST_WILD(ZFS_IOC_RELEASE, pool, required, NULL, 0);
487
488
nvlist_free(release);
489
nvlist_free(required);
490
}
491
492
493
static void
494
test_send_new(const char *snapshot, int fd)
495
{
496
nvlist_t *required = fnvlist_alloc();
497
nvlist_t *optional = fnvlist_alloc();
498
499
fnvlist_add_int32(required, "fd", fd);
500
501
fnvlist_add_boolean(optional, "largeblockok");
502
fnvlist_add_boolean(optional, "embedok");
503
fnvlist_add_boolean(optional, "compressok");
504
fnvlist_add_boolean(optional, "rawok");
505
506
/*
507
* TODO - Resumable send is harder to set up. So we currently
508
* ignore testing for that variant.
509
*/
510
#if 0
511
fnvlist_add_string(optional, "fromsnap", from);
512
fnvlist_add_uint64(optional, "resume_object", resumeobj);
513
fnvlist_add_uint64(optional, "resume_offset", offset);
514
fnvlist_add_boolean(optional, "savedok");
515
#endif
516
IOC_INPUT_TEST(ZFS_IOC_SEND_NEW, snapshot, required, optional, 0);
517
518
nvlist_free(optional);
519
nvlist_free(required);
520
}
521
522
static void
523
test_recv_new(const char *dataset, int fd)
524
{
525
dmu_replay_record_t drr;
526
nvlist_t *required = fnvlist_alloc();
527
nvlist_t *optional = fnvlist_alloc();
528
nvlist_t *props = fnvlist_alloc();
529
char snapshot[MAXNAMELEN + 32];
530
ssize_t count;
531
532
memset(&drr, 0, sizeof (dmu_replay_record_t));
533
534
int cleanup_fd = open(ZFS_DEV, O_RDWR);
535
if (cleanup_fd == -1) {
536
(void) fprintf(stderr, "open(%s) failed: %s\n", ZFS_DEV,
537
strerror(errno));
538
exit(EXIT_FAILURE);
539
}
540
(void) snprintf(snapshot, sizeof (snapshot), "%s@replicant", dataset);
541
542
count = pread(fd, &drr, sizeof (drr), 0);
543
if (count != sizeof (drr)) {
544
(void) fprintf(stderr, "could not read stream: %s\n",
545
strerror(errno));
546
}
547
548
fnvlist_add_string(required, "snapname", snapshot);
549
fnvlist_add_byte_array(required, "begin_record", (uchar_t *)&drr,
550
sizeof (drr));
551
fnvlist_add_int32(required, "input_fd", fd);
552
553
fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");
554
fnvlist_add_nvlist(optional, "localprops", props);
555
fnvlist_add_boolean(optional, "force");
556
fnvlist_add_boolean(optional, "heal");
557
fnvlist_add_int32(optional, "cleanup_fd", cleanup_fd);
558
559
/*
560
* TODO - Resumable receive is harder to set up. So we currently
561
* ignore testing for one.
562
*/
563
#if 0
564
fnvlist_add_nvlist(optional, "props", recvdprops);
565
fnvlist_add_string(optional, "origin", origin);
566
fnvlist_add_boolean(optional, "resumable");
567
fnvlist_add_uint64(optional, "action_handle", *action_handle);
568
#endif
569
IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional,
570
ENOTSUP);
571
572
nvlist_free(props);
573
nvlist_free(optional);
574
nvlist_free(required);
575
576
(void) close(cleanup_fd);
577
}
578
579
static void
580
test_send_space(const char *snapshot1, const char *snapshot2)
581
{
582
nvlist_t *optional = fnvlist_alloc();
583
584
fnvlist_add_string(optional, "from", snapshot1);
585
fnvlist_add_boolean(optional, "largeblockok");
586
fnvlist_add_boolean(optional, "embedok");
587
fnvlist_add_boolean(optional, "compressok");
588
fnvlist_add_boolean(optional, "rawok");
589
590
IOC_INPUT_TEST(ZFS_IOC_SEND_SPACE, snapshot2, NULL, optional, 0);
591
592
nvlist_free(optional);
593
}
594
595
static void
596
test_remap(const char *dataset)
597
{
598
IOC_INPUT_TEST(ZFS_IOC_REMAP, dataset, NULL, NULL, 0);
599
}
600
601
static void
602
test_channel_program(const char *pool)
603
{
604
const char *program =
605
"arg = ...\n"
606
"argv = arg[\"argv\"]\n"
607
"return argv[1]";
608
const char *const argv[1] = { "Hello World!" };
609
nvlist_t *required = fnvlist_alloc();
610
nvlist_t *optional = fnvlist_alloc();
611
nvlist_t *args = fnvlist_alloc();
612
613
fnvlist_add_string(required, "program", program);
614
fnvlist_add_string_array(args, "argv", argv, 1);
615
fnvlist_add_nvlist(required, "arg", args);
616
617
fnvlist_add_boolean_value(optional, "sync", B_TRUE);
618
fnvlist_add_uint64(optional, "instrlimit", 1000 * 1000);
619
fnvlist_add_uint64(optional, "memlimit", 8192 * 1024);
620
621
IOC_INPUT_TEST(ZFS_IOC_CHANNEL_PROGRAM, pool, required, optional, 0);
622
623
nvlist_free(args);
624
nvlist_free(optional);
625
nvlist_free(required);
626
}
627
628
#define WRAPPING_KEY_LEN 32
629
630
static void
631
test_load_key(const char *dataset)
632
{
633
nvlist_t *required = fnvlist_alloc();
634
nvlist_t *optional = fnvlist_alloc();
635
nvlist_t *hidden = fnvlist_alloc();
636
uint8_t keydata[WRAPPING_KEY_LEN] = {0};
637
638
fnvlist_add_uint8_array(hidden, "wkeydata", keydata, sizeof (keydata));
639
fnvlist_add_nvlist(required, "hidden_args", hidden);
640
fnvlist_add_boolean(optional, "noop");
641
642
IOC_INPUT_TEST(ZFS_IOC_LOAD_KEY, dataset, required, optional, EINVAL);
643
nvlist_free(hidden);
644
nvlist_free(optional);
645
nvlist_free(required);
646
}
647
648
static void
649
test_change_key(const char *dataset)
650
{
651
IOC_INPUT_TEST(ZFS_IOC_CHANGE_KEY, dataset, NULL, NULL, EINVAL);
652
}
653
654
static void
655
test_unload_key(const char *dataset)
656
{
657
IOC_INPUT_TEST(ZFS_IOC_UNLOAD_KEY, dataset, NULL, NULL, EACCES);
658
}
659
660
static void
661
test_vdev_initialize(const char *pool)
662
{
663
nvlist_t *required = fnvlist_alloc();
664
nvlist_t *vdev_guids = fnvlist_alloc();
665
666
fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);
667
fnvlist_add_uint64(required, ZPOOL_INITIALIZE_COMMAND,
668
POOL_INITIALIZE_START);
669
fnvlist_add_nvlist(required, ZPOOL_INITIALIZE_VDEVS, vdev_guids);
670
671
IOC_INPUT_TEST(ZFS_IOC_POOL_INITIALIZE, pool, required, NULL, EINVAL);
672
nvlist_free(vdev_guids);
673
nvlist_free(required);
674
}
675
676
static void
677
test_vdev_trim(const char *pool)
678
{
679
nvlist_t *required = fnvlist_alloc();
680
nvlist_t *optional = fnvlist_alloc();
681
nvlist_t *vdev_guids = fnvlist_alloc();
682
683
fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);
684
fnvlist_add_uint64(required, ZPOOL_TRIM_COMMAND, POOL_TRIM_START);
685
fnvlist_add_nvlist(required, ZPOOL_TRIM_VDEVS, vdev_guids);
686
fnvlist_add_uint64(optional, ZPOOL_TRIM_RATE, 1ULL << 30);
687
fnvlist_add_boolean_value(optional, ZPOOL_TRIM_SECURE, B_TRUE);
688
689
IOC_INPUT_TEST(ZFS_IOC_POOL_TRIM, pool, required, optional, EINVAL);
690
nvlist_free(vdev_guids);
691
nvlist_free(optional);
692
nvlist_free(required);
693
}
694
695
/* Test with invalid values */
696
static void
697
test_scrub(const char *pool)
698
{
699
nvlist_t *required = fnvlist_alloc();
700
fnvlist_add_uint64(required, "scan_type", POOL_SCAN_FUNCS + 1);
701
fnvlist_add_uint64(required, "scan_command", POOL_SCRUB_FLAGS_END + 1);
702
IOC_INPUT_TEST(ZFS_IOC_POOL_SCRUB, pool, required, NULL, EINVAL);
703
nvlist_free(required);
704
}
705
706
static int
707
zfs_destroy(const char *dataset)
708
{
709
zfs_cmd_t zc = {"\0"};
710
int err;
711
712
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
713
zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
714
err = lzc_ioctl_fd(zfs_fd, ZFS_IOC_DESTROY, &zc);
715
716
return (err == 0 ? 0 : errno);
717
}
718
719
static void
720
test_redact(const char *snapshot1, const char *snapshot2)
721
{
722
nvlist_t *required = fnvlist_alloc();
723
nvlist_t *snapnv = fnvlist_alloc();
724
char bookmark[MAXNAMELEN + 32];
725
726
fnvlist_add_string(required, "bookname", "testbookmark");
727
fnvlist_add_boolean(snapnv, snapshot2);
728
fnvlist_add_nvlist(required, "snapnv", snapnv);
729
730
IOC_INPUT_TEST(ZFS_IOC_REDACT, snapshot1, required, NULL, 0);
731
732
nvlist_free(snapnv);
733
nvlist_free(required);
734
735
strlcpy(bookmark, snapshot1, sizeof (bookmark));
736
*strchr(bookmark, '@') = '\0';
737
strlcat(bookmark, "#testbookmark", sizeof (bookmark) -
738
strlen(bookmark));
739
zfs_destroy(bookmark);
740
}
741
742
static void
743
test_get_bookmark_props(const char *bookmark)
744
{
745
IOC_INPUT_TEST(ZFS_IOC_GET_BOOKMARK_PROPS, bookmark, NULL, NULL, 0);
746
}
747
748
static void
749
test_wait(const char *pool)
750
{
751
nvlist_t *required = fnvlist_alloc();
752
nvlist_t *optional = fnvlist_alloc();
753
754
fnvlist_add_int32(required, "wait_activity", 2);
755
fnvlist_add_uint64(optional, "wait_tag", 0xdeadbeefdeadbeef);
756
757
IOC_INPUT_TEST(ZFS_IOC_WAIT, pool, required, optional, EINVAL);
758
759
nvlist_free(required);
760
nvlist_free(optional);
761
}
762
763
static void
764
test_wait_fs(const char *dataset)
765
{
766
nvlist_t *required = fnvlist_alloc();
767
768
fnvlist_add_int32(required, "wait_activity", 2);
769
770
IOC_INPUT_TEST(ZFS_IOC_WAIT_FS, dataset, required, NULL, EINVAL);
771
772
nvlist_free(required);
773
}
774
775
static void
776
test_get_bootenv(const char *pool)
777
{
778
IOC_INPUT_TEST(ZFS_IOC_GET_BOOTENV, pool, NULL, NULL, 0);
779
}
780
781
static void
782
test_set_bootenv(const char *pool)
783
{
784
nvlist_t *required = fnvlist_alloc();
785
786
fnvlist_add_uint64(required, "version", VB_RAW);
787
fnvlist_add_string(required, GRUB_ENVMAP, "test");
788
789
IOC_INPUT_TEST_WILD(ZFS_IOC_SET_BOOTENV, pool, required, NULL, 0);
790
791
nvlist_free(required);
792
}
793
794
static void
795
zfs_ioc_input_tests(const char *pool)
796
{
797
char filepath[] = "/tmp/ioc_test_file_XXXXXX";
798
char dataset[ZFS_MAX_DATASET_NAME_LEN];
799
char snapbase[ZFS_MAX_DATASET_NAME_LEN + 32];
800
char snapshot[ZFS_MAX_DATASET_NAME_LEN + 32];
801
char bookmark[ZFS_MAX_DATASET_NAME_LEN + 32];
802
char backup[ZFS_MAX_DATASET_NAME_LEN];
803
char clone[ZFS_MAX_DATASET_NAME_LEN];
804
char clonesnap[ZFS_MAX_DATASET_NAME_LEN + 32];
805
int tmpfd, err;
806
807
/*
808
* Setup names and create a working dataset
809
*/
810
(void) snprintf(dataset, sizeof (dataset), "%s/test-fs", pool);
811
(void) snprintf(snapbase, sizeof (snapbase), "%s@snapbase", dataset);
812
(void) snprintf(snapshot, sizeof (snapshot), "%s@snapshot", dataset);
813
(void) snprintf(bookmark, sizeof (bookmark), "%s#bookmark", dataset);
814
(void) snprintf(clone, sizeof (clone), "%s/test-fs-clone", pool);
815
(void) snprintf(clonesnap, sizeof (clonesnap), "%s@snap", clone);
816
(void) snprintf(backup, sizeof (backup), "%s/backup", pool);
817
818
err = lzc_create(dataset, LZC_DATSET_TYPE_ZFS, NULL, NULL, -1);
819
if (err) {
820
(void) fprintf(stderr, "could not create '%s': %s\n",
821
dataset, strerror(errno));
822
exit(2);
823
}
824
825
tmpfd = mkstemp(filepath);
826
if (tmpfd < 0) {
827
(void) fprintf(stderr, "could not create '%s': %s\n",
828
filepath, strerror(errno));
829
exit(2);
830
}
831
832
/*
833
* run a test for each ioctl
834
* Note that some test build on previous test operations
835
*/
836
test_pool_sync(pool);
837
test_pool_reopen(pool);
838
test_pool_checkpoint(pool);
839
test_pool_discard_checkpoint(pool);
840
test_log_history(pool);
841
842
test_create(dataset);
843
test_snapshot(pool, snapbase);
844
test_snapshot(pool, snapshot);
845
846
test_space_snaps(snapshot);
847
test_send_space(snapbase, snapshot);
848
test_send_new(snapshot, tmpfd);
849
test_recv_new(backup, tmpfd);
850
851
test_bookmark(pool, snapshot, bookmark);
852
test_get_bookmarks(dataset);
853
test_get_bookmark_props(bookmark);
854
test_destroy_bookmarks(pool, bookmark);
855
856
test_hold(pool, snapshot);
857
test_get_holds(snapshot);
858
test_release(pool, snapshot);
859
860
test_clone(snapshot, clone);
861
test_snapshot(pool, clonesnap);
862
test_redact(snapshot, clonesnap);
863
zfs_destroy(clonesnap);
864
zfs_destroy(clone);
865
866
test_rollback(dataset, snapshot);
867
test_destroy_snaps(pool, snapshot);
868
test_destroy_snaps(pool, snapbase);
869
870
test_remap(dataset);
871
test_channel_program(pool);
872
873
test_load_key(dataset);
874
test_change_key(dataset);
875
test_unload_key(dataset);
876
877
test_vdev_initialize(pool);
878
test_vdev_trim(pool);
879
880
test_wait(pool);
881
test_wait_fs(dataset);
882
883
test_set_bootenv(pool);
884
test_get_bootenv(pool);
885
886
test_scrub(pool);
887
888
/*
889
* cleanup
890
*/
891
zfs_cmd_t zc = {"\0"};
892
893
nvlist_t *snaps = fnvlist_alloc();
894
fnvlist_add_boolean(snaps, snapshot);
895
(void) lzc_destroy_snaps(snaps, B_FALSE, NULL);
896
nvlist_free(snaps);
897
898
(void) zfs_destroy(dataset);
899
(void) zfs_destroy(backup);
900
901
(void) close(tmpfd);
902
(void) unlink(filepath);
903
904
/*
905
* All the unused slots should yield ZFS_ERR_IOC_CMD_UNAVAIL
906
*/
907
for (int i = 0; i < ARRAY_SIZE(ioc_skip); i++) {
908
if (ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST])
909
(void) fprintf(stderr, "cmd %d tested, not skipped!\n",
910
(int)(ioc_skip[i] - ZFS_IOC_FIRST));
911
912
ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST] = B_TRUE;
913
}
914
915
(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
916
zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
917
918
for (unsigned ioc = ZFS_IOC_FIRST; ioc < ZFS_IOC_LAST; ioc++) {
919
unsigned cmd = ioc - ZFS_IOC_FIRST;
920
921
if (ioc_tested[cmd])
922
continue;
923
924
if (lzc_ioctl_fd(zfs_fd, ioc, &zc) != 0 &&
925
errno != ZFS_ERR_IOC_CMD_UNAVAIL) {
926
(void) fprintf(stderr, "cmd %d is missing a test case "
927
"(%d)\n", cmd, errno);
928
}
929
}
930
}
931
932
enum zfs_ioc_ref {
933
#ifdef __FreeBSD__
934
ZFS_IOC_BASE = 0,
935
#else
936
ZFS_IOC_BASE = ('Z' << 8),
937
#endif
938
ZFS_IOC_PLATFORM_BASE = ZFS_IOC_BASE + 0x80,
939
};
940
941
/*
942
* Canonical reference check of /dev/zfs ioctl numbers.
943
* These cannot change and new ioctl numbers must be appended.
944
*/
945
static boolean_t
946
validate_ioc_values(void)
947
{
948
boolean_t result = B_TRUE;
949
950
#define CHECK(expr) do { \
951
if (!(expr)) { \
952
result = B_FALSE; \
953
fprintf(stderr, "(%s) === FALSE\n", #expr); \
954
} \
955
} while (0)
956
957
CHECK(ZFS_IOC_BASE + 0 == ZFS_IOC_POOL_CREATE);
958
CHECK(ZFS_IOC_BASE + 1 == ZFS_IOC_POOL_DESTROY);
959
CHECK(ZFS_IOC_BASE + 2 == ZFS_IOC_POOL_IMPORT);
960
CHECK(ZFS_IOC_BASE + 3 == ZFS_IOC_POOL_EXPORT);
961
CHECK(ZFS_IOC_BASE + 4 == ZFS_IOC_POOL_CONFIGS);
962
CHECK(ZFS_IOC_BASE + 5 == ZFS_IOC_POOL_STATS);
963
CHECK(ZFS_IOC_BASE + 6 == ZFS_IOC_POOL_TRYIMPORT);
964
CHECK(ZFS_IOC_BASE + 7 == ZFS_IOC_POOL_SCAN);
965
CHECK(ZFS_IOC_BASE + 8 == ZFS_IOC_POOL_FREEZE);
966
CHECK(ZFS_IOC_BASE + 9 == ZFS_IOC_POOL_UPGRADE);
967
CHECK(ZFS_IOC_BASE + 10 == ZFS_IOC_POOL_GET_HISTORY);
968
CHECK(ZFS_IOC_BASE + 11 == ZFS_IOC_VDEV_ADD);
969
CHECK(ZFS_IOC_BASE + 12 == ZFS_IOC_VDEV_REMOVE);
970
CHECK(ZFS_IOC_BASE + 13 == ZFS_IOC_VDEV_SET_STATE);
971
CHECK(ZFS_IOC_BASE + 14 == ZFS_IOC_VDEV_ATTACH);
972
CHECK(ZFS_IOC_BASE + 15 == ZFS_IOC_VDEV_DETACH);
973
CHECK(ZFS_IOC_BASE + 16 == ZFS_IOC_VDEV_SETPATH);
974
CHECK(ZFS_IOC_BASE + 17 == ZFS_IOC_VDEV_SETFRU);
975
CHECK(ZFS_IOC_BASE + 18 == ZFS_IOC_OBJSET_STATS);
976
CHECK(ZFS_IOC_BASE + 19 == ZFS_IOC_OBJSET_ZPLPROPS);
977
CHECK(ZFS_IOC_BASE + 20 == ZFS_IOC_DATASET_LIST_NEXT);
978
CHECK(ZFS_IOC_BASE + 21 == ZFS_IOC_SNAPSHOT_LIST_NEXT);
979
CHECK(ZFS_IOC_BASE + 22 == ZFS_IOC_SET_PROP);
980
CHECK(ZFS_IOC_BASE + 23 == ZFS_IOC_CREATE);
981
CHECK(ZFS_IOC_BASE + 24 == ZFS_IOC_DESTROY);
982
CHECK(ZFS_IOC_BASE + 25 == ZFS_IOC_ROLLBACK);
983
CHECK(ZFS_IOC_BASE + 26 == ZFS_IOC_RENAME);
984
CHECK(ZFS_IOC_BASE + 27 == ZFS_IOC_RECV);
985
CHECK(ZFS_IOC_BASE + 28 == ZFS_IOC_SEND);
986
CHECK(ZFS_IOC_BASE + 29 == ZFS_IOC_INJECT_FAULT);
987
CHECK(ZFS_IOC_BASE + 30 == ZFS_IOC_CLEAR_FAULT);
988
CHECK(ZFS_IOC_BASE + 31 == ZFS_IOC_INJECT_LIST_NEXT);
989
CHECK(ZFS_IOC_BASE + 32 == ZFS_IOC_ERROR_LOG);
990
CHECK(ZFS_IOC_BASE + 33 == ZFS_IOC_CLEAR);
991
CHECK(ZFS_IOC_BASE + 34 == ZFS_IOC_PROMOTE);
992
CHECK(ZFS_IOC_BASE + 35 == ZFS_IOC_SNAPSHOT);
993
CHECK(ZFS_IOC_BASE + 36 == ZFS_IOC_DSOBJ_TO_DSNAME);
994
CHECK(ZFS_IOC_BASE + 37 == ZFS_IOC_OBJ_TO_PATH);
995
CHECK(ZFS_IOC_BASE + 38 == ZFS_IOC_POOL_SET_PROPS);
996
CHECK(ZFS_IOC_BASE + 39 == ZFS_IOC_POOL_GET_PROPS);
997
CHECK(ZFS_IOC_BASE + 40 == ZFS_IOC_SET_FSACL);
998
CHECK(ZFS_IOC_BASE + 41 == ZFS_IOC_GET_FSACL);
999
CHECK(ZFS_IOC_BASE + 42 == ZFS_IOC_SHARE);
1000
CHECK(ZFS_IOC_BASE + 43 == ZFS_IOC_INHERIT_PROP);
1001
CHECK(ZFS_IOC_BASE + 44 == ZFS_IOC_SMB_ACL);
1002
CHECK(ZFS_IOC_BASE + 45 == ZFS_IOC_USERSPACE_ONE);
1003
CHECK(ZFS_IOC_BASE + 46 == ZFS_IOC_USERSPACE_MANY);
1004
CHECK(ZFS_IOC_BASE + 47 == ZFS_IOC_USERSPACE_UPGRADE);
1005
CHECK(ZFS_IOC_BASE + 48 == ZFS_IOC_HOLD);
1006
CHECK(ZFS_IOC_BASE + 49 == ZFS_IOC_RELEASE);
1007
CHECK(ZFS_IOC_BASE + 50 == ZFS_IOC_GET_HOLDS);
1008
CHECK(ZFS_IOC_BASE + 51 == ZFS_IOC_OBJSET_RECVD_PROPS);
1009
CHECK(ZFS_IOC_BASE + 52 == ZFS_IOC_VDEV_SPLIT);
1010
CHECK(ZFS_IOC_BASE + 53 == ZFS_IOC_NEXT_OBJ);
1011
CHECK(ZFS_IOC_BASE + 54 == ZFS_IOC_DIFF);
1012
CHECK(ZFS_IOC_BASE + 55 == ZFS_IOC_TMP_SNAPSHOT);
1013
CHECK(ZFS_IOC_BASE + 56 == ZFS_IOC_OBJ_TO_STATS);
1014
CHECK(ZFS_IOC_BASE + 57 == ZFS_IOC_SPACE_WRITTEN);
1015
CHECK(ZFS_IOC_BASE + 58 == ZFS_IOC_SPACE_SNAPS);
1016
CHECK(ZFS_IOC_BASE + 59 == ZFS_IOC_DESTROY_SNAPS);
1017
CHECK(ZFS_IOC_BASE + 60 == ZFS_IOC_POOL_REGUID);
1018
CHECK(ZFS_IOC_BASE + 61 == ZFS_IOC_POOL_REOPEN);
1019
CHECK(ZFS_IOC_BASE + 62 == ZFS_IOC_SEND_PROGRESS);
1020
CHECK(ZFS_IOC_BASE + 63 == ZFS_IOC_LOG_HISTORY);
1021
CHECK(ZFS_IOC_BASE + 64 == ZFS_IOC_SEND_NEW);
1022
CHECK(ZFS_IOC_BASE + 65 == ZFS_IOC_SEND_SPACE);
1023
CHECK(ZFS_IOC_BASE + 66 == ZFS_IOC_CLONE);
1024
CHECK(ZFS_IOC_BASE + 67 == ZFS_IOC_BOOKMARK);
1025
CHECK(ZFS_IOC_BASE + 68 == ZFS_IOC_GET_BOOKMARKS);
1026
CHECK(ZFS_IOC_BASE + 69 == ZFS_IOC_DESTROY_BOOKMARKS);
1027
CHECK(ZFS_IOC_BASE + 70 == ZFS_IOC_RECV_NEW);
1028
CHECK(ZFS_IOC_BASE + 71 == ZFS_IOC_POOL_SYNC);
1029
CHECK(ZFS_IOC_BASE + 72 == ZFS_IOC_CHANNEL_PROGRAM);
1030
CHECK(ZFS_IOC_BASE + 73 == ZFS_IOC_LOAD_KEY);
1031
CHECK(ZFS_IOC_BASE + 74 == ZFS_IOC_UNLOAD_KEY);
1032
CHECK(ZFS_IOC_BASE + 75 == ZFS_IOC_CHANGE_KEY);
1033
CHECK(ZFS_IOC_BASE + 76 == ZFS_IOC_REMAP);
1034
CHECK(ZFS_IOC_BASE + 77 == ZFS_IOC_POOL_CHECKPOINT);
1035
CHECK(ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_DISCARD_CHECKPOINT);
1036
CHECK(ZFS_IOC_BASE + 79 == ZFS_IOC_POOL_INITIALIZE);
1037
CHECK(ZFS_IOC_BASE + 80 == ZFS_IOC_POOL_TRIM);
1038
CHECK(ZFS_IOC_BASE + 81 == ZFS_IOC_REDACT);
1039
CHECK(ZFS_IOC_BASE + 82 == ZFS_IOC_GET_BOOKMARK_PROPS);
1040
CHECK(ZFS_IOC_BASE + 83 == ZFS_IOC_WAIT);
1041
CHECK(ZFS_IOC_BASE + 84 == ZFS_IOC_WAIT_FS);
1042
CHECK(ZFS_IOC_BASE + 87 == ZFS_IOC_POOL_SCRUB);
1043
CHECK(ZFS_IOC_PLATFORM_BASE + 1 == ZFS_IOC_EVENTS_NEXT);
1044
CHECK(ZFS_IOC_PLATFORM_BASE + 2 == ZFS_IOC_EVENTS_CLEAR);
1045
CHECK(ZFS_IOC_PLATFORM_BASE + 3 == ZFS_IOC_EVENTS_SEEK);
1046
CHECK(ZFS_IOC_PLATFORM_BASE + 4 == ZFS_IOC_NEXTBOOT);
1047
CHECK(ZFS_IOC_PLATFORM_BASE + 5 == ZFS_IOC_JAIL);
1048
CHECK(ZFS_IOC_PLATFORM_BASE + 6 == ZFS_IOC_UNJAIL);
1049
CHECK(ZFS_IOC_PLATFORM_BASE + 7 == ZFS_IOC_SET_BOOTENV);
1050
CHECK(ZFS_IOC_PLATFORM_BASE + 8 == ZFS_IOC_GET_BOOTENV);
1051
1052
#undef CHECK
1053
1054
return (result);
1055
}
1056
1057
int
1058
main(int argc, const char *argv[])
1059
{
1060
if (argc != 2) {
1061
(void) fprintf(stderr, "usage: %s <pool>\n", argv[0]);
1062
exit(2);
1063
}
1064
1065
if (!validate_ioc_values()) {
1066
(void) fprintf(stderr, "WARNING: zfs_ioc_t has binary "
1067
"incompatible command values\n");
1068
exit(3);
1069
}
1070
1071
(void) libzfs_core_init();
1072
zfs_fd = open(ZFS_DEV, O_RDWR);
1073
if (zfs_fd < 0) {
1074
(void) fprintf(stderr, "open: %s\n", strerror(errno));
1075
libzfs_core_fini();
1076
exit(2);
1077
}
1078
1079
zfs_ioc_input_tests(argv[1]);
1080
1081
(void) close(zfs_fd);
1082
libzfs_core_fini();
1083
1084
return (unexpected_failures);
1085
}
1086
1087