master
c 656 lines 17.5 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 splice.c
8
9 Abstract:
10
11 This file contains tests for the splice syscall.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <unistd.h>
18 #include <sys/syscall.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <fcntl.h>
23
24 #define LXT_NAME "Splice"
25
26 #define SPLICE_SYSCALL(_Fdin, _Offin, _Fdout, _Offout, _Size, _Flags) \
27 syscall(SYS_splice, _Fdin, _Offin, _Fdout, _Offout, _Size, _Flags)
28
29 #define TEE_SYSCALL(_Fdin, _Fdout, _Size, _Flags) syscall(SYS_tee, _Fdin, _Fdout, _Size, _Flags)
30
31 #ifndef SPLICE_F_NONBLOCK
32 #define SPLICE_F_NONBLOCK 0x02
33 #endif
34
35 #define SPLICE_READ_PIPE_INDEX 0
36 #define SPLICE_WRITE_PIPE_INDEX 1
37
38 //
39 // The following defines a standardized file path and content for a file that
40 // can be used for splicing.
41 //
42
43 #define SPLICE_STD_FILE "/data/test/splice_test_std_file_1.txt"
44 #define SPLICE_STD_FILE_CONTENT "123456789Test"
45 #define SPLICE_STD_FILE_SIZE (unsigned long)(strlen(SPLICE_STD_FILE_CONTENT))
46
47 int SpliceOpenStandardFile(void);
48
49 int SpliceVariationBasicTests(PLXT_ARGS Args);
50
51 int SpliceVariationBlocking(PLXT_ARGS Args);
52
53 int SpliceVariationInvalidParameters(PLXT_ARGS Args);
54
55 int TeeVariationBasicTests(PLXT_ARGS Args);
56
57 int TeeVariationInvalidParameters(PLXT_ARGS Args);
58
59 //
60 // Globals.
61 //
62
63 static const LXT_VARIATION g_LxtVariations[] = {
64 {"Splice - Invalid Parameter Test ", SpliceVariationInvalidParameters},
65 {"Splice - Blocking Tests", SpliceVariationBlocking},
66 {"Splice - Basic Usage Tests", SpliceVariationBasicTests},
67 {"Tee - Invalid Parameter Test ", TeeVariationInvalidParameters},
68 {"Tee - Basic Usage Test", TeeVariationBasicTests}};
69
70 int SpliceTestEntry(int Argc, char* Argv[])
71
72 /*++
73
74 Routine Description:
75
76 This routine is the main entry point for the procfs tests.
77
78 Arguments:
79
80 Argc - Supplies the number of command line arguments.
81
82 Argv - Supplies the command line arguments.
83
84 Return Value:
85
86 Returns 0 on success, -1 on failure.
87
88 --*/
89
90 {
91
92 LXT_ARGS Args;
93 int Result;
94
95 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
96 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
97
98 ErrorExit:
99 LxtUninitialize();
100 return !LXT_SUCCESS(Result);
101 }
102
103 int SpliceOpenStandardFile(void)
104
105 /*++
106
107 Routine Description:
108
109 This routine returns the file descriptor for the standard file which
110 include uniform data for splicing.
111
112 Arguments:
113
114 None.
115
116 Return Value:
117
118 On success, returns open file descriptor; otherwise, -1.
119
120 --*/
121
122 {
123
124 int Fd;
125 off_t Offset;
126 int Result;
127
128 LxtCheckErrno(Fd = open(SPLICE_STD_FILE, (O_CREAT | O_RDWR), (S_IRUSR | S_IWUSR)));
129
130 LxtCheckErrno(write(Fd, SPLICE_STD_FILE_CONTENT, SPLICE_STD_FILE_SIZE));
131
132 //
133 // Set the offset back to zero.
134 //
135
136 LxtCheckErrno(Offset = lseek(Fd, 0, SEEK_SET));
137
138 //
139 // Set the result.
140 //
141
142 Result = Fd;
143 Fd = 0;
144
145 ErrorExit:
146 if (Fd > 0)
147 {
148 close(Fd);
149 unlink(SPLICE_STD_FILE);
150 }
151
152 return Result;
153 }
154
155 int SpliceVariationBasicTests(PLXT_ARGS Args)
156
157 /*++
158
159 Routine Description:
160
161 This routine runs basic usage tests for splice, including splicing between
162 two pipes and a pipe and a regular file, and tests the results for
163 accurate splice sizes, content, and file offsets.
164
165 Arguments:
166
167 Args - Supplies a pointer to variation arguments.
168
169 Return Value:
170
171 On success, returns open file descriptor; otherwise, -1.
172
173
174 --*/
175
176 {
177
178 char Buffer[4];
179 LXT_PIPE DestinationPipe = {-1, -1};
180 loff_t InitialOffset;
181 loff_t Offset;
182 char* PipeData;
183 ssize_t PipeDataSize;
184 int RegularFd;
185 int Result;
186 ssize_t SpliceSize;
187 LXT_PIPE SourcePipe = {-1, -1};
188
189 RegularFd = -1;
190 PipeData = "1234";
191 PipeDataSize = strlen(PipeData);
192 LxtCheckResult(LxtCreatePipe(&DestinationPipe));
193 LxtCheckResult(LxtCreatePipe(&SourcePipe));
194 LxtCheckResult(RegularFd = SpliceOpenStandardFile());
195
196 //
197 // Set up read-end of pipes as non-blocking for empty tests.
198 //
199
200 LxtCheckErrno(fcntl(SourcePipe.Read, F_SETFL, O_NONBLOCK));
201 LxtCheckErrno(fcntl(DestinationPipe.Read, F_SETFL, O_NONBLOCK));
202
203 //
204 // Perform basic tests between pipes.
205 //
206
207 LxtLogInfo("Basic Usage - Splicing between two pipes");
208 LxtCheckErrno(write(SourcePipe.Write, PipeData, PipeDataSize));
209 LxtCheckErrno(SpliceSize = SPLICE_SYSCALL(SourcePipe.Read, NULL, DestinationPipe.Write, NULL, PipeDataSize, SPLICE_F_NONBLOCK));
210
211 LxtCheckEqual(SpliceSize, PipeDataSize, "%d");
212
213 //
214 // Check that the read pipe is now empty by attempting to read a single
215 // byte.
216 //
217
218 LxtCheckErrnoFailure(read(SourcePipe.Read, Buffer, 1), EAGAIN);
219 LxtCheckErrno(SpliceSize = read(DestinationPipe.Read, Buffer, PipeDataSize));
220
221 LxtCheckEqual(SpliceSize, PipeDataSize, "%d");
222
223 //
224 // LX_TODO: Enable the following additional basic tests once splicing is
225 // available for VolFs file types.
226 //
227
228 /*
229 //
230 // Perform test from a regular file to a pipe.
231 //
232
233 InitialOffset = 4;
234 Offset = InitialOffset;
235 LxtLogInfo("Basic Usage - Splicing from a regular file to a pipe");
236 LxtCheckErrno(SpliceSize = SPLICE_SYSCALL(RegularFd,
237 &Offset,
238 DestinationPipe.Write,
239 NULL,
240 4,
241 SPLICE_F_NONBLOCK));
242
243 LxtCheckEqual(SpliceSize, 4, "%d");
244 LxtCheckErrno(SpliceSize = read(DestinationPipe.Read, Buffer, 4));
245 LxtCheckEqual(SpliceSize, 4, "%d");
246 LxtCheckEqual(Offset - InitialOffset, 4, "%d");
247 LxtCheckEqual(Buffer[0],
248 SPLICE_STD_FILE_CONTENT[InitialOffset],
249 "%c");
250
251 //
252 // Ensure that offset remains unchanged on the file.
253 //
254
255 LxtCheckErrno(SpliceSize = read(RegularFd, Buffer, 4));
256 LxtCheckEqual(SpliceSize, 4, "%d");
257 LxtCheckEqual(Buffer[0],
258 SPLICE_STD_FILE_CONTENT[0],
259 "%c");
260
261 //
262 // Reset the file's offset for the next test.
263 //
264
265 LxtCheckErrno(lseek(RegularFd, 0, SEEK_SET));
266
267 //
268 // Perform test from a pipe to a regular file.
269 //
270
271 InitialOffset = 1;
272 Offset = InitialOffset;
273 LxtLogInfo("Basic Usage - Splicing from a pipe to a regular file");
274 LxtCheckErrno(write(SourcePipe.Write, PipeData, PipeDataSize));
275 LxtCheckErrno(SpliceSize = SPLICE_SYSCALL(SourcePipe.Read,
276 NULL,
277 RegularFd,
278 &Offset,
279 PipeDataSize,
280 SPLICE_F_NONBLOCK));
281
282 LxtCheckEqual(SpliceSize, PipeDataSize, "%d");
283 LxtCheckEqual(Offset - InitialOffset, PipeDataSize, "%d");
284
285 //
286 // Ensure that the regular file's internal offset is unchanged and that the
287 // the pipe data was properly splice into the file with the offset.
288 //
289
290 LxtCheckErrno(SpliceSize = read(RegularFd, Buffer, 2));
291 LxtCheckEqual(SpliceSize, 2, "%d");
292 LxtCheckEqual(Buffer[0],
293 SPLICE_STD_FILE_CONTENT[0],
294 "%c");
295
296 LxtCheckEqual(Buffer[1], PipeData[0], "%c");
297 */
298
299 ErrorExit:
300 LxtClosePipe(&DestinationPipe);
301 LxtClosePipe(&SourcePipe);
302 if (RegularFd > 0)
303 {
304 close(RegularFd);
305 }
306
307 return Result;
308 }
309
310 int SpliceVariationBlocking(PLXT_ARGS Args)
311
312 /*++
313
314 Routine Description:
315
316 This routine tests the splice syscall with the splice-specific non-blocking
317 flag with pipes that have opposite internal blocking settings and checks for
318 proper behavior.
319
320 Arguments:
321
322 Args - Supplies a pointer to variation arguments.
323
324 Return Value:
325
326 On success, returns open file descriptor; otherwise, -1.
327
328
329 --*/
330
331 {
332
333 pid_t ChildPid;
334 LXT_PIPE DestinationPipe = {-1, -1};
335 int Result;
336 LXT_PIPE SourcePipe = {-1, -1};
337 int WaitPidResult;
338 int WaitPidStatus;
339
340 LxtCheckResult(LxtCreatePipe(&DestinationPipe));
341 LxtCheckResult(LxtCreatePipe(&SourcePipe));
342
343 //
344 // Verify that a pipe which is automatically set to have blocking I/O
345 // semantics, does not block when the splice call is supplied with the
346 // splice-specific non-blocking flag.
347 //
348
349 LxtLogInfo("Blocking - Non-blocking splice with blocking pipes");
350 LxtCheckResult(ChildPid = fork());
351 if (ChildPid == 0)
352 {
353
354 //
355 // By default, the created pipes are blocking. The splice non-blocking
356 // flag should override this behavior.
357 //
358
359 Result = SPLICE_SYSCALL(SourcePipe.Read, NULL, DestinationPipe.Write, NULL, 1, SPLICE_F_NONBLOCK);
360
361 if (Result >= 0)
362 {
363 LxtLogError("Non-blocking splice syscall succeeded");
364 _exit(1);
365 }
366
367 if (errno != EAGAIN)
368 {
369 LxtLogError("Non-blocking splice syscall returned with error %s", strerror(errno));
370
371 _exit(1);
372 }
373
374 _exit(0);
375 }
376
377 LxtCheckResult(WaitPidStatus = LxtWaitPidPollOptions(ChildPid, 0, 0, 2));
378
379 //
380 // Verify that a pipe that is set to non-blocking will block when the
381 // splice-specific non-blocking flag is not passed to splice.
382 //
383
384 LxtLogInfo("Blocking - Blocking splice with non-blocking pipe");
385 LxtCheckErrno(fcntl(SourcePipe.Read, F_SETFL, O_NONBLOCK));
386 LxtCheckResult(ChildPid = fork());
387 if (ChildPid == 0)
388 {
389 Result = SPLICE_SYSCALL(SourcePipe.Read, NULL, DestinationPipe.Write, NULL, 1, 0);
390
391 _exit(0);
392 }
393
394 sleep(2);
395 LxtCheckErrno(WaitPidResult = waitpid(ChildPid, &WaitPidStatus, WNOHANG));
396
397 //
398 // If the child is not alive, it did not block as expected.
399 //
400
401 LxtCheckEqual(WaitPidResult, 0, "%d");
402 kill(ChildPid, SIGKILL);
403 Result = 0;
404 ErrorExit:
405 LxtClosePipe(&DestinationPipe);
406 LxtClosePipe(&SourcePipe);
407 return Result;
408 }
409
410 int SpliceVariationInvalidParameters(PLXT_ARGS Args)
411
412 /*++
413
414 Routine Description:
415
416 This routine tests the splice syscall errors are properly set when invalid
417 parameters are passed to it.
418
419 Arguments:
420
421 Args - Supplies a pointer to variation arguments.
422
423 Return Value:
424
425 On success, returns open file descriptor; otherwise, -1.
426
427 --*/
428 {
429
430 LXT_PIPE DestinationPipe = {-1, -1};
431 loff_t ReadOffset;
432 int Result;
433 LXT_PIPE SourcePipe = {-1, -1};
434 int StandardFd;
435
436 StandardFd = 0;
437 LxtCheckErrno(LxtCreatePipe(&SourcePipe));
438 LxtCheckErrno(LxtCreatePipe(&DestinationPipe));
439 LxtCheckResult(StandardFd = SpliceOpenStandardFile());
440
441 //
442 // Put some random data into the source pipe and set the offset.
443 //
444
445 LxtCheckErrno(write(SourcePipe.Write, "1234", 4));
446 ReadOffset = 2;
447
448 //
449 // Check that a call with invalid parameters, but a splice size of zero will
450 // succeed.
451 //
452
453 LxtLogInfo("Invalid Params - Passing invalid parameters with splice size of zero");
454
455 LxtCheckErrno(SPLICE_SYSCALL(SourcePipe.Read, &ReadOffset, DestinationPipe.Write, NULL, 0, 0));
456
457 LxtCheckErrno(SPLICE_SYSCALL(StandardFd, NULL, StandardFd, NULL, 0, 0));
458 LxtCheckErrno(SPLICE_SYSCALL(-1, NULL, -1, NULL, 0, 0));
459
460 //
461 // Check that invalid flags do not cause any errors.
462 //
463
464 LxtCheckErrno(SPLICE_SYSCALL(SourcePipe.Read, NULL, DestinationPipe.Write, NULL, 4, 0xF0));
465
466 //
467 // Check the error result when a pipe is given a non-null offset.
468 //
469
470 LxtLogInfo("Invalid Params - Passing non-null offset with pipe fd");
471 LxtCheckErrnoFailure(SPLICE_SYSCALL(SourcePipe.Read, &ReadOffset, DestinationPipe.Write, NULL, 1, 0), ESPIPE);
472
473 LxtCheckErrnoFailure(SPLICE_SYSCALL(SourcePipe.Read, NULL, DestinationPipe.Write, &ReadOffset, 1, 0), ESPIPE);
474
475 //
476 // Ensure that the correct error is returned when splice takes two
477 // parameters that are not pipes.
478 //
479
480 LxtLogInfo("Invalid Params - Passing two non-pipe fd's to splice");
481 LxtCheckErrnoFailure(SPLICE_SYSCALL(StandardFd, NULL, StandardFd, NULL, 1, 0), EINVAL);
482
483 //
484 // Validate errors returned wrong read\write pipe
485 //
486
487 //
488 // LX_TODO: Here and in the tee syscall variation, the atomic property of
489 // tee/splice must be implemented before these tests are enabled.
490 //
491
492 /*
493 LxtLogInfo("Invalid Params - Invalid splice read\write pipe 1");
494 LxtCheckErrnoFailure(SPLICE_SYSCALL(SourcePipe.Read,
495 NULL,
496 SourcePipe.Read,
497 NULL,
498 200,
499 0),
500 EBADF);
501
502 LxtLogInfo("Invalid Params - Invalid splice read\write pipe 2");
503 LxtCheckErrnoFailure(SPLICE_SYSCALL(SourcePipe.Write,
504 NULL,
505 SourcePipe.Read,
506 NULL,
507 200,
508 0),
509 EBADF);
510
511 LxtLogInfo("Invalid Params - Invalid splice read\write pipe 3");
512 LxtCheckErrnoFailure(SPLICE_SYSCALL(SourcePipe.Read,
513 NULL,
514 DestinationPipe.Read,
515 NULL,
516 200,
517 0),
518 EBADF);
519 */
520
521 ErrorExit:
522 LxtClosePipe(&SourcePipe);
523 LxtClosePipe(&DestinationPipe);
524 if (StandardFd > 0)
525 {
526 close(StandardFd);
527 }
528
529 return Result;
530 }
531
532 int TeeVariationBasicTests(PLXT_ARGS Args)
533
534 /*++
535 --*/
536
537 {
538
539 char Buffer[16];
540 LXT_PIPE DestinationPipe = {-1, -1};
541 char* PipeData;
542 ssize_t PipeDataSize;
543 ssize_t ReadSize;
544 int Result;
545 ssize_t SpliceSize;
546 LXT_PIPE SourcePipe = {-1, -1};
547
548 PipeData = "1234";
549 PipeDataSize = strlen(PipeData);
550 LxtCheckResult(LxtCreatePipe(&DestinationPipe));
551 LxtCheckResult(LxtCreatePipe(&SourcePipe));
552
553 //
554 // Set up read-end of pipes as non-blocking for empty tests.
555 //
556
557 LxtCheckErrno(fcntl(SourcePipe.Read, F_SETFL, O_NONBLOCK));
558 LxtCheckErrno(fcntl(DestinationPipe.Read, F_SETFL, O_NONBLOCK));
559
560 //
561 // Perform basic tests between pipes.
562 //
563
564 LxtLogInfo("Basic Usage - Tee");
565 LxtCheckErrno(write(SourcePipe.Write, PipeData, PipeDataSize));
566 LxtCheckErrno(SpliceSize = TEE_SYSCALL(SourcePipe.Read, DestinationPipe.Write, PipeDataSize, SPLICE_F_NONBLOCK));
567
568 LxtCheckEqual(SpliceSize, PipeDataSize, "%d");
569
570 //
571 // Check that the read pipe still has the same data as before.
572 //
573
574 LxtCheckErrno(ReadSize = read(SourcePipe.Read, Buffer, PipeDataSize));
575 LxtCheckEqual(ReadSize, PipeDataSize, "%d");
576 Buffer[ReadSize] = '\0';
577 LxtCheckStringEqual(Buffer, PipeData);
578
579 //
580 // Check that the destination pipe has the correct data after the tee.
581 //
582
583 LxtCheckErrno(ReadSize = read(DestinationPipe.Read, Buffer, PipeDataSize));
584 LxtCheckEqual(ReadSize, PipeDataSize, "%d");
585 Buffer[ReadSize] = '\0';
586 LxtCheckStringEqual(Buffer, PipeData);
587
588 ErrorExit:
589 LxtClosePipe(&SourcePipe);
590 LxtClosePipe(&DestinationPipe);
591 return Result;
592 }
593
594 int TeeVariationInvalidParameters(PLXT_ARGS Args)
595
596 /*++
597 --*/
598
599 {
600
601 LXT_PIPE DestinationPipe = {-1, -1};
602 int Result;
603 LXT_PIPE SourcePipe = {-1, -1};
604 int StandardFd;
605
606 StandardFd = 0;
607 LxtCheckErrno(LxtCreatePipe(&SourcePipe));
608 LxtCheckErrno(LxtCreatePipe(&DestinationPipe));
609 LxtCheckResult(StandardFd = SpliceOpenStandardFile());
610
611 //
612 // Put some random data into the source pipe and set the offset.
613 //
614
615 LxtCheckErrno(write(SourcePipe.Write, "1234", 4));
616
617 //
618 // Check that a call with invalid parameters, but a size of zero will
619 // succeed.
620 //
621
622 LxtLogInfo("Invalid Params - Passing invalid parameters to tee with size of zero");
623
624 LxtCheckErrno(TEE_SYSCALL(StandardFd, DestinationPipe.Write, 0, 0));
625 LxtCheckErrno(TEE_SYSCALL(SourcePipe.Read, StandardFd, 0, 0));
626 LxtCheckErrno(TEE_SYSCALL(StandardFd, StandardFd, 0, 0));
627
628 //
629 // Check that invalid flags do not cause any errors.
630 //
631
632 LxtCheckErrno(TEE_SYSCALL(SourcePipe.Read, DestinationPipe.Write, 4, 0xF0));
633 //
634 // Validate the errors returned with invalid parameters and non-zero splice
635 // sizes.
636 //
637
638 LxtLogInfo("Invalid Params - Passing a non-pipe to a tee syscall");
639 LxtCheckErrnoFailure(TEE_SYSCALL(StandardFd, DestinationPipe.Write, 1, 0), EINVAL);
640
641 LxtCheckErrnoFailure(TEE_SYSCALL(SourcePipe.Read, StandardFd, 1, 0), EINVAL);
642
643 //
644 // Validate errors returned sending to the wrong read\write pipe
645 //
646
647 ErrorExit:
648 LxtClosePipe(&SourcePipe);
649 LxtClosePipe(&DestinationPipe);
650 if (StandardFd > 0)
651 {
652 close(StandardFd);
653 }
654
655 return Result;
656 }