]> git.ipfire.org Git - thirdparty/squid.git/blob - src/fs/ufs/store_io_ufs.cc
Summary: Merge epoll and delay pools/deferred reads removal.
[thirdparty/squid.git] / src / fs / ufs / store_io_ufs.cc
1
2 /*
3 * $Id: store_io_ufs.cc,v 1.18 2003/03/04 01:40:57 robertc Exp $
4 *
5 * DEBUG: section 79 Storage Manager UFS Interface
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "store_ufs.h"
38 #include "Store.h"
39 #include "ufscommon.h"
40
41 #include "SwapDir.h"
42
43 UfsIO UfsIO::Instance;
44 bool
45 UfsIO::shedLoad()
46 {
47 return false;
48 }
49
50 void
51 UfsIO::deleteSelf() const
52 {
53 /* Do nothing, we use a single instance */
54 }
55
56 StoreIOState::Pointer
57 UfsIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
58 {
59 return new ufsstate_t (SD, e, callback, callback_data);
60 }
61
62 DiskFile::Pointer
63 UfsIO::newFile (char const *path)
64 {
65 return new UFSFile (path);
66 }
67
68 CBDATA_CLASS_INIT(ufsstate_t);
69
70 void *
71 ufsstate_t::operator new (size_t)
72 {
73 CBDATA_INIT_TYPE(ufsstate_t);
74 ufsstate_t *result = cbdataAlloc(ufsstate_t);
75 /* Mark result as being owned - we want the refcounter to do the delete
76 * call */
77 cbdataReference(result);
78 return result;
79 }
80
81 void
82 ufsstate_t::operator delete (void *address)
83 {
84 ufsstate_t *t = static_cast<ufsstate_t *>(address);
85 cbdataFree(address);
86 /* And allow the memory to be freed */
87 cbdataReferenceDone (t);
88 }
89
90 ufsstate_t::ufsstate_t(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void *callback_data_)
91 {
92 swap_filen = anEntry->swap_filen;
93 swap_dirn = SD->index;
94 mode = O_BINARY;
95 callback = callback_;
96 callback_data = cbdataReference(callback_data_);
97 e = anEntry;
98 }
99
100 CBDATA_CLASS_INIT(UFSFile);
101 void *
102 UFSFile::operator new (size_t)
103 {
104 CBDATA_INIT_TYPE(UFSFile);
105 UFSFile *result = cbdataAlloc(UFSFile);
106 /* Mark result as being owned - we want the refcounter to do the delete
107 * call */
108 cbdataReference(result);
109 return result;
110 }
111
112 void
113 UFSFile::operator delete (void *address)
114 {
115 UFSFile *t = static_cast<UFSFile *>(address);
116 cbdataFree(address);
117 /* And allow the memory to be freed */
118 cbdataReferenceDone (t);
119 }
120
121 void
122 UFSFile::deleteSelf() const {delete this;}
123
124 UFSFile::UFSFile (char const *aPath) : fd (-1)
125 {
126 assert (aPath);
127 debug (79,3)("UFSFile::UFSFile: %s\n", aPath);
128 path_ = xstrdup (aPath);
129 }
130
131 UFSFile::~UFSFile()
132 {
133 safe_free (path_);
134 doClose();
135 }
136
137 void
138 UFSFile::open (int flags, mode_t mode, IORequestor::Pointer callback)
139 {
140 /* Simulate async calls */
141 fd = file_open(path_ , flags);
142 ioRequestor = callback;
143
144 if (fd < 0) {
145 debug(79, 3) ("UFSFile::open: got failure (%d)\n", errno);
146 } else {
147 store_open_disk_fd++;
148 debug(79, 3) ("UFSFile::open: opened FD %d\n", fd);
149 }
150
151 callback->ioCompletedNotification();
152 }
153
154 void
155 UFSFile::create (int flags, mode_t mode, IORequestor::Pointer callback)
156 {
157 /* We use the same logic path for open */
158 open(flags, mode, callback);
159 }
160
161
162 void UFSFile::doClose()
163 {
164 if (fd > -1) {
165 file_close(fd);
166 store_open_disk_fd--;
167 fd = -1;
168 }
169 }
170
171 void
172 UFSFile::close ()
173 {
174 debug (79,3)("UFSFile::close: %p closing for %p\n", this, ioRequestor.getRaw());
175 doClose();
176 assert (ioRequestor.getRaw());
177 ioRequestor->closeCompleted();
178 }
179
180 bool
181 UFSFile::canRead() const
182 {
183 return fd > -1;
184 }
185
186 bool
187 UFSFile::error() const
188 {
189 if (fd < 0)
190 return true;
191
192 return false;
193 }
194
195 void
196 ufsstate_t::ioCompletedNotification()
197 {
198 if (opening) {
199 opening = false;
200 /* There is no 'opened' callback */
201 return;
202 }
203
204 if (creating) {
205 creating = false;
206 return;
207 }
208
209 assert(0);
210 }
211
212 void
213 ufsstate_t::closeCompleted()
214 {
215 doCallback(theFile->error() ? 0 : -1);
216 }
217
218 void
219 ufsstate_t::close()
220 {
221 debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X\n",
222 swap_dirn, swap_filen);
223 closing = true;
224
225 if (!(reading || writing)) {
226 ((UFSFile *)theFile.getRaw())->close();
227 }
228 }
229
230 void
231 UFSStoreState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
232 {
233 assert(read.callback == NULL);
234 assert(read.callback_data == NULL);
235 assert(!reading);
236 assert(!closing);
237 assert (callback);
238
239 if (!theFile->canRead()) {
240 debug(79, 3) ("UFSStoreState::read_: queueing read because theFile can't read\n");
241 queueRead (buf, size, offset, callback, callback_data);
242 return;
243 }
244
245 read.callback = callback;
246 read.callback_data = cbdataReference(callback_data);
247 debug(79, 3) ("UFSStoreState::read_: dirno %d, fileno %08X\n",
248 swap_dirn, swap_filen);
249 offset_ = offset;
250 read_buf = buf;
251 reading = true;
252 theFile->read(buf, offset, size);
253 }
254
255 void
256 UFSFile::read(char *buf, off_t offset, size_t size)
257 {
258 assert (fd > -1);
259 assert (ioRequestor.getRaw());
260 file_read(fd, buf, size, offset, ReadDone, this);
261 }
262
263 void
264 UFSFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
265 {
266 UFSFile *myFile = static_cast<UFSFile *>(my_data);
267 assert (myFile);
268 myFile->readDone (fd, buf, len, errflag);
269 }
270
271 void
272 UFSFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
273 {
274 debug(79, 3) ("storeUfsWrite: FD %d\n",fd);
275 file_write(fd,
276 offset,
277 (char *)buf,
278 size,
279 WriteDone,
280 this,
281 free_func);
282 }
283
284 void
285 UFSStoreState::write(char const *buf, size_t size, off_t offset, FREE * free_func)
286 {
287 debug(79, 3) ("UFSStoreState::write: dirn %d, fileno %08X\n", swap_dirn, swap_filen);
288
289 if (!theFile->canWrite() || writing) {
290 assert(creating || writing);
291 queueWrite(buf, size, offset, free_func);
292 return;
293 }
294
295 writing = true;
296 theFile->write(buf,size,offset,free_func);
297 }
298
299 void
300 UfsSwapDir::unlink(StoreEntry & e)
301 {
302 debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e.swap_filen);
303 replacementRemove(&e);
304 mapBitReset(e.swap_filen);
305 UFSSwapDir::unlinkFile(e.swap_filen);
306 }
307
308 /* === STATIC =========================================================== */
309
310 void
311 UFSFile::readDone(int rvfd, const char *buf, int len, int errflag)
312 {
313 debug (79,3)("UFSFile::readDone: FD %d\n",rvfd);
314 assert (fd == rvfd);
315
316 ssize_t rlen;
317
318 if (errflag) {
319 debug(79, 3) ("UFSFile::readDone: got failure (%d)\n", errflag);
320 rlen = -1;
321 } else {
322 rlen = (ssize_t) len;
323 }
324
325 if (errflag == DISK_EOF)
326 errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */
327
328 ioRequestor->readCompleted(buf, rlen, errflag);
329 }
330
331 void
332 ufsstate_t::readCompleted(const char *buf, int len, int errflag)
333 {
334
335 reading = false;
336 debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, len %d\n",
337 swap_dirn, swap_filen, len);
338
339 if (len > 0)
340 offset_ += len;
341
342 STRCB *callback = read.callback;
343
344 assert(callback);
345
346 read.callback = NULL;
347
348 void *cbdata;
349
350 if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
351 if (len > 0 && read_buf != buf)
352 memcpy(read_buf, buf, len);
353
354 callback(cbdata, read_buf, len);
355 } else if (closing)
356 fatal("Sync ufs doesn't support overlapped close and read calls\n");
357 }
358
359 void
360 UFSFile::WriteDone (int fd, int errflag, size_t len, void *me)
361 {
362 UFSFile *aFile = static_cast<UFSFile *>(me);
363 aFile->writeDone (fd, errflag, len);
364 }
365
366 void
367 UFSFile::writeDone(int rvfd, int errflag, size_t len)
368 {
369 assert (rvfd == fd);
370 debug(79, 3) ("storeUfsWriteDone: FD %d, len %ld\n",
371 fd, (long int) len);
372
373 if (errflag) {
374 debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag);
375 doClose();
376 ioRequestor->writeCompleted (DISK_ERROR,0);
377 return;
378 }
379
380 ioRequestor->writeCompleted(DISK_OK, len);
381 }
382
383 void
384 ufsstate_t::writeCompleted(int errflag, size_t len)
385 {
386 debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, len %ld\n",
387 swap_dirn, swap_filen, (long int) len);
388 writing = false;
389
390 if (theFile->error())
391 doCallback(DISK_ERROR);
392
393 offset_ += len;
394
395 if (closing)
396 ((UFSFile *)theFile.getRaw())->close();
397 }
398
399 void
400 ufsstate_t::doCallback(int errflag)
401 {
402 debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag);
403 /* We are finished with the file */
404 theFile = NULL;
405 void *cbdata;
406
407 if (cbdataReferenceValidDone(callback_data, &cbdata))
408 callback(cbdata, errflag, this);
409
410 callback = NULL;
411 }
412
413
414 /*
415 * Clean up any references from the SIO before it get's released.
416 */
417 ufsstate_t::~ufsstate_t()
418 {}
419
420
421
422 /* ============= THE REAL UFS CODE ================ */
423
424 UFSStoreState::UFSStoreState() : opening (false), creating (false), closing (false), reading(false), writing(false), pending_reads(NULL), pending_writes (NULL){}
425
426 UFSStoreState::~UFSStoreState()
427 {
428 _queued_read *qr;
429
430 while ((qr = (_queued_read *)linklistShift(&pending_reads))) {
431 cbdataReferenceDone(qr->callback_data);
432 delete qr;
433 }
434
435 struct _queued_write *qw;
436
437 while ((qw = (struct _queued_write *)linklistShift(&pending_writes))) {
438 if (qw->free_func)
439 qw->free_func(const_cast<char *>(qw->buf));
440 delete qw;
441 }
442 }
443
444 bool
445 UFSStoreState::kickReadQueue()
446 {
447 _queued_read *q = (_queued_read *)linklistShift(&pending_reads);
448
449 if (NULL == q)
450 return false;
451
452 debug(79, 3) ("UFSStoreState::kickReadQueue: reading queued request of %ld bytes\n",
453 (long int) q->size);
454
455 void *cbdata;
456
457 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
458 read_(q->buf, q->size, q->offset, q->callback, cbdata);
459
460 delete q;
461
462 return true;
463 }
464
465 MemPool * UFSStoreState::_queued_read::Pool = NULL;
466
467 void *
468 UFSStoreState::_queued_read::operator new(size_t size)
469 {
470 if (!Pool)
471 Pool = memPoolCreate("AUFS Queued read data",sizeof (_queued_read));
472
473 return memPoolAlloc (Pool);
474 }
475
476 void
477 UFSStoreState::_queued_read::operator delete (void *address)
478 {
479 memPoolFree (Pool, address);
480 }
481
482 void
483 UFSStoreState::queueRead(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data)
484 {
485 debug(79, 3) ("UFSStoreState::queueRead: queueing read\n");
486 assert(opening);
487 assert (pending_reads == NULL);
488 _queued_read *q = new _queued_read;
489 q->buf = buf;
490 q->size = size;
491 q->offset = offset;
492 q->callback = callback;
493 q->callback_data = cbdataReference(callback_data);
494 linklistPush(&pending_reads, q);
495 }
496
497 MemPool * UFSStoreState::_queued_write::Pool = NULL;
498
499 void *
500 UFSStoreState::_queued_write::operator new(size_t size)
501 {
502 if (!Pool)
503 Pool = memPoolCreate("AUFS Queued write data",sizeof (_queued_write));
504
505 return memPoolAlloc (Pool);
506 }
507
508 void
509 UFSStoreState::_queued_write::operator delete (void *address)
510 {
511 memPoolFree (Pool, address);
512 }
513
514 bool
515 UFSStoreState::kickWriteQueue()
516 {
517 _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
518
519 if (NULL == q)
520 return false;
521
522 debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
523 (long int) q->size);
524
525 write(const_cast<char *>(q->buf), q->size, q->offset, q->free_func);
526 delete q;
527 return true;
528 }
529
530 void
531 UFSStoreState::queueWrite(char const *buf, size_t size, off_t offset, FREE * free_func)
532 {
533 debug(79, 3) ("UFSStoreState::queueWrite: queuing write\n");
534
535 struct _queued_write *q;
536 q = new _queued_write;
537 q->buf = buf;
538 q->size = size;
539 q->offset = offset;
540 q->free_func = free_func;
541 linklistPush(&pending_writes, q);
542 }
543
544 StoreIOState::Pointer
545 UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
546 STIOCB * callback, void *callback_data)
547 {
548 assert (((UfsSwapDir *)SD)->IO == this);
549 debug(79, 3) ("UFSStrategy::open: fileno %08X\n", e->swap_filen);
550
551 if (shedLoad()) {
552 openFailed();
553 return NULL;
554 }
555
556 /* to consider: make createstate a private UFSStrategy call */
557 StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
558
559 sio->mode |= O_RDONLY;
560
561 UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
562
563 assert (state);
564
565 char *path = ((UFSSwapDir *)SD)->fullPath(e->swap_filen, NULL);
566
567 DiskFile::Pointer myFile = newFile (path);
568
569 state->theFile = myFile;
570
571 state->opening = true;
572
573 myFile->open (sio->mode, 0644, state);
574
575 if (myFile->error())
576 return NULL;
577
578 return sio;
579 }
580
581 StoreIOState::Pointer
582 UFSStrategy::create(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
583 STIOCB * callback, void *callback_data)
584 {
585 assert (((UfsSwapDir *)SD)->IO == this);
586 /* Allocate a number */
587 sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
588 debug(79, 3) ("UFSStrategy::create: fileno %08X\n", filn);
589
590 if (shedLoad()) {
591 openFailed();
592 ((UFSSwapDir *)SD)->mapBitReset (filn);
593 return NULL;
594 }
595
596 /* Shouldn't we handle a 'bitmap full' error here? */
597
598 StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
599
600 sio->mode |= O_WRONLY | O_CREAT | O_TRUNC;
601
602 sio->swap_filen = filn;
603
604 UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
605
606 assert (state);
607
608 char *path = ((UFSSwapDir *)SD)->fullPath(filn, NULL);
609
610 DiskFile::Pointer myFile = newFile (path);
611
612 state->theFile = myFile;
613
614 state->creating = true;
615
616 myFile->create (state->mode, 0644, state);
617
618 if (myFile->error()) {
619 ((UFSSwapDir *)SD)->mapBitReset (filn);
620 return NULL;
621 }
622
623 /* now insert into the replacement policy */
624 ((UFSSwapDir *)SD)->replacementAdd(e);
625
626 return sio;
627 }