]>
Commit | Line | Data |
---|---|---|
b224ea98 | 1 | |
95e36d02 | 2 | |
30a4f2a8 | 3 | /* |
ea6ae5b4 | 4 | * $Id: disk.cc,v 1.143 1999/05/03 20:39:31 wessels Exp $ |
30a4f2a8 | 5 | * |
6 | * DEBUG: section 6 Disk I/O Routines | |
7 | * AUTHOR: Harvest Derived | |
8 | * | |
42c04c16 | 9 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
e25c139f | 10 | * ---------------------------------------------------------- |
30a4f2a8 | 11 | * |
12 | * Squid is the result of efforts by numerous individuals from the | |
13 | * Internet community. Development is led by Duane Wessels of the | |
e25c139f | 14 | * National Laboratory for Applied Network Research and funded by the |
15 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
16 | * Duane Wessels and the University of California San Diego. Please | |
17 | * see the COPYRIGHT file for full details. Squid incorporates | |
18 | * software developed and/or copyrighted by other sources. Please see | |
19 | * the CREDITS file for full details. | |
30a4f2a8 | 20 | * |
21 | * This program is free software; you can redistribute it and/or modify | |
22 | * it under the terms of the GNU General Public License as published by | |
23 | * the Free Software Foundation; either version 2 of the License, or | |
24 | * (at your option) any later version. | |
25 | * | |
26 | * This program is distributed in the hope that it will be useful, | |
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
29 | * GNU General Public License for more details. | |
30 | * | |
31 | * You should have received a copy of the GNU General Public License | |
32 | * along with this program; if not, write to the Free Software | |
cbdec147 | 33 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 34 | * |
30a4f2a8 | 35 | */ |
ed43818f | 36 | |
44a47c6e | 37 | #include "squid.h" |
090089c4 | 38 | |
39 | #define DISK_LINE_LEN 1024 | |
090089c4 | 40 | |
0a0bf5db | 41 | typedef struct open_ctrl_t { |
f17936ab | 42 | FOCB *callback; |
0a0bf5db | 43 | void *callback_data; |
44 | char *path; | |
45 | } open_ctrl_t; | |
46 | ||
de866d20 | 47 | static AIOCB diskHandleWriteComplete; |
48 | static AIOCB diskHandleReadComplete; | |
95d15928 | 49 | static PF diskHandleRead; |
50 | static PF diskHandleWrite; | |
ecefc661 | 51 | static AIOCB fileOpenComplete; |
24382924 | 52 | |
04cece06 | 53 | void |
0673c0ba | 54 | disk_init(void) |
090089c4 | 55 | { |
04cece06 | 56 | #if USE_ASYNC_IO |
57 | aioClose(dup(0)); | |
58 | #endif | |
090089c4 | 59 | } |
60 | ||
61 | /* Open a disk file. Return a file descriptor */ | |
684c2720 | 62 | int |
6cf028ab | 63 | file_open(const char *path, int mode, FOCB * callback, void *callback_data, void *tag) |
090089c4 | 64 | { |
090089c4 | 65 | int fd; |
0a0bf5db | 66 | open_ctrl_t *ctrlp; |
67 | ||
68 | ctrlp = xmalloc(sizeof(open_ctrl_t)); | |
69 | ctrlp->path = xstrdup(path); | |
70 | ctrlp->callback = callback; | |
71 | ctrlp->callback_data = callback_data; | |
090089c4 | 72 | |
b59c7120 | 73 | if (mode & O_WRONLY) |
74 | mode |= O_APPEND; | |
4f92c80c | 75 | mode |= SQUID_NONBLOCK; |
b59c7120 | 76 | |
090089c4 | 77 | /* Open file */ |
b6a2f15e | 78 | Opening_FD++; |
0a0bf5db | 79 | #if USE_ASYNC_IO |
f17936ab | 80 | if (callback != NULL) { |
ecefc661 | 81 | aioOpen(path, mode, 0644, fileOpenComplete, ctrlp, tag); |
9e4ad609 | 82 | return DISK_OK; |
0a0bf5db | 83 | } |
f17936ab | 84 | #endif |
b870e0b4 | 85 | errno = 0; |
0a0bf5db | 86 | fd = open(path, mode, 0644); |
ecefc661 | 87 | fileOpenComplete(-1, ctrlp, fd, errno); |
0a0bf5db | 88 | if (fd < 0) |
89 | return DISK_ERROR; | |
90 | return fd; | |
0a0bf5db | 91 | } |
92 | ||
93 | ||
94 | static void | |
ecefc661 | 95 | fileOpenComplete(int unused, void *data, int fd, int errcode) |
0a0bf5db | 96 | { |
97 | open_ctrl_t *ctrlp = (open_ctrl_t *) data; | |
701a8572 | 98 | debug(6, 5) ("fileOpenComplete: FD %d, data %p, errcode %d\n", |
ecefc661 | 99 | fd, data, errcode); |
886f2785 | 100 | Counter.syscalls.disk.opens++; |
b6a2f15e | 101 | Opening_FD--; |
0e473d70 | 102 | if (fd == -2 && errcode == -2) { /* Cancelled - clean up */ |
6cf028ab | 103 | if (ctrlp->callback) |
104 | (ctrlp->callback) (ctrlp->callback_data, fd, errcode); | |
105 | xfree(ctrlp->path); | |
106 | xfree(ctrlp); | |
107 | return; | |
108 | } | |
0a0bf5db | 109 | if (fd < 0) { |
110 | errno = errcode; | |
ecefc661 | 111 | debug(50, 3) ("fileOpenComplete: error opening file %s: %s\n", ctrlp->path, |
0a0bf5db | 112 | xstrerror()); |
113 | if (ctrlp->callback) | |
6cf028ab | 114 | (ctrlp->callback) (ctrlp->callback_data, DISK_ERROR, errcode); |
0a0bf5db | 115 | xfree(ctrlp->path); |
116 | xfree(ctrlp); | |
117 | return; | |
090089c4 | 118 | } |
ecefc661 | 119 | debug(6, 5) ("fileOpenComplete: FD %d\n", fd); |
3ca60c86 | 120 | commSetCloseOnExec(fd); |
5c5783a2 | 121 | fd_open(fd, FD_FILE, ctrlp->path); |
0a0bf5db | 122 | if (ctrlp->callback) |
6cf028ab | 123 | (ctrlp->callback) (ctrlp->callback_data, fd, errcode); |
0a0bf5db | 124 | xfree(ctrlp->path); |
125 | xfree(ctrlp); | |
126 | } | |
127 | ||
090089c4 | 128 | /* close a disk file. */ |
95d15928 | 129 | void |
b8d8561b | 130 | file_close(int fd) |
090089c4 | 131 | { |
76f87348 | 132 | fde *F = &fd_table[fd]; |
65d548bf | 133 | PF *callback; |
25354045 | 134 | #if USE_ASYNC_IO |
0e473d70 | 135 | if (fd < 0) { |
6cf028ab | 136 | debug(6, 0) ("file_close: FD less than zero: %d\n", fd); |
137 | return; | |
138 | } | |
25354045 | 139 | #else |
140 | assert(fd >= 0); | |
141 | #endif | |
60c0b5a2 | 142 | assert(F->flags.open); |
65d548bf | 143 | if ((callback = F->read_handler)) { |
144 | F->read_handler = NULL; | |
145 | callback(-1, F->read_data); | |
146 | } | |
0cd30ba5 | 147 | if (F->flags.write_daemon) { |
cd377065 | 148 | #if defined(_SQUID_MSWIN_) || defined(_SQUID_OS2_) |
149 | /* | |
150 | * on some operating systems, you can not delete or rename | |
151 | * open files, so we won't allow delayed close. | |
152 | */ | |
153 | while (!diskWriteIsComplete(fd)) | |
154 | diskHandleWrite(fd, NULL); | |
155 | #else | |
0cd30ba5 | 156 | F->flags.close_request = 1; |
66979cec | 157 | debug(6, 2) ("file_close: FD %d, delaying close\n", fd); |
95d15928 | 158 | return; |
cd377065 | 159 | #endif |
fb247d78 | 160 | } |
65d548bf | 161 | /* |
162 | * Assert there is no write callback. Otherwise we might be | |
163 | * leaking write state data by closing the descriptor | |
164 | */ | |
165 | assert(F->write_handler == NULL); | |
ddb43c58 | 166 | F->flags.closing = 1; |
0a0bf5db | 167 | #if USE_ASYNC_IO |
95d15928 | 168 | aioClose(fd); |
0a0bf5db | 169 | #else |
42f99d0d | 170 | #if CALL_FSYNC_BEFORE_CLOSE |
171 | fsync(fd); | |
172 | #endif | |
95d15928 | 173 | close(fd); |
0a0bf5db | 174 | #endif |
0cd30ba5 | 175 | debug(6, F->flags.close_request ? 2 : 5) |
5ac0b6e7 | 176 | ("file_close: FD %d, really closing\n", fd); |
ddb43c58 | 177 | #if !USE_ASYNC_IO |
6cf028ab | 178 | fd_close(fd); |
ddb43c58 | 179 | #endif |
886f2785 | 180 | Counter.syscalls.disk.closes++; |
090089c4 | 181 | } |
182 | ||
f02b8498 | 183 | /* |
184 | * This function has the purpose of combining multiple writes. This is | |
185 | * to facilitate the ASYNC_IO option since it can only guarantee 1 | |
186 | * write to a file per trip around the comm.c select() loop. That's bad | |
187 | * because more than 1 write can be made to the access.log file per | |
188 | * trip, and so this code is purely designed to help batch multiple | |
189 | * sequential writes to the access.log file. Squid will never issue | |
190 | * multiple writes for any other file type during 1 trip around the | |
191 | * select() loop. --SLF | |
192 | */ | |
582b6456 | 193 | static void |
f02b8498 | 194 | diskCombineWrites(struct _fde_disk *fdd) |
090089c4 | 195 | { |
4a86108c | 196 | int len = 0; |
0a0bf5db | 197 | dwrite_q *q = NULL; |
198 | dwrite_q *wq = NULL; | |
f02b8498 | 199 | /* |
200 | * We need to combine multiple write requests on an FD's write | |
201 | * queue But only if we don't need to seek() in between them, ugh! | |
202 | * XXX This currently ignores any seeks (file_offset) | |
203 | */ | |
204 | if (fdd->write_q != NULL && fdd->write_q->next != NULL) { | |
de866d20 | 205 | len = 0; |
f02b8498 | 206 | for (q = fdd->write_q; q != NULL; q = q->next) |
d377699f | 207 | len += q->len - q->buf_offset; |
0a0bf5db | 208 | wq = xcalloc(1, sizeof(dwrite_q)); |
209 | wq->buf = xmalloc(len); | |
210 | wq->len = 0; | |
d377699f | 211 | wq->buf_offset = 0; |
0a0bf5db | 212 | wq->next = NULL; |
ed7f0b6a | 213 | wq->free_func = xfree; |
0a0bf5db | 214 | do { |
f02b8498 | 215 | q = fdd->write_q; |
d377699f | 216 | len = q->len - q->buf_offset; |
217 | xmemcpy(wq->buf + wq->len, q->buf + q->buf_offset, len); | |
0a0bf5db | 218 | wq->len += len; |
f02b8498 | 219 | fdd->write_q = q->next; |
ed7f0b6a | 220 | if (q->free_func) |
221 | (q->free_func) (q->buf); | |
0a0bf5db | 222 | safe_free(q); |
f02b8498 | 223 | } while (fdd->write_q != NULL); |
de866d20 | 224 | fdd->write_q_tail = wq; |
f02b8498 | 225 | fdd->write_q = wq; |
0a0bf5db | 226 | } |
f02b8498 | 227 | } |
228 | ||
229 | /* write handler */ | |
230 | static void | |
231 | diskHandleWrite(int fd, void *notused) | |
232 | { | |
d1cbc844 | 233 | #if !USE_ASYNC_IO |
f02b8498 | 234 | int len = 0; |
d1cbc844 | 235 | #endif |
f02b8498 | 236 | fde *F = &fd_table[fd]; |
237 | struct _fde_disk *fdd = &F->disk; | |
238 | if (!fdd->write_q) | |
239 | return; | |
f02b8498 | 240 | debug(6, 3) ("diskHandleWrite: FD %d\n", fd); |
8350fe9b | 241 | assert(fdd->write_q != NULL); |
d377699f | 242 | assert(fdd->write_q->len > fdd->write_q->buf_offset); |
0a0bf5db | 243 | #if USE_ASYNC_IO |
244 | aioWrite(fd, | |
5999b776 | 245 | -1, /* seek offset, -1 == append */ |
d377699f | 246 | fdd->write_q->buf + fdd->write_q->buf_offset, |
247 | fdd->write_q->len - fdd->write_q->buf_offset, | |
0a0bf5db | 248 | diskHandleWriteComplete, |
ecefc661 | 249 | fdd->write_q); |
0a0bf5db | 250 | #else |
ba7b771e | 251 | debug(6, 3) ("diskHandleWrite: FD %d writing %d bytes\n", |
5f6ac48b | 252 | fd, (int) (fdd->write_q->len - fdd->write_q->buf_offset)); |
b870e0b4 | 253 | errno = 0; |
0a0bf5db | 254 | len = write(fd, |
d377699f | 255 | fdd->write_q->buf + fdd->write_q->buf_offset, |
256 | fdd->write_q->len - fdd->write_q->buf_offset); | |
d1cbc844 | 257 | diskHandleWriteComplete(fd, fdd->write_q, len, errno); |
0a0bf5db | 258 | #endif |
259 | } | |
260 | ||
de866d20 | 261 | static void |
ecefc661 | 262 | diskHandleWriteComplete(int fd, void *data, int len, int errcode) |
0a0bf5db | 263 | { |
76f87348 | 264 | fde *F = &fd_table[fd]; |
265 | struct _fde_disk *fdd = &F->disk; | |
de866d20 | 266 | dwrite_q *q = fdd->write_q; |
267 | int status = DISK_OK; | |
ba7b771e | 268 | int do_callback; |
68c21f71 | 269 | int do_close; |
0a0bf5db | 270 | errno = errcode; |
ba7b771e | 271 | debug(6, 3) ("diskHandleWriteComplete: FD %d len = %d\n", fd, len); |
886f2785 | 272 | Counter.syscalls.disk.writes++; |
f0027316 | 273 | #if USE_ASYNC_IO |
274 | /* | |
275 | * From: "Michael O'Reilly" <michael@metal.iinet.net.au> | |
276 | * Date: 24 Feb 1998 15:12:06 +0800 | |
277 | * | |
278 | * A small patch to improve the AIO sanity. the patch below makes sure | |
279 | * the write request really does match the data passed back from the | |
280 | * async IO call. note that I haven't actually rebooted with this | |
281 | * patch yet, so 'provisional' is an understatement. | |
282 | */ | |
ecefc661 | 283 | if (q && q != data) { |
284 | dwrite_q *p = data; | |
f0027316 | 285 | debug(50, 0) ("KARMA: q != data (%p, %p)\n", q, p); |
286 | debug(50, 0) ("KARMA: (%d, %d, %d FD %d)\n", | |
287 | q->buf_offset, q->len, len, fd); | |
288 | debug(50, 0) ("KARMA: desc %s, type %d, open %d, flags 0x%x\n", | |
98829dd0 | 289 | F->desc, F->type, F->flags.open, F->flags); |
f0027316 | 290 | debug(50, 0) ("KARMA: (%d, %d)\n", p->buf_offset, p->len); |
291 | len = -1; | |
292 | errcode = EFAULT; | |
293 | } | |
294 | #endif | |
de866d20 | 295 | if (q == NULL) /* Someone aborted then write completed */ |
296 | return; | |
6cf028ab | 297 | |
0e473d70 | 298 | if (len == -2 && errcode == -2) { /* Write cancelled - cleanup */ |
6cf028ab | 299 | do { |
300 | fdd->write_q = q->next; | |
ed7f0b6a | 301 | if (q->free_func) |
302 | (q->free_func) (q->buf); | |
6cf028ab | 303 | safe_free(q); |
304 | } while ((q = fdd->write_q)); | |
305 | return; | |
306 | } | |
6cf028ab | 307 | fd_bytes(fd, len, FD_WRITE); |
0a0bf5db | 308 | if (len < 0) { |
b224ea98 | 309 | if (!ignoreErrno(errno)) { |
de866d20 | 310 | status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR; |
a3d5953d | 311 | debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n", |
0c77d853 | 312 | fd, xstrerror()); |
25354045 | 313 | /* |
314 | * If there is no write callback, then this file is | |
315 | * most likely something important like a log file, or | |
316 | * an interprocess pipe. Its not a swapfile. We feel | |
317 | * that a write failure on a log file is rather important, | |
318 | * and Squid doesn't otherwise deal with this condition. | |
319 | * So to get the administrators attention, we exit with | |
320 | * a fatal message. | |
321 | */ | |
322 | if (fdd->wrt_handle == NULL) | |
323 | fatal("Write failure -- check your disk space and cache.log"); | |
324 | /* | |
325 | * If there is a write failure, then we notify the | |
326 | * upper layer via the callback, at the end of this | |
327 | * function. Meanwhile, flush all pending buffers | |
328 | * here. Let the upper layer decide how to handle the | |
329 | * failure. This will prevent experiencing multiple, | |
330 | * repeated write failures for the same FD because of | |
331 | * the queued data. | |
332 | */ | |
333 | do { | |
334 | fdd->write_q = q->next; | |
335 | if (q->free_func) | |
336 | (q->free_func) (q->buf); | |
337 | safe_free(q); | |
338 | } while ((q = fdd->write_q)); | |
0c77d853 | 339 | } |
de866d20 | 340 | len = 0; |
0a0bf5db | 341 | } |
8350fe9b | 342 | if (q != NULL) { |
343 | /* q might become NULL from write failure above */ | |
d377699f | 344 | q->buf_offset += len; |
6cf028ab | 345 | if (q->buf_offset > q->len) |
346 | debug(50, 1) ("diskHandleWriteComplete: q->buf_offset > q->len (%p,%d, %d, %d FD %d)\n", | |
5f6ac48b | 347 | q, (int) q->buf_offset, q->len, len, fd); |
d377699f | 348 | assert(q->buf_offset <= q->len); |
349 | if (q->buf_offset == q->len) { | |
56878878 | 350 | /* complete write */ |
351 | fdd->write_q = q->next; | |
ed7f0b6a | 352 | if (q->free_func) |
353 | (q->free_func) (q->buf); | |
56878878 | 354 | safe_free(q); |
355 | } | |
090089c4 | 356 | } |
de866d20 | 357 | if (fdd->write_q == NULL) { |
358 | /* no more data */ | |
359 | fdd->write_q_tail = NULL; | |
0cd30ba5 | 360 | F->flags.write_daemon = 0; |
de866d20 | 361 | } else { |
0a0bf5db | 362 | /* another block is queued */ |
f02b8498 | 363 | diskCombineWrites(fdd); |
25354045 | 364 | cbdataLock(fdd->wrt_handle_data); |
de866d20 | 365 | commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0); |
0cd30ba5 | 366 | F->flags.write_daemon = 1; |
4a86108c | 367 | } |
0cd30ba5 | 368 | do_close = F->flags.close_request; |
25354045 | 369 | if (fdd->wrt_handle) { |
ba7b771e | 370 | if (fdd->wrt_handle_data == NULL) |
371 | do_callback = 1; | |
372 | else if (cbdataValid(fdd->wrt_handle_data)) | |
373 | do_callback = 1; | |
374 | else | |
375 | do_callback = 0; | |
25354045 | 376 | if (fdd->wrt_handle_data != NULL) |
377 | cbdataUnlock(fdd->wrt_handle_data); | |
26720a7c | 378 | if (do_callback) { |
ba7b771e | 379 | fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data); |
26720a7c | 380 | /* |
381 | * NOTE, this callback can close the FD, so we must | |
382 | * not touch 'F', 'fdd', etc. after this. | |
383 | */ | |
384 | return; | |
385 | } | |
25354045 | 386 | } |
68c21f71 | 387 | if (do_close) |
b59c7120 | 388 | file_close(fd); |
090089c4 | 389 | } |
390 | ||
391 | ||
090089c4 | 392 | /* write block to a file */ |
393 | /* write back queue. Only one writer at a time. */ | |
394 | /* call a handle when writing is complete. */ | |
e3ef2b09 | 395 | void |
3ebcfaa1 | 396 | file_write(int fd, |
d377699f | 397 | off_t file_offset, |
5830cdb3 | 398 | void *ptr_to_buf, |
684c2720 | 399 | int len, |
d89d1fb6 | 400 | DWCB handle, |
684c2720 | 401 | void *handle_data, |
9e4ad609 | 402 | FREE * free_func) |
090089c4 | 403 | { |
c6ac7aae | 404 | dwrite_q *wq = NULL; |
48cc3fcf | 405 | fde *F = &fd_table[fd]; |
406 | assert(fd >= 0); | |
60c0b5a2 | 407 | assert(F->flags.open); |
090089c4 | 408 | /* if we got here. Caller is eligible to write. */ |
30a4f2a8 | 409 | wq = xcalloc(1, sizeof(dwrite_q)); |
d377699f | 410 | wq->file_offset = file_offset; |
090089c4 | 411 | wq->buf = ptr_to_buf; |
090089c4 | 412 | wq->len = len; |
d377699f | 413 | wq->buf_offset = 0; |
090089c4 | 414 | wq->next = NULL; |
ed7f0b6a | 415 | wq->free_func = free_func; |
76f87348 | 416 | F->disk.wrt_handle = handle; |
417 | F->disk.wrt_handle_data = handle_data; | |
090089c4 | 418 | /* add to queue */ |
48cc3fcf | 419 | if (F->disk.write_q == NULL) { |
090089c4 | 420 | /* empty queue */ |
76f87348 | 421 | F->disk.write_q = F->disk.write_q_tail = wq; |
090089c4 | 422 | } else { |
76f87348 | 423 | F->disk.write_q_tail->next = wq; |
424 | F->disk.write_q_tail = wq; | |
090089c4 | 425 | } |
0cd30ba5 | 426 | if (!F->flags.write_daemon) { |
25354045 | 427 | cbdataLock(F->disk.wrt_handle_data); |
0a0bf5db | 428 | #if USE_ASYNC_IO |
95d15928 | 429 | diskHandleWrite(fd, NULL); |
0a0bf5db | 430 | #else |
e82d6d21 | 431 | commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0); |
9d66d521 | 432 | #endif |
0cd30ba5 | 433 | F->flags.write_daemon = 1; |
429fdbec | 434 | } |
090089c4 | 435 | } |
436 | ||
23b2b404 | 437 | /* |
438 | * a wrapper around file_write to allow for MemBuf to be file_written | |
439 | * in a snap | |
440 | */ | |
137ee196 | 441 | void |
442 | file_write_mbuf(int fd, off_t off, MemBuf mb, DWCB * handler, void *handler_data) | |
443 | { | |
444 | file_write(fd, off, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb)); | |
445 | } | |
090089c4 | 446 | |
447 | /* Read from FD */ | |
582b6456 | 448 | static void |
449 | diskHandleRead(int fd, void *data) | |
090089c4 | 450 | { |
582b6456 | 451 | dread_ctrl *ctrl_dat = data; |
606bd3b5 | 452 | #if !USE_ASYNC_IO |
edd2eb63 | 453 | fde *F = &fd_table[fd]; |
090089c4 | 454 | int len; |
606bd3b5 | 455 | #endif |
65d548bf | 456 | /* |
457 | * FD < 0 indicates premature close; we just have to free | |
458 | * the state data. | |
459 | */ | |
460 | if (fd < 0) { | |
db1cd23c | 461 | memFree(ctrl_dat, MEM_DREAD_CTRL); |
65d548bf | 462 | return; |
463 | } | |
0a0bf5db | 464 | #if USE_ASYNC_IO |
465 | aioRead(fd, | |
20f92343 | 466 | ctrl_dat->offset, |
711982d8 | 467 | ctrl_dat->buf, |
468 | ctrl_dat->req_len, | |
0a0bf5db | 469 | diskHandleReadComplete, |
23b2b404 | 470 | ctrl_dat); |
0a0bf5db | 471 | #else |
711982d8 | 472 | if (F->disk.offset != ctrl_dat->offset) { |
f2b30883 | 473 | debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n", |
343c257b | 474 | fd, (int) ctrl_dat->offset); |
711982d8 | 475 | lseek(fd, ctrl_dat->offset, SEEK_SET); /* XXX ignore return? */ |
886f2785 | 476 | Counter.syscalls.disk.seeks++; |
556c33d5 | 477 | F->disk.offset = ctrl_dat->offset; |
711982d8 | 478 | } |
b870e0b4 | 479 | errno = 0; |
711982d8 | 480 | len = read(fd, ctrl_dat->buf, ctrl_dat->req_len); |
015b507a | 481 | if (len > 0) |
e82d6d21 | 482 | F->disk.offset += len; |
ecefc661 | 483 | diskHandleReadComplete(fd, ctrl_dat, len, errno); |
090089c4 | 484 | #endif |
0a0bf5db | 485 | } |
486 | ||
de866d20 | 487 | static void |
ecefc661 | 488 | diskHandleReadComplete(int fd, void *data, int len, int errcode) |
0a0bf5db | 489 | { |
23b2b404 | 490 | dread_ctrl *ctrl_dat = data; |
901a2a3c | 491 | int rc = DISK_OK; |
886f2785 | 492 | Counter.syscalls.disk.reads++; |
0a0bf5db | 493 | errno = errcode; |
0e473d70 | 494 | if (len == -2 && errcode == -2) { /* Read cancelled - cleanup */ |
6cf028ab | 495 | cbdataUnlock(ctrl_dat->client_data); |
db1cd23c | 496 | memFree(ctrl_dat, MEM_DREAD_CTRL); |
6cf028ab | 497 | return; |
498 | } | |
4f92c80c | 499 | fd_bytes(fd, len, FD_READ); |
0a0bf5db | 500 | if (len < 0) { |
b224ea98 | 501 | if (ignoreErrno(errno)) { |
901a2a3c | 502 | commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0); |
de866d20 | 503 | return; |
0a0bf5db | 504 | } |
901a2a3c | 505 | debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror()); |
506 | len = 0; | |
507 | rc = DISK_ERROR; | |
090089c4 | 508 | } else if (len == 0) { |
901a2a3c | 509 | rc = DISK_EOF; |
090089c4 | 510 | } |
901a2a3c | 511 | if (cbdataValid(ctrl_dat->client_data)) |
5d86029a | 512 | ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data); |
901a2a3c | 513 | cbdataUnlock(ctrl_dat->client_data); |
db1cd23c | 514 | memFree(ctrl_dat, MEM_DREAD_CTRL); |
090089c4 | 515 | } |
516 | ||
517 | ||
518 | /* start read operation */ | |
519 | /* buffer must be allocated from the caller. | |
520 | * It must have at least req_len space in there. | |
521 | * call handler when a reading is complete. */ | |
b8d8561b | 522 | int |
d377699f | 523 | file_read(int fd, char *buf, int req_len, off_t offset, DRCB * handler, void *client_data) |
090089c4 | 524 | { |
525 | dread_ctrl *ctrl_dat; | |
711982d8 | 526 | assert(fd >= 0); |
0a5bc521 | 527 | ctrl_dat = memAllocate(MEM_DREAD_CTRL); |
090089c4 | 528 | ctrl_dat->fd = fd; |
529 | ctrl_dat->offset = offset; | |
530 | ctrl_dat->req_len = req_len; | |
531 | ctrl_dat->buf = buf; | |
090089c4 | 532 | ctrl_dat->end_of_file = 0; |
533 | ctrl_dat->handler = handler; | |
534 | ctrl_dat->client_data = client_data; | |
901a2a3c | 535 | cbdataLock(client_data); |
0a0bf5db | 536 | #if USE_ASYNC_IO |
537 | diskHandleRead(fd, ctrl_dat); | |
538 | #else | |
b177367b | 539 | commSetSelect(fd, |
234967c9 | 540 | COMM_SELECT_READ, |
cd1fb0eb | 541 | diskHandleRead, |
542 | ctrl_dat, | |
b177367b | 543 | 0); |
0a0bf5db | 544 | #endif |
090089c4 | 545 | return DISK_OK; |
546 | } | |
547 | ||
b8d8561b | 548 | int |
549 | diskWriteIsComplete(int fd) | |
b59c7120 | 550 | { |
95d15928 | 551 | return fd_table[fd].disk.write_q ? 0 : 1; |
0a21bd84 | 552 | } |