1 module during.tests.fsync; 2 3 import during; 4 import during.tests.base; 5 6 import core.stdc.stdlib; 7 import core.sys.linux.errno; 8 import core.sys.linux.fcntl; 9 import core.sys.posix.sys.uio : iovec; 10 import core.sys.posix.unistd; 11 12 @("single") 13 unittest 14 { 15 Uring io; 16 auto res = io.setup(); 17 assert(res >= 0, "Error initializing IO"); 18 19 auto fname = getTestFileName!"fsync_single"; 20 auto fd = openFile(fname, O_CREAT | O_WRONLY); 21 scope (exit) unlink(&fname[0]); 22 23 auto ret = io 24 .putWith!((ref SubmissionEntry e, int fd) => e.prepFsync(fd))(fd) 25 .submit(1); 26 assert(ret == 1); 27 assert(io.length == 1); 28 assert(io.front.res == 0); 29 io.popFront(); 30 31 close(fd); 32 } 33 34 @("barrier") 35 unittest 36 { 37 if (!checkKernelVersion(5, 3)) return; 38 39 enum NUM_WRITES = 4; 40 Uring io; 41 auto res = io.setup(); 42 assert(res >= 0, "Error initializing IO"); 43 44 auto fname = getTestFileName!"fsync_barier"; 45 auto fd = openFile(fname, O_CREAT | O_WRONLY); 46 scope (exit) unlink(&fname[0]); 47 48 iovec[NUM_WRITES] iovecs; 49 foreach (i; 0..NUM_WRITES) 50 { 51 iovecs[i].iov_base = malloc(4096); 52 iovecs[i].iov_len = 4096; 53 } 54 55 int off; 56 foreach (i; 0..NUM_WRITES) 57 { 58 io.putWith!((ref SubmissionEntry e, int fd, ref iovec v, int off) 59 { 60 e.prepWritev(fd, v, off); 61 e.user_data = 1; 62 })(fd, iovecs[i], off); 63 off += 4096; 64 } 65 66 io.putWith!((ref SubmissionEntry e, int fd) 67 { 68 e.prepFsync(fd, FsyncFlags.DATASYNC); 69 e.user_data = 2; 70 e.flags = SubmissionEntryFlags.IO_DRAIN; 71 })(fd); 72 73 auto ret = io.submit(NUM_WRITES + 1); 74 if (ret < 0) 75 { 76 if (ret == -EINVAL) 77 { 78 version (D_BetterC) 79 { 80 errmsg = "Expected kernel to support barrier fsync"; 81 return; 82 } 83 else throw new Exception("Expected kernel to support barrier fsync"); 84 } 85 assert(0, "submit failed"); 86 } 87 else assert(ret == NUM_WRITES + 1); 88 89 // assert(io.length == NUM_WRITES + 1); // TODO: fails on GH actions with 5.11 90 foreach (i; 0..NUM_WRITES + 1) 91 { 92 if (io.empty) io.wait(1); // TODO: workaround for above, similar is used here: https://github.com/axboe/liburing/blob/0b6b5bc79a85bc3a461c6f3ba9c0ce0dba696d4c/test/fsync.c#L111 93 if (io.front.res == -EINVAL) 94 { 95 version (D_BetterC) 96 { 97 errmsg = "Expected kernel to support IOSQE_IO_DRAIN"; 98 break; 99 } 100 else throw new Exception("Expected kernel to support IOSQE_IO_DRAIN"); 101 } 102 assert(io.front.res >= 0); 103 if (i < NUM_WRITES) assert(io.front.user_data == 1, "unexpected op completion"); 104 else assert(io.front.user_data == 2, "unexpected op completion"); 105 106 io.popFront(); 107 } 108 109 close(fd); 110 } 111 112 @("range") 113 unittest 114 { 115 if (!checkKernelVersion(5, 2)) return; 116 117 enum NUM_WRITES = 4; 118 Uring io; 119 auto res = io.setup(); 120 assert(res >= 0, "Error initializing IO"); 121 122 auto fname = getTestFileName!"fsync_range"; 123 auto fd = openFile(fname, O_CREAT | O_WRONLY); 124 scope (exit) unlink(&fname[0]); 125 126 iovec[NUM_WRITES] iovecs; 127 foreach (i; 0..NUM_WRITES) 128 { 129 iovecs[i].iov_base = malloc(4096); 130 iovecs[i].iov_len = 4096; 131 } 132 133 int off; 134 foreach (i; 0..NUM_WRITES) 135 { 136 io.putWith!((ref SubmissionEntry e, int fd, ref iovec v, int off) 137 { 138 e.prepWritev(fd, v, off); 139 e.user_data = 1; 140 e.flags = SubmissionEntryFlags.IO_LINK; 141 })(fd, iovecs[i], off); 142 off += 4096; 143 } 144 145 io.putWith!((ref SubmissionEntry e, int fd) 146 { 147 e.prepSyncFileRange(fd, (NUM_WRITES - 1) * 4096, 4096); 148 e.user_data = 2; 149 e.flags = SubmissionEntryFlags.IO_LINK; 150 })(fd); 151 152 auto ret = io.submit(NUM_WRITES + 1); 153 if (ret < 0) 154 { 155 if (ret == -EINVAL) 156 { 157 version (D_BetterC) 158 { 159 errmsg = "Expected kernel to support range file sync"; 160 return; 161 } 162 else throw new Exception("Expected kernel to support range file sync"); 163 } 164 assert(0, "submit failed"); 165 } 166 else assert(ret == NUM_WRITES + 1); 167 168 assert(io.length == NUM_WRITES + 1); 169 foreach (i; 0..NUM_WRITES + 1) 170 { 171 assert(io.front.res >= 0); 172 if (i < NUM_WRITES) assert(io.front.user_data == 1, "unexpected op completion"); 173 else assert(io.front.user_data == 2, "unexpected op completion"); 174 io.popFront(); 175 } 176 177 close(fd); 178 }