]>
Commit | Line | Data |
---|---|---|
30a4f2a8 | 1 | /* |
f2b30883 | 2 | * $Id: disk.cc,v 1.93 1997/11/12 00:10:45 wessels Exp $ |
30a4f2a8 | 3 | * |
4 | * DEBUG: section 6 Disk I/O Routines | |
5 | * AUTHOR: Harvest Derived | |
6 | * | |
42c04c16 | 7 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 8 | * -------------------------------------------------------- |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from the | |
11 | * Internet community. Development is led by Duane Wessels of the | |
12 | * National Laboratory for Applied Network Research and funded by | |
13 | * the National Science Foundation. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2 of the License, or | |
18 | * (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
29 | */ | |
30 | ||
31 | /* | |
32 | * Copyright (c) 1994, 1995. All rights reserved. | |
33 | * | |
34 | * The Harvest software was developed by the Internet Research Task | |
35 | * Force Research Group on Resource Discovery (IRTF-RD): | |
36 | * | |
37 | * Mic Bowman of Transarc Corporation. | |
38 | * Peter Danzig of the University of Southern California. | |
39 | * Darren R. Hardy of the University of Colorado at Boulder. | |
40 | * Udi Manber of the University of Arizona. | |
41 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
42 | * Duane Wessels of the University of Colorado at Boulder. | |
43 | * | |
44 | * This copyright notice applies to software in the Harvest | |
45 | * ``src/'' directory only. Users should consult the individual | |
46 | * copyright notices in the ``components/'' subdirectories for | |
47 | * copyright information about other software bundled with the | |
48 | * Harvest source code distribution. | |
49 | * | |
50 | * TERMS OF USE | |
51 | * | |
52 | * The Harvest software may be used and re-distributed without | |
53 | * charge, provided that the software origin and research team are | |
54 | * cited in any use of the system. Most commonly this is | |
55 | * accomplished by including a link to the Harvest Home Page | |
56 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
57 | * Broker you deploy, as well as in the query result pages. These | |
58 | * links are generated automatically by the standard Broker | |
59 | * software distribution. | |
60 | * | |
61 | * The Harvest software is provided ``as is'', without express or | |
62 | * implied warranty, and with no support nor obligation to assist | |
63 | * in its use, correction, modification or enhancement. We assume | |
64 | * no liability with respect to the infringement of copyrights, | |
65 | * trade secrets, or any patents, and are not responsible for | |
66 | * consequential damages. Proper use of the Harvest software is | |
67 | * entirely the responsibility of the user. | |
68 | * | |
69 | * DERIVATIVE WORKS | |
70 | * | |
71 | * Users may make derivative works from the Harvest software, subject | |
72 | * to the following constraints: | |
73 | * | |
74 | * - You must include the above copyright notice and these | |
75 | * accompanying paragraphs in all forms of derivative works, | |
76 | * and any documentation and other materials related to such | |
77 | * distribution and use acknowledge that the software was | |
78 | * developed at the above institutions. | |
79 | * | |
80 | * - You must notify IRTF-RD regarding your distribution of | |
81 | * the derivative work. | |
82 | * | |
83 | * - You must clearly notify users that your are distributing | |
84 | * a modified version and not the original Harvest software. | |
85 | * | |
86 | * - Any derivative product is also subject to these copyright | |
87 | * and use restrictions. | |
88 | * | |
89 | * Note that the Harvest software is NOT in the public domain. We | |
90 | * retain copyright, as specified above. | |
91 | * | |
92 | * HISTORY OF FREE SOFTWARE STATUS | |
93 | * | |
94 | * Originally we required sites to license the software in cases | |
95 | * where they were going to build commercial products/services | |
96 | * around Harvest. In June 1995 we changed this policy. We now | |
97 | * allow people to use the core Harvest software (the code found in | |
98 | * the Harvest ``src/'' directory) for free. We made this change | |
99 | * in the interest of encouraging the widest possible deployment of | |
100 | * the technology. The Harvest software is really a reference | |
101 | * implementation of a set of protocols and formats, some of which | |
102 | * we intend to standardize. We encourage commercial | |
103 | * re-implementations of code complying to this set of standards. | |
104 | */ | |
ed43818f | 105 | |
44a47c6e | 106 | #include "squid.h" |
090089c4 | 107 | |
108 | #define DISK_LINE_LEN 1024 | |
090089c4 | 109 | |
0a0bf5db | 110 | typedef struct disk_ctrl_t { |
111 | int fd; | |
112 | void *data; | |
113 | } disk_ctrl_t; | |
114 | ||
115 | ||
116 | typedef struct open_ctrl_t { | |
f17936ab | 117 | FOCB *callback; |
0a0bf5db | 118 | void *callback_data; |
119 | char *path; | |
120 | } open_ctrl_t; | |
121 | ||
de866d20 | 122 | static AIOCB diskHandleWriteComplete; |
123 | static AIOCB diskHandleReadComplete; | |
95d15928 | 124 | static PF diskHandleRead; |
125 | static PF diskHandleWrite; | |
f5b8bbc4 | 126 | static void file_open_complete(void *, int, int); |
24382924 | 127 | |
090089c4 | 128 | /* initialize table */ |
b8d8561b | 129 | int |
0673c0ba | 130 | disk_init(void) |
090089c4 | 131 | { |
090089c4 | 132 | return 0; |
133 | } | |
134 | ||
135 | /* Open a disk file. Return a file descriptor */ | |
684c2720 | 136 | int |
9e4ad609 | 137 | file_open(const char *path, int mode, FOCB * callback, void *callback_data) |
090089c4 | 138 | { |
090089c4 | 139 | int fd; |
0a0bf5db | 140 | open_ctrl_t *ctrlp; |
141 | ||
142 | ctrlp = xmalloc(sizeof(open_ctrl_t)); | |
143 | ctrlp->path = xstrdup(path); | |
144 | ctrlp->callback = callback; | |
145 | ctrlp->callback_data = callback_data; | |
090089c4 | 146 | |
b59c7120 | 147 | if (mode & O_WRONLY) |
148 | mode |= O_APPEND; | |
4f92c80c | 149 | mode |= SQUID_NONBLOCK; |
b59c7120 | 150 | |
090089c4 | 151 | /* Open file */ |
0a0bf5db | 152 | #if USE_ASYNC_IO |
f17936ab | 153 | if (callback != NULL) { |
9e4ad609 | 154 | aioOpen(path, mode, 0644, file_open_complete, ctrlp); |
155 | return DISK_OK; | |
0a0bf5db | 156 | } |
f17936ab | 157 | #endif |
0a0bf5db | 158 | fd = open(path, mode, 0644); |
159 | file_open_complete(ctrlp, fd, errno); | |
160 | if (fd < 0) | |
161 | return DISK_ERROR; | |
162 | return fd; | |
0a0bf5db | 163 | } |
164 | ||
165 | ||
166 | static void | |
95d15928 | 167 | file_open_complete(void *data, int fd, int errcode) |
0a0bf5db | 168 | { |
169 | open_ctrl_t *ctrlp = (open_ctrl_t *) data; | |
0a0bf5db | 170 | if (fd < 0) { |
171 | errno = errcode; | |
a3d5953d | 172 | debug(50, 0) ("file_open: error opening file %s: %s\n", ctrlp->path, |
0a0bf5db | 173 | xstrerror()); |
174 | if (ctrlp->callback) | |
175 | (ctrlp->callback) (ctrlp->callback_data, DISK_ERROR); | |
176 | xfree(ctrlp->path); | |
177 | xfree(ctrlp); | |
178 | return; | |
090089c4 | 179 | } |
365e5b34 | 180 | debug(6, 5) ("file_open: FD %d\n", fd); |
3ca60c86 | 181 | commSetCloseOnExec(fd); |
5c5783a2 | 182 | fd_open(fd, FD_FILE, ctrlp->path); |
0a0bf5db | 183 | if (ctrlp->callback) |
184 | (ctrlp->callback) (ctrlp->callback_data, fd); | |
185 | xfree(ctrlp->path); | |
186 | xfree(ctrlp); | |
187 | } | |
188 | ||
090089c4 | 189 | /* close a disk file. */ |
95d15928 | 190 | void |
b8d8561b | 191 | file_close(int fd) |
090089c4 | 192 | { |
76f87348 | 193 | fde *F = &fd_table[fd]; |
f88211e8 | 194 | assert(fd >= 0); |
76f87348 | 195 | assert(F->open); |
79a15e0a | 196 | if (EBIT_TEST(F->flags, FD_WRITE_DAEMON)) { |
197 | EBIT_SET(F->flags, FD_CLOSE_REQUEST); | |
95d15928 | 198 | return; |
fb247d78 | 199 | } |
79a15e0a | 200 | if (EBIT_TEST(F->flags, FD_WRITE_PENDING)) { |
201 | EBIT_SET(F->flags, FD_CLOSE_REQUEST); | |
95d15928 | 202 | return; |
203 | } | |
5c5783a2 | 204 | fd_close(fd); |
365e5b34 | 205 | debug(6, 5) ("file_close: FD %d\n", fd); |
0a0bf5db | 206 | #if USE_ASYNC_IO |
95d15928 | 207 | aioClose(fd); |
0a0bf5db | 208 | #else |
95d15928 | 209 | close(fd); |
0a0bf5db | 210 | #endif |
090089c4 | 211 | } |
212 | ||
090089c4 | 213 | |
214 | /* write handler */ | |
582b6456 | 215 | static void |
79d39a72 | 216 | diskHandleWrite(int fd, void *notused) |
090089c4 | 217 | { |
4a86108c | 218 | int len = 0; |
0a0bf5db | 219 | disk_ctrl_t *ctrlp; |
220 | dwrite_q *q = NULL; | |
221 | dwrite_q *wq = NULL; | |
76f87348 | 222 | fde *F = &fd_table[fd]; |
223 | struct _fde_disk *fdd = &F->disk; | |
de866d20 | 224 | if (!fdd->write_q) |
582b6456 | 225 | return; |
0a0bf5db | 226 | /* We need to combine subsequent write requests after the first */ |
de866d20 | 227 | if (fdd->write_q->next != NULL && fdd->write_q->next->next != NULL) { |
228 | len = 0; | |
229 | for (q = fdd->write_q->next; q != NULL; q = q->next) | |
0a0bf5db | 230 | len += q->len - q->cur_offset; |
231 | wq = xcalloc(1, sizeof(dwrite_q)); | |
232 | wq->buf = xmalloc(len); | |
233 | wq->len = 0; | |
234 | wq->cur_offset = 0; | |
235 | wq->next = NULL; | |
236 | wq->free = xfree; | |
237 | do { | |
de866d20 | 238 | q = fdd->write_q->next; |
0a0bf5db | 239 | len = q->len - q->cur_offset; |
de866d20 | 240 | xmemcpy(wq->buf + wq->len, q->buf + q->cur_offset, len); |
0a0bf5db | 241 | wq->len += len; |
de866d20 | 242 | fdd->write_q->next = q->next; |
0a0bf5db | 243 | if (q->free) |
244 | (q->free) (q->buf); | |
245 | safe_free(q); | |
de866d20 | 246 | } while (fdd->write_q->next != NULL); |
247 | fdd->write_q_tail = wq; | |
248 | fdd->write_q->next = wq; | |
0a0bf5db | 249 | } |
250 | ctrlp = xcalloc(1, sizeof(disk_ctrl_t)); | |
251 | ctrlp->fd = fd; | |
8350fe9b | 252 | assert(fdd->write_q != NULL); |
253 | assert(fdd->write_q->len > fdd->write_q->cur_offset); | |
0a0bf5db | 254 | #if USE_ASYNC_IO |
255 | aioWrite(fd, | |
de866d20 | 256 | fdd->write_q->buf + fdd->write_q->cur_offset, |
257 | fdd->write_q->len - fdd->write_q->cur_offset, | |
0a0bf5db | 258 | diskHandleWriteComplete, |
cd1fb0eb | 259 | ctrlp); |
0a0bf5db | 260 | #else |
261 | len = write(fd, | |
de866d20 | 262 | fdd->write_q->buf + fdd->write_q->cur_offset, |
263 | fdd->write_q->len - fdd->write_q->cur_offset); | |
582b6456 | 264 | diskHandleWriteComplete(ctrlp, len, errno); |
0a0bf5db | 265 | #endif |
266 | } | |
267 | ||
de866d20 | 268 | static void |
b69f7771 | 269 | diskHandleWriteComplete(void *data, int len, int errcode) |
0a0bf5db | 270 | { |
271 | disk_ctrl_t *ctrlp = data; | |
0a0bf5db | 272 | int fd = ctrlp->fd; |
76f87348 | 273 | fde *F = &fd_table[fd]; |
274 | struct _fde_disk *fdd = &F->disk; | |
de866d20 | 275 | dwrite_q *q = fdd->write_q; |
276 | int status = DISK_OK; | |
0a0bf5db | 277 | errno = errcode; |
278 | safe_free(data); | |
b69f7771 | 279 | fd_bytes(fd, len, FD_WRITE); |
de866d20 | 280 | if (q == NULL) /* Someone aborted then write completed */ |
281 | return; | |
0a0bf5db | 282 | if (len < 0) { |
283 | if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { | |
de866d20 | 284 | (void) 0; |
0a0bf5db | 285 | } else { |
de866d20 | 286 | status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR; |
a3d5953d | 287 | debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n", |
0c77d853 | 288 | fd, xstrerror()); |
de866d20 | 289 | if (fdd->wrt_handle == NULL) { |
290 | /* FLUSH PENDING BUFFERS */ | |
291 | do { | |
292 | fdd->write_q = q->next; | |
293 | if (q->free) | |
294 | (q->free) (q->buf); | |
295 | safe_free(q); | |
296 | } while ((q = fdd->write_q)); | |
090089c4 | 297 | } |
0c77d853 | 298 | } |
de866d20 | 299 | len = 0; |
0a0bf5db | 300 | } |
8350fe9b | 301 | if (q != NULL) { |
302 | /* q might become NULL from write failure above */ | |
56878878 | 303 | q->cur_offset += len; |
304 | assert(q->cur_offset <= q->len); | |
305 | if (q->cur_offset == q->len) { | |
306 | /* complete write */ | |
307 | fdd->write_q = q->next; | |
308 | if (q->free) | |
309 | (q->free) (q->buf); | |
310 | safe_free(q); | |
311 | } | |
090089c4 | 312 | } |
de866d20 | 313 | if (fdd->write_q == NULL) { |
314 | /* no more data */ | |
315 | fdd->write_q_tail = NULL; | |
79a15e0a | 316 | EBIT_CLR(F->flags, FD_WRITE_PENDING); |
317 | EBIT_CLR(F->flags, FD_WRITE_DAEMON); | |
de866d20 | 318 | } else { |
0a0bf5db | 319 | /* another block is queued */ |
de866d20 | 320 | commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0); |
79a15e0a | 321 | EBIT_SET(F->flags, FD_WRITE_DAEMON); |
4a86108c | 322 | } |
de866d20 | 323 | if (fdd->wrt_handle) |
d89d1fb6 | 324 | fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data); |
79a15e0a | 325 | if (EBIT_TEST(F->flags, FD_CLOSE_REQUEST)) |
b59c7120 | 326 | file_close(fd); |
090089c4 | 327 | } |
328 | ||
329 | ||
090089c4 | 330 | /* write block to a file */ |
331 | /* write back queue. Only one writer at a time. */ | |
332 | /* call a handle when writing is complete. */ | |
b8d8561b | 333 | int |
3ebcfaa1 | 334 | file_write(int fd, |
684c2720 | 335 | char *ptr_to_buf, |
336 | int len, | |
d89d1fb6 | 337 | DWCB handle, |
684c2720 | 338 | void *handle_data, |
9e4ad609 | 339 | FREE * free_func) |
090089c4 | 340 | { |
c6ac7aae | 341 | dwrite_q *wq = NULL; |
48cc3fcf | 342 | fde *F = &fd_table[fd]; |
343 | assert(fd >= 0); | |
344 | assert(F->open); | |
090089c4 | 345 | /* if we got here. Caller is eligible to write. */ |
30a4f2a8 | 346 | wq = xcalloc(1, sizeof(dwrite_q)); |
090089c4 | 347 | wq->buf = ptr_to_buf; |
090089c4 | 348 | wq->len = len; |
349 | wq->cur_offset = 0; | |
350 | wq->next = NULL; | |
86ee2017 | 351 | wq->free = free_func; |
76f87348 | 352 | F->disk.wrt_handle = handle; |
353 | F->disk.wrt_handle_data = handle_data; | |
090089c4 | 354 | /* add to queue */ |
79a15e0a | 355 | EBIT_SET(F->flags, FD_WRITE_PENDING); |
48cc3fcf | 356 | if (F->disk.write_q == NULL) { |
090089c4 | 357 | /* empty queue */ |
76f87348 | 358 | F->disk.write_q = F->disk.write_q_tail = wq; |
090089c4 | 359 | } else { |
76f87348 | 360 | F->disk.write_q_tail->next = wq; |
361 | F->disk.write_q_tail = wq; | |
090089c4 | 362 | } |
79a15e0a | 363 | if (!EBIT_TEST(F->flags, FD_WRITE_DAEMON)) { |
0a0bf5db | 364 | #if USE_ASYNC_IO |
95d15928 | 365 | diskHandleWrite(fd, NULL); |
0a0bf5db | 366 | #else |
95d15928 | 367 | commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0); |
0a0bf5db | 368 | #endif |
79a15e0a | 369 | EBIT_SET(F->flags, FD_WRITE_DAEMON); |
429fdbec | 370 | } |
090089c4 | 371 | return DISK_OK; |
372 | } | |
373 | ||
374 | ||
375 | ||
376 | /* Read from FD */ | |
582b6456 | 377 | static void |
378 | diskHandleRead(int fd, void *data) | |
090089c4 | 379 | { |
582b6456 | 380 | dread_ctrl *ctrl_dat = data; |
711982d8 | 381 | fde *F = &fd_table[fd]; |
606bd3b5 | 382 | #if !USE_ASYNC_IO |
090089c4 | 383 | int len; |
606bd3b5 | 384 | #endif |
385 | disk_ctrl_t *ctrlp = xcalloc(1, sizeof(disk_ctrl_t)); | |
0a0bf5db | 386 | ctrlp->fd = fd; |
cd1fb0eb | 387 | ctrlp->data = ctrl_dat; |
0a0bf5db | 388 | #if USE_ASYNC_IO |
389 | aioRead(fd, | |
711982d8 | 390 | ctrl_dat->buf, |
391 | ctrl_dat->req_len, | |
0a0bf5db | 392 | diskHandleReadComplete, |
cd1fb0eb | 393 | ctrlp); |
0a0bf5db | 394 | #else |
711982d8 | 395 | if (F->disk.offset != ctrl_dat->offset) { |
f2b30883 | 396 | debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n", |
343c257b | 397 | fd, (int) ctrl_dat->offset); |
711982d8 | 398 | lseek(fd, ctrl_dat->offset, SEEK_SET); /* XXX ignore return? */ |
556c33d5 | 399 | F->disk.offset = ctrl_dat->offset; |
711982d8 | 400 | } |
401 | len = read(fd, ctrl_dat->buf, ctrl_dat->req_len); | |
402 | F->disk.offset += len; | |
582b6456 | 403 | diskHandleReadComplete(ctrlp, len, errno); |
090089c4 | 404 | #endif |
0a0bf5db | 405 | } |
406 | ||
de866d20 | 407 | static void |
4f92c80c | 408 | diskHandleReadComplete(void *data, int len, int errcode) |
0a0bf5db | 409 | { |
410 | disk_ctrl_t *ctrlp = data; | |
411 | dread_ctrl *ctrl_dat = ctrlp->data; | |
412 | int fd = ctrlp->fd; | |
901a2a3c | 413 | int rc = DISK_OK; |
0a0bf5db | 414 | errno = errcode; |
415 | xfree(data); | |
4f92c80c | 416 | fd_bytes(fd, len, FD_READ); |
0a0bf5db | 417 | if (len < 0) { |
418 | if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { | |
901a2a3c | 419 | commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0); |
de866d20 | 420 | return; |
0a0bf5db | 421 | } |
901a2a3c | 422 | debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror()); |
423 | len = 0; | |
424 | rc = DISK_ERROR; | |
090089c4 | 425 | } else if (len == 0) { |
901a2a3c | 426 | rc = DISK_EOF; |
090089c4 | 427 | } |
901a2a3c | 428 | if (cbdataValid(ctrl_dat->client_data)) |
5d86029a | 429 | ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data); |
901a2a3c | 430 | cbdataUnlock(ctrl_dat->client_data); |
6a54c60e | 431 | safe_free(ctrl_dat); |
090089c4 | 432 | } |
433 | ||
434 | ||
435 | /* start read operation */ | |
436 | /* buffer must be allocated from the caller. | |
437 | * It must have at least req_len space in there. | |
438 | * call handler when a reading is complete. */ | |
b8d8561b | 439 | int |
d89d1fb6 | 440 | file_read(int fd, char *buf, int req_len, int offset, DRCB * handler, void *client_data) |
090089c4 | 441 | { |
442 | dread_ctrl *ctrl_dat; | |
711982d8 | 443 | assert(fd >= 0); |
30a4f2a8 | 444 | ctrl_dat = xcalloc(1, sizeof(dread_ctrl)); |
090089c4 | 445 | ctrl_dat->fd = fd; |
446 | ctrl_dat->offset = offset; | |
447 | ctrl_dat->req_len = req_len; | |
448 | ctrl_dat->buf = buf; | |
090089c4 | 449 | ctrl_dat->end_of_file = 0; |
450 | ctrl_dat->handler = handler; | |
451 | ctrl_dat->client_data = client_data; | |
901a2a3c | 452 | cbdataLock(client_data); |
0a0bf5db | 453 | #if USE_ASYNC_IO |
454 | diskHandleRead(fd, ctrl_dat); | |
455 | #else | |
b177367b | 456 | commSetSelect(fd, |
234967c9 | 457 | COMM_SELECT_READ, |
cd1fb0eb | 458 | diskHandleRead, |
459 | ctrl_dat, | |
b177367b | 460 | 0); |
0a0bf5db | 461 | #endif |
090089c4 | 462 | return DISK_OK; |
463 | } | |
464 | ||
b8d8561b | 465 | int |
466 | diskWriteIsComplete(int fd) | |
b59c7120 | 467 | { |
95d15928 | 468 | return fd_table[fd].disk.write_q ? 0 : 1; |
0a21bd84 | 469 | } |