1 #include "kvm/read-write.h" 2 3 #include <sys/types.h> 4 #include <sys/uio.h> 5 #include <unistd.h> 6 #include <string.h> 7 #include <errno.h> 8 9 /* Same as read(2) except that this function never returns EAGAIN or EINTR. */ 10 ssize_t xread(int fd, void *buf, size_t count) 11 { 12 ssize_t nr; 13 14 restart: 15 nr = read(fd, buf, count); 16 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 17 goto restart; 18 19 return nr; 20 } 21 22 /* Same as write(2) except that this function never returns EAGAIN or EINTR. */ 23 ssize_t xwrite(int fd, const void *buf, size_t count) 24 { 25 ssize_t nr; 26 27 restart: 28 nr = write(fd, buf, count); 29 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 30 goto restart; 31 32 return nr; 33 } 34 35 ssize_t read_in_full(int fd, void *buf, size_t count) 36 { 37 ssize_t total = 0; 38 char *p = buf; 39 40 while (count > 0) { 41 ssize_t nr; 42 43 nr = xread(fd, p, count); 44 if (nr <= 0) { 45 if (total > 0) 46 return total; 47 48 return -1; 49 } 50 51 count -= nr; 52 total += nr; 53 p += nr; 54 } 55 56 return total; 57 } 58 59 ssize_t write_in_full(int fd, const void *buf, size_t count) 60 { 61 const char *p = buf; 62 ssize_t total = 0; 63 64 while (count > 0) { 65 ssize_t nr; 66 67 nr = xwrite(fd, p, count); 68 if (nr < 0) 69 return -1; 70 if (nr == 0) { 71 errno = ENOSPC; 72 return -1; 73 } 74 count -= nr; 75 total += nr; 76 p += nr; 77 } 78 79 return total; 80 } 81 82 /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */ 83 ssize_t xpread(int fd, void *buf, size_t count, off_t offset) 84 { 85 ssize_t nr; 86 87 restart: 88 nr = pread(fd, buf, count, offset); 89 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 90 goto restart; 91 92 return nr; 93 } 94 95 /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */ 96 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) 97 { 98 ssize_t nr; 99 100 restart: 101 nr = pwrite(fd, buf, count, offset); 102 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 103 goto restart; 104 105 return nr; 106 } 107 108 ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset) 109 { 110 ssize_t total = 0; 111 char *p = buf; 112 113 while (count > 0) { 114 ssize_t nr; 115 116 nr = xpread(fd, p, count, offset); 117 if (nr <= 0) { 118 if (total > 0) 119 return total; 120 121 return -1; 122 } 123 124 count -= nr; 125 total += nr; 126 p += nr; 127 offset += nr; 128 } 129 130 return total; 131 } 132 133 ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset) 134 { 135 const char *p = buf; 136 ssize_t total = 0; 137 138 while (count > 0) { 139 ssize_t nr; 140 141 nr = xpwrite(fd, p, count, offset); 142 if (nr < 0) 143 return -1; 144 if (nr == 0) { 145 errno = ENOSPC; 146 return -1; 147 } 148 count -= nr; 149 total += nr; 150 p += nr; 151 offset += nr; 152 } 153 154 return total; 155 } 156 157 /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */ 158 ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt) 159 { 160 ssize_t nr; 161 162 restart: 163 nr = readv(fd, iov, iovcnt); 164 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 165 goto restart; 166 167 return nr; 168 } 169 170 /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */ 171 ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt) 172 { 173 ssize_t nr; 174 175 restart: 176 nr = writev(fd, iov, iovcnt); 177 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 178 goto restart; 179 180 return nr; 181 } 182 183 static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt) 184 { 185 size_t size = 0; 186 while (iovcnt--) 187 size += (iov++)->iov_len; 188 189 return size; 190 } 191 192 static inline void shift_iovec(const struct iovec **iov, int *iovcnt, 193 size_t nr, ssize_t *total, size_t *count, off_t *offset) 194 { 195 while (nr >= (*iov)->iov_len) { 196 nr -= (*iov)->iov_len; 197 *total += (*iov)->iov_len; 198 *count -= (*iov)->iov_len; 199 if (offset) 200 *offset += (*iov)->iov_len; 201 (*iovcnt)--; 202 (*iov)++; 203 } 204 } 205 206 ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt) 207 { 208 ssize_t total = 0; 209 size_t count = get_iov_size(iov, iovcnt); 210 211 while (count > 0) { 212 ssize_t nr; 213 214 nr = xreadv(fd, iov, iovcnt); 215 if (nr <= 0) { 216 if (total > 0) 217 return total; 218 219 return -1; 220 } 221 222 shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); 223 } 224 225 return total; 226 } 227 228 ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt) 229 { 230 ssize_t total = 0; 231 size_t count = get_iov_size(iov, iovcnt); 232 233 while (count > 0) { 234 ssize_t nr; 235 236 nr = xwritev(fd, iov, iovcnt); 237 if (nr < 0) 238 return -1; 239 if (nr == 0) { 240 errno = ENOSPC; 241 return -1; 242 } 243 244 shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); 245 } 246 247 return total; 248 } 249 250 /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */ 251 ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) 252 { 253 ssize_t nr; 254 255 restart: 256 nr = preadv(fd, iov, iovcnt, offset); 257 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 258 goto restart; 259 260 return nr; 261 } 262 263 /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */ 264 ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) 265 { 266 ssize_t nr; 267 268 restart: 269 nr = pwritev(fd, iov, iovcnt, offset); 270 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 271 goto restart; 272 273 return nr; 274 } 275 276 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 277 { 278 ssize_t total = 0; 279 size_t count = get_iov_size(iov, iovcnt); 280 281 while (count > 0) { 282 ssize_t nr; 283 284 nr = xpreadv(fd, iov, iovcnt, offset); 285 if (nr <= 0) { 286 if (total > 0) 287 return total; 288 289 return -1; 290 } 291 292 shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); 293 } 294 295 return total; 296 } 297 298 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 299 { 300 ssize_t total = 0; 301 size_t count = get_iov_size(iov, iovcnt); 302 303 while (count > 0) { 304 ssize_t nr; 305 306 nr = xpwritev(fd, iov, iovcnt, offset); 307 if (nr < 0) 308 return -1; 309 if (nr == 0) { 310 errno = ENOSPC; 311 return -1; 312 } 313 314 shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); 315 } 316 317 return total; 318 } 319 320 #ifdef CONFIG_HAS_AIO 321 int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, 322 off_t offset, int ev, void *param) 323 { 324 struct iocb *ios[1] = { iocb }; 325 int ret; 326 327 io_prep_pwritev(iocb, fd, iov, iovcnt, offset); 328 io_set_eventfd(iocb, ev); 329 iocb->data = param; 330 331 restart: 332 ret = io_submit(ctx, 1, ios); 333 if (ret == -EAGAIN) 334 goto restart; 335 return ret; 336 } 337 338 int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, 339 off_t offset, int ev, void *param) 340 { 341 struct iocb *ios[1] = { iocb }; 342 int ret; 343 344 io_prep_preadv(iocb, fd, iov, iovcnt, offset); 345 io_set_eventfd(iocb, ev); 346 iocb->data = param; 347 348 restart: 349 ret = io_submit(ctx, 1, ios); 350 if (ret == -EAGAIN) 351 goto restart; 352 return ret; 353 } 354 #endif 355