disk.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:16k
源码类别:

代理服务器

开发平台:

Unix_Linux

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