]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/kvm/util/read-write.c
Merge remote-tracking branch 'signal/for-next'
[karo-tx-linux.git] / tools / kvm / util / read-write.c
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