3 * $Id: store_io_ufs.cc,v 1.25 2004/11/07 14:03:18 hno Exp $
5 * DEBUG: section 79 Storage Manager UFS Interface
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
37 #include "store_ufs.h"
39 #include "ufscommon.h"
43 UfsIO
UfsIO::Instance
;
53 /* Return 999 (99.9%) constant load */
58 UfsIO::createState(SwapDir
*SD
, StoreEntry
*e
, STIOCB
* callback
, void *callback_data
) const
60 return new UFSStoreState (SD
, e
, callback
, callback_data
);
64 UfsIO::newFile (char const *path
)
66 return new UFSFile (path
);
70 UfsIO::unlinkFile(char const *path
)
83 CBDATA_CLASS_INIT(UFSStoreState
);
86 UFSStoreState::operator new (size_t)
88 CBDATA_INIT_TYPE(UFSStoreState
);
89 return cbdataAlloc(UFSStoreState
);
93 UFSStoreState::operator delete (void *address
)
98 CBDATA_CLASS_INIT(UFSFile
);
100 UFSFile::operator new (size_t)
102 CBDATA_INIT_TYPE(UFSFile
);
103 UFSFile
*result
= cbdataAlloc(UFSFile
);
104 /* Mark result as being owned - we want the refcounter to do the delete
106 cbdataReference(result
);
111 UFSFile::operator delete (void *address
)
113 UFSFile
*t
= static_cast<UFSFile
*>(address
);
115 /* And allow the memory to be freed */
116 cbdataReferenceDone (t
);
119 UFSFile::UFSFile (char const *aPath
) : fd (-1), closed (true), error_(false)
122 debug (79,3)("UFSFile::UFSFile: %s\n", aPath
);
123 path_
= xstrdup (aPath
);
133 UFSFile::open (int flags
, mode_t mode
, IORequestor::Pointer callback
)
135 /* Simulate async calls */
136 fd
= file_open(path_
, flags
);
137 ioRequestor
= callback
;
140 debug(79, 1) ("UFSFile::open: Failed to open %s (%s)\n", path_
, xstrerror());
144 store_open_disk_fd
++;
145 debug(79, 3) ("UFSFile::open: opened FD %d\n", fd
);
148 callback
->ioCompletedNotification();
152 UFSFile::create (int flags
, mode_t mode
, IORequestor::Pointer callback
)
154 /* We use the same logic path for open */
155 open(flags
, mode
, callback
);
159 void UFSFile::doClose()
164 store_open_disk_fd
--;
172 debug (79,3)("UFSFile::close: %p closing for %p\n", this, ioRequestor
.getRaw());
174 assert (ioRequestor
.getRaw());
175 ioRequestor
->closeCompleted();
179 UFSFile::canRead() const
185 UFSFile::error() const
187 if ((fd
< 0 && !closed
) || error_
)
193 void UFSFile::error(bool const &aBool
)
199 UFSStoreState::ioCompletedNotification()
203 debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n",
204 swap_dirn
, swap_filen
, theFile
->error());
205 assert (FILE_MODE(mode
) == O_RDONLY
);
213 debug(79, 3) ("storeDiskdCreateDone: dirno %d, fileno %08x status %d\n",
214 swap_dirn
, swap_filen
, theFile
->error());
220 assert (!(closing
||opening
));
221 debug(79, 3) ("diskd::ioCompleted: dirno %d, fileno %08x status %d\n", swap_dirn
, swap_filen
, theFile
->error());
222 /* Ok, notification past open means an error has occured */
223 assert (theFile
->error());
224 doCallback(DISK_ERROR
);
228 UFSStoreState::openDone()
230 if (theFile
->error()) {
231 doCallback(DISK_ERROR
);
235 if (FILE_MODE(mode
) == O_WRONLY
) {
236 if (kickWriteQueue())
238 } else if ((FILE_MODE(mode
) == O_RDONLY
) && !closing
) {
243 if (closing
&& !theFile
->ioInProgress())
244 doCallback(theFile
->error() ? -1 : 0);
246 debug(79, 3) ("squidaiostate_t::openDone: exiting\n");
250 UFSStoreState::closeCompleted()
253 debug(79, 3) ("UFSStoreState::closeCompleted: dirno %d, fileno %08x status %d\n",
254 swap_dirn
, swap_filen
, theFile
->error());
256 if (theFile
->error())
257 doCallback(DISK_ERROR
);
266 UFSStoreState::close()
268 debug(79, 3) ("UFSStoreState::close: dirno %d, fileno %08X\n", swap_dirn
,
270 /* mark the object to be closed on the next io that completes */
276 UFSStoreState::read_(char *buf
, size_t size
, off_t offset
, STRCB
* callback
, void *callback_data
)
278 assert(read
.callback
== NULL
);
279 assert(read
.callback_data
== NULL
);
284 if (!theFile
->canRead()) {
285 debug(79, 3) ("UFSStoreState::read_: queueing read because theFile can't read\n");
286 queueRead (buf
, size
, offset
, callback
, callback_data
);
290 read
.callback
= callback
;
291 read
.callback_data
= cbdataReference(callback_data
);
292 debug(79, 3) ("UFSStoreState::read_: dirno %d, fileno %08X\n",
293 swap_dirn
, swap_filen
);
297 theFile
->read(buf
, offset
, size
);
301 UFSFile::read(char *buf
, off_t offset
, size_t size
)
304 assert (ioRequestor
.getRaw());
305 file_read(fd
, buf
, size
, offset
, ReadDone
, this);
309 UFSFile::ReadDone(int fd
, const char *buf
, int len
, int errflag
, void *my_data
)
311 UFSFile
*myFile
= static_cast<UFSFile
*>(my_data
);
313 myFile
->readDone (fd
, buf
, len
, errflag
);
317 UFSFile::write(char const *buf
, size_t size
, off_t offset
, FREE
*free_func
)
319 debug(79, 3) ("storeUfsWrite: FD %d\n",fd
);
330 UFSStoreState::write(char const *buf
, size_t size
, off_t offset
, FREE
* free_func
)
332 debug(79, 3) ("UFSStoreState::write: dirn %d, fileno %08X\n", swap_dirn
, swap_filen
);
334 if (!theFile
->canWrite()) {
335 assert(creating
|| writing
);
336 queueWrite(buf
, size
, offset
, free_func
);
341 theFile
->write(buf
,size
,offset
,free_func
);
345 UFSFile::ioInProgress()const
347 /* IO is never pending with UFS */
351 /* === STATIC =========================================================== */
354 UFSFile::readDone(int rvfd
, const char *buf
, int len
, int errflag
)
356 debug (79,3)("UFSFile::readDone: FD %d\n",rvfd
);
362 debug(79, 3) ("UFSFile::readDone: got failure (%d)\n", errflag
);
365 rlen
= (ssize_t
) len
;
368 if (errflag
== DISK_EOF
)
369 errflag
= DISK_OK
; /* EOF is signalled by len == 0, not errors... */
371 ioRequestor
->readCompleted(buf
, rlen
, errflag
);
375 UFSStoreState::readCompleted(const char *buf
, int len
, int errflag
)
378 debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x len %d\n",
379 swap_dirn
, swap_filen
, len
);
384 STRCB
*callback
= read
.callback
;
388 read
.callback
= NULL
;
393 * diskd IO queues closes via the diskd queue. So close callbacks
394 * occur strictly after reads and writes.
395 * ufs doesn't queue, it simply completes, so close callbacks occur
396 * strictly after reads and writes.
397 * aufs performs closes syncronously, so close events must be managed
398 * to force strict ordering.
399 * The below does this:
400 * closing is set when close() is called, and close only triggers
401 * when no io's are pending.
402 * writeCompleted likewise.
404 if (!closing
&& cbdataReferenceValidDone(read
.callback_data
, &cbdata
)) {
405 if (len
> 0 && read_buf
!= buf
)
406 memcpy(read_buf
, buf
, len
);
408 callback(cbdata
, read_buf
, len
);
409 } else if (closing
&& theFile
.getRaw()!= NULL
&& !theFile
->ioInProgress())
414 UFSFile::WriteDone (int fd
, int errflag
, size_t len
, void *me
)
416 UFSFile
*aFile
= static_cast<UFSFile
*>(me
);
417 aFile
->writeDone (fd
, errflag
, len
);
421 UFSFile::writeDone(int rvfd
, int errflag
, size_t len
)
424 debug(79, 3) ("storeUfsWriteDone: FD %d, len %ld\n",
428 debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag
);
430 ioRequestor
->writeCompleted (DISK_ERROR
,0);
434 ioRequestor
->writeCompleted(DISK_OK
, len
);
438 UFSStoreState::writeCompleted(int errflag
, size_t len
)
440 debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, len %ld\n",
441 swap_dirn
, swap_filen
, (long int) len
);
446 if (theFile
->error()) {
447 doCallback(DISK_ERROR
);
451 if (closing
&& !theFile
->ioInProgress()) {
456 if (!flags
.write_kicking
) {
457 flags
.write_kicking
= true;
458 /* While we start and complete syncronously io's. */
460 while (kickWriteQueue() && !theFile
->ioInProgress())
463 flags
.write_kicking
= false;
465 if (!theFile
->ioInProgress() && closing
)
471 UFSStoreState::doCallback(int errflag
)
473 debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag
);
474 STIOCB
*theCallback
= callback
;
479 if (cbdataReferenceValidDone(callback_data
, &cbdata
) && theCallback
)
480 theCallback(cbdata
, errflag
, this);
482 /* We are finished with the file as this is on close or error only.*/
483 /* This must be the last line, as theFile may be the only object holding
489 /* ============= THE REAL UFS CODE ================ */
491 UFSStoreState::UFSStoreState(SwapDir
* SD
, StoreEntry
* anEntry
, STIOCB
* callback_
, void *callback_data_
) : opening (false), creating (false), closing (false), reading(false), writing(false), pending_reads(NULL
), pending_writes (NULL
)
493 swap_filen
= anEntry
->swap_filen
;
494 swap_dirn
= SD
->index
;
496 callback
= callback_
;
497 callback_data
= cbdataReference(callback_data_
);
499 flags
.write_kicking
= false;
502 UFSStoreState::~UFSStoreState()
506 while ((qr
= (_queued_read
*)linklistShift(&pending_reads
))) {
507 cbdataReferenceDone(qr
->callback_data
);
513 while ((qw
= (_queued_write
*)linklistShift(&pending_writes
))) {
515 qw
->free_func(const_cast<char *>(qw
->buf
));
521 UFSStoreState::kickReadQueue()
523 _queued_read
*q
= (_queued_read
*)linklistShift(&pending_reads
);
528 debug(79, 3) ("UFSStoreState::kickReadQueue: reading queued request of %ld bytes\n",
533 if (cbdataReferenceValidDone(q
->callback_data
, &cbdata
))
534 read_(q
->buf
, q
->size
, q
->offset
, q
->callback
, cbdata
);
542 UFSStoreState::queueRead(char *buf
, size_t size
, off_t offset
, STRCB
*callback
, void *callback_data
)
544 debug(79, 3) ("UFSStoreState::queueRead: queueing read\n");
546 assert (pending_reads
== NULL
);
547 _queued_read
*q
= new _queued_read
;
551 q
->callback
= callback
;
552 q
->callback_data
= cbdataReference(callback_data
);
553 linklistPush(&pending_reads
, q
);
557 UFSStoreState::kickWriteQueue()
559 _queued_write
*q
= (_queued_write
*)linklistShift(&pending_writes
);
564 debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
567 write(const_cast<char *>(q
->buf
), q
->size
, q
->offset
, q
->free_func
);
573 UFSStoreState::queueWrite(char const *buf
, size_t size
, off_t offset
, FREE
* free_func
)
575 debug(79, 3) ("UFSStoreState::queueWrite: queuing write\n");
578 q
= new _queued_write
;
582 q
->free_func
= free_func
;
583 linklistPush(&pending_writes
, q
);
586 StoreIOState::Pointer
587 UFSStrategy::open(SwapDir
* SD
, StoreEntry
* e
, STFNCB
* file_callback
,
588 STIOCB
* callback
, void *callback_data
)
590 assert (((UFSSwapDir
*)SD
)->IO
== this);
591 debug(79, 3) ("UFSStrategy::open: fileno %08X\n", e
->swap_filen
);
598 /* to consider: make createstate a private UFSStrategy call */
599 StoreIOState::Pointer sio
= createState (SD
, e
, callback
, callback_data
);
601 sio
->mode
|= O_RDONLY
;
603 UFSStoreState
*state
= dynamic_cast <UFSStoreState
*>(sio
.getRaw());
607 char *path
= ((UFSSwapDir
*)SD
)->fullPath(e
->swap_filen
, NULL
);
609 DiskFile::Pointer myFile
= newFile (path
);
611 state
->theFile
= myFile
;
613 state
->opening
= true;
615 myFile
->open (sio
->mode
, 0644, state
);
623 StoreIOState::Pointer
624 UFSStrategy::create(SwapDir
* SD
, StoreEntry
* e
, STFNCB
* file_callback
,
625 STIOCB
* callback
, void *callback_data
)
627 assert (((UFSSwapDir
*)SD
)->IO
== this);
628 /* Allocate a number */
629 sfileno filn
= ((UFSSwapDir
*)SD
)->mapBitAllocate();
630 debug(79, 3) ("UFSStrategy::create: fileno %08X\n", filn
);
634 ((UFSSwapDir
*)SD
)->mapBitReset (filn
);
638 /* Shouldn't we handle a 'bitmap full' error here? */
640 StoreIOState::Pointer sio
= createState (SD
, e
, callback
, callback_data
);
642 sio
->mode
|= O_WRONLY
| O_CREAT
| O_TRUNC
;
644 sio
->swap_filen
= filn
;
646 UFSStoreState
*state
= dynamic_cast <UFSStoreState
*>(sio
.getRaw());
650 char *path
= ((UFSSwapDir
*)SD
)->fullPath(filn
, NULL
);
652 DiskFile::Pointer myFile
= newFile (path
);
654 state
->theFile
= myFile
;
656 state
->creating
= true;
658 myFile
->create (state
->mode
, 0644, state
);
660 if (myFile
->error()) {
661 ((UFSSwapDir
*)SD
)->mapBitReset (filn
);
665 /* now insert into the replacement policy */
666 ((UFSSwapDir
*)SD
)->replacementAdd(e
);
672 UfsIOModule::GetInstance()
675 Instance
= new UfsIOModule
;
685 UfsIOModule::shutdown()
689 UfsIOModule::createSwapDirIOStrategy()
691 return new InstanceToSingletonAdapter
<UfsIO
>(&UfsIO::Instance
);
694 UfsIOModule
*UfsIOModule::Instance
= NULL
;