]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/fs/ufs/store_io_ufs.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / fs / ufs / store_io_ufs.cc
index 9923d22d1e1791919e0547b525fd249d2a302e9f..a9d21c9aa4557bf3bfaaeb01243d79e2a3974b18 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_io_ufs.cc,v 1.19 2003/07/15 23:12:02 robertc Exp $
+ * $Id$
  *
  * DEBUG: section 79    Storage Manager UFS Interface
  * AUTHOR: Duane Wessels
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
-#include "squid.h"
-#include "store_ufs.h"
+#include "squid-old.h"
 #include "Store.h"
 #include "ufscommon.h"
+#include "Generic.h"
+#include "DiskIO/DiskFile.h"
+#include "DiskIO/DiskIOStrategy.h"
+#include "DiskIO/ReadRequest.h"
+#include "DiskIO/WriteRequest.h"
 
 #include "SwapDir.h"
 
-UfsIO UfsIO::Instance;
 bool
-UfsIO::shedLoad()
+UFSStrategy::shedLoad()
 {
-    return false;
+    return io->shedLoad();
 }
 
-void
-UfsIO::deleteSelf() const
+int
+UFSStrategy::load()
 {
-    /* Do nothing, we use a single instance */
+    return io->load();
 }
 
-StoreIOState::Pointer
-UfsIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
+UFSStrategy::UFSStrategy (DiskIOStrategy *anIO) : io(anIO)
+{}
+
+UFSStrategy::~UFSStrategy ()
 {
-    return new ufsstate_t (SD, e, callback, callback_data);
+    delete io;
 }
 
-DiskFile::Pointer
-UfsIO::newFile (char const *path)
+StoreIOState::Pointer
+UFSStrategy::createState(SwapDir *SD, StoreEntry *e, StoreIOState::STIOCB * aCallback, void *callback_data) const
 {
-    return new UFSFile (path);
+    return new UFSStoreState (SD, e, aCallback, callback_data);
 }
 
-CBDATA_CLASS_INIT(ufsstate_t);
-
-void *
-ufsstate_t::operator new (size_t)
+DiskFile::Pointer
+UFSStrategy::newFile (char const *path)
 {
-    CBDATA_INIT_TYPE(ufsstate_t);
-    ufsstate_t *result = cbdataAlloc(ufsstate_t);
-    /* Mark result as being owned - we want the refcounter to do the delete
-     * call */
-    cbdataReference(result);
-    return result;
+    return io->newFile(path);
 }
 
+
 void
-ufsstate_t::operator delete (void *address)
+UFSStrategy::unlinkFile(char const *path)
 {
-    ufsstate_t *t = static_cast<ufsstate_t *>(address);
-    cbdataFree(address);
-    /* And allow the memory to be freed */
-    cbdataReferenceDone (t);
+    io->unlinkFile(path);
 }
 
-ufsstate_t::ufsstate_t(SwapDir * SD, StoreEntry * anEntry, STIOCB * callback_, void *callback_data_)
-{
-    swap_filen = anEntry->swap_filen;
-    swap_dirn = SD->index;
-    mode = O_BINARY;
-    callback = callback_;
-    callback_data = cbdataReference(callback_data_);
-    e = anEntry;
-}
+CBDATA_CLASS_INIT(UFSStoreState);
 
-CBDATA_CLASS_INIT(UFSFile);
 void *
-UFSFile::operator new (size_t)
+UFSStoreState::operator new (size_t)
 {
-    CBDATA_INIT_TYPE(UFSFile);
-    UFSFile *result = cbdataAlloc(UFSFile);
-    /* Mark result as being owned - we want the refcounter to do the delete
-     * call */
-    cbdataReference(result);
-    return result;
+    CBDATA_INIT_TYPE(UFSStoreState);
+    return cbdataAlloc(UFSStoreState);
 }
 
 void
-UFSFile::operator delete (void *address)
+UFSStoreState::operator delete (void *address)
 {
-    UFSFile *t = static_cast<UFSFile *>(address);
     cbdataFree(address);
-    /* And allow the memory to be freed */
-    cbdataReferenceDone (t);
 }
 
 void
-UFSFile::deleteSelf() const {delete this;}
-
-UFSFile::UFSFile (char const *aPath) : fd (-1)
-{
-    assert (aPath);
-    debug (79,3)("UFSFile::UFSFile: %s\n", aPath);
-    path_ = xstrdup (aPath);
-}
-
-UFSFile::~UFSFile()
+UFSStoreState::ioCompletedNotification()
 {
-    safe_free (path_);
-    doClose();
-}
+    if (opening) {
+        opening = false;
+        debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
+               swap_dirn  << ", fileno "<< std::setfill('0') << std::hex <<
+               std::setw(8) << swap_filen  << " status "<< std::setfill(' ') <<
+               std::dec << theFile->error());
 
-void
-UFSFile::open (int flags, mode_t mode, IORequestor::Pointer callback)
-{
-    /* Simulate async calls */
-    fd = file_open(path_ , flags);
-    ioRequestor = callback;
+        assert (FILE_MODE(mode) == O_RDONLY);
+        openDone();
 
-    if (fd < 0) {
-        debug(79, 3) ("UFSFile::open: got failure (%d)\n", errno);
-    } else {
-        store_open_disk_fd++;
-        debug(79, 3) ("UFSFile::open: opened FD %d\n", fd);
+        return;
     }
 
-    callback->ioCompletedNotification();
-}
-
-void
-UFSFile::create (int flags, mode_t mode, IORequestor::Pointer callback)
-{
-    /* We use the same logic path for open */
-    open(flags, mode, callback);
-}
+    if (creating) {
+        creating = false;
+        debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
+               swap_dirn  << ", fileno "<< std::setfill('0') << std::hex <<
+               std::setw(8) << swap_filen  << " status "<< std::setfill(' ') <<
+               std::dec << theFile->error());
 
+        openDone();
 
-void UFSFile::doClose()
-{
-    if (fd > -1) {
-        file_close(fd);
-        store_open_disk_fd--;
-        fd = -1;
+        return;
     }
-}
-
-void
-UFSFile::close ()
-{
-    debug (79,3)("UFSFile::close: %p closing for %p\n", this, ioRequestor.getRaw());
-    doClose();
-    assert (ioRequestor.getRaw());
-    ioRequestor->closeCompleted();
-}
-
-bool
-UFSFile::canRead() const
-{
-    return fd > -1;
-}
 
-bool
-UFSFile::error() const
-{
-    if (fd < 0)
-        return true;
+    assert (!(closing ||opening));
+    debugs(79, 3, "diskd::ioCompleted: dirno " << swap_dirn  << ", fileno "<<
+           std::setfill('0') << std::hex << std::setw(8) << swap_filen  <<
+           " status "<< std::setfill(' ') << std::dec << theFile->error());
 
-    return false;
+    /* Ok, notification past open means an error has occured */
+    assert (theFile->error());
+    tryClosing();
 }
 
 void
-ufsstate_t::ioCompletedNotification()
+UFSStoreState::openDone()
 {
-    if (opening) {
-        opening = false;
-        /* There is no 'opened' callback */
+    if (closing)
+        debugs(0,0,HERE << "already closing in openDone()!?");
+
+    if (theFile->error()) {
+        tryClosing();
         return;
     }
 
-    if (creating) {
-        creating = false;
-        return;
+    if (FILE_MODE(mode) == O_WRONLY) {
+        drainWriteQueue();
+
+    } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) {
+        if (kickReadQueue())
+            return;
     }
 
-    assert(0);
+    if (flags.try_closing)
+        tryClosing();
+
+    debugs(79, 3, "UFSStoreState::openDone: exiting");
 }
 
 void
-ufsstate_t::closeCompleted()
+UFSStoreState::closeCompleted()
 {
-    doCallback(theFile->error() ? 0 : -1);
+    assert (closing);
+    debugs(79, 3, "UFSStoreState::closeCompleted: dirno " << swap_dirn  <<
+           ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
+           swap_filen  << " status "<< std::setfill(' ') << std::dec <<
+           theFile->error());
+
+    if (theFile->error()) {
+        debugs(79,3,HERE<< "theFile->error() ret " << theFile->error());
+        doCloseCallback(DISK_ERROR);
+    } else {
+        doCloseCallback(DISK_OK);
+    }
+
+    closing = false;
 }
 
+/*
+ * DPW 2006-05-24
+ * This close function is called by the higher layer when it has finished
+ * reading/writing everything, or otherwise wants to close the swap
+ * file.  In the case of writing and using aufs storage, close() might
+ * be called before any/all data is written, and even before the open
+ * callback occurs.  Thus, we use our tryClosing() method, which knows
+ * when it is safe to actually signal the lower layer for closing.
+ */
 void
-ufsstate_t::close()
+UFSStoreState::close(int)
 {
-    debug(79, 3) ("storeUfsClose: dirno %d, fileno %08X\n",
-                  swap_dirn, swap_filen);
-    closing = true;
-
-    if (!(reading || writing)) {
-        ((UFSFile *)theFile.getRaw())->close();
-    }
+    debugs(79, 3, "UFSStoreState::close: dirno " << swap_dirn  << ", fileno "<<
+           std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
+    tryClosing(); // UFS does not distinguish different closure types
 }
 
 void
-UFSStoreState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
+UFSStoreState::read_(char *buf, size_t size, off_t aOffset, STRCB * aCallback, void *aCallbackData)
 {
     assert(read.callback == NULL);
     assert(read.callback_data == NULL);
     assert(!reading);
     assert(!closing);
-    assert (callback);
+    assert (aCallback);
 
     if (!theFile->canRead()) {
-        debug(79, 3) ("UFSStoreState::read_: queueing read because theFile can't read\n");
-        queueRead (buf, size, offset, callback, callback_data);
+        debugs(79, 3, "UFSStoreState::read_: queueing read because theFile can't read");
+        queueRead (buf, size, aOffset, aCallback, aCallbackData);
         return;
     }
 
-    read.callback = callback;
-    read.callback_data = cbdataReference(callback_data);
-    debug(79, 3) ("UFSStoreState::read_: dirno %d, fileno %08X\n",
-                  swap_dirn, swap_filen);
-    offset_ = offset;
+    read.callback = aCallback;
+    read.callback_data = cbdataReference(aCallbackData);
+    debugs(79, 3, "UFSStoreState::read_: dirno " << swap_dirn  << ", fileno "<<
+           std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
+    offset_ = aOffset;
     read_buf = buf;
     reading = true;
-    theFile->read(buf, offset, size);
+    theFile->read(new ReadRequest(buf,aOffset,size));
 }
 
-void
-UFSFile::read(char *buf, off_t offset, size_t size)
-{
-    assert (fd > -1);
-    assert (ioRequestor.getRaw());
-    file_read(fd, buf, size, offset, ReadDone, this);
-}
-
-void
-UFSFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
-{
-    UFSFile *myFile = static_cast<UFSFile *>(my_data);
-    assert (myFile);
-    myFile->readDone (fd, buf, len, errflag);
-}
-
-void
-UFSFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
-{
-    debug(79, 3) ("storeUfsWrite: FD %d\n",fd);
-    file_write(fd,
-               offset,
-               (char *)buf,
-               size,
-               WriteDone,
-               this,
-               free_func);
-}
 
+/*
+ * DPW 2006-05-24
+ * This, the public write interface, places the write request at the end
+ * of the pending_writes queue to ensure correct ordering of writes.
+ * We could optimize things a little if there are no other pending
+ * writes and just do the write directly.  But for now we'll keep the
+ * code simpler and always go through the pending_writes queue.
+ */
 void
-UFSStoreState::write(char const *buf, size_t size, off_t offset, FREE * free_func)
+UFSStoreState::write(char const *buf, size_t size, off_t aOffset, FREE * free_func)
 {
-    debug(79, 3) ("UFSStoreState::write: dirn %d, fileno %08X\n", swap_dirn, swap_filen);
+    debugs(79, 3, "UFSStoreState::write: dirn " << swap_dirn  << ", fileno "<<
+           std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
 
-    if (!theFile->canWrite() || writing) {
-        assert(creating || writing);
-        queueWrite(buf, size, offset, free_func);
+    if (theFile->error()) {
+        debugs(79,1,HERE << "avoid write on theFile with error");
+        debugs(79,1,HERE << "calling free_func for " << (void*) buf);
+        free_func((void*)buf);
         return;
     }
 
-    writing = true;
-    theFile->write(buf,size,offset,free_func);
+    queueWrite(buf, size, aOffset, free_func);
+    drainWriteQueue();
 }
 
-void
-UfsSwapDir::unlink(StoreEntry & e)
-{
-    debug(79, 3) ("storeUfsUnlink: fileno %08X\n", e.swap_filen);
-    replacementRemove(&e);
-    mapBitReset(e.swap_filen);
-    UFSSwapDir::unlinkFile(e.swap_filen);
-}
-
-/*  === STATIC =========================================================== */
 
+/*
+ * DPW 2006-05-24
+ * This, the private write method, calls the lower level write for the
+ * first write request in the pending_writes queue.  doWrite() is only
+ * called by drainWriteQueue().
+ */
 void
-UFSFile::readDone(int rvfd, const char *buf, int len, int errflag)
+UFSStoreState::doWrite()
 {
-    debug (79,3)("UFSFile::readDone: FD %d\n",rvfd);
-    assert (fd == rvfd);
+    debugs(79, 3, HERE << this << " UFSStoreState::doWrite");
 
-    ssize_t rlen;
+    assert(theFile->canWrite());
 
-    if (errflag) {
-        debug(79, 3) ("UFSFile::readDone: got failure (%d)\n", errflag);
-        rlen = -1;
-    } else {
-        rlen = (ssize_t) len;
+    _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
+
+    if (q == NULL) {
+        debugs(79, 3, HERE << this << " UFSStoreState::doWrite queue is empty");
+        return;
     }
 
-    if (errflag == DISK_EOF)
-        errflag = DISK_OK;     /* EOF is signalled by len == 0, not errors... */
+    if (theFile->error()) {
+        debugs(79,1,HERE << "avoid write on theFile with error");
+        debugs(79,3,HERE << "calling free_func for " << (void*) q->buf);
+        /*
+         * DPW 2006-05-24
+         * Note "free_func" is memNodeWriteComplete(), which doesn't
+         * really free the memory.  Instead it clears the node's
+         * write_pending flag.
+         */
+        q->free_func((void*)q->buf);
+        delete q;
+        return;
+    }
 
-    ioRequestor->readCompleted(buf, rlen, errflag);
+    /*
+     * DPW 2006-05-24
+     * UFSStoreState has a 'writing' flag that we used to set here,
+     * but it wasn't really used anywhere.  In fact, some lower
+     * layers such as DISKD allow multiple outstanding writes, which
+     * makes the boolean writing flag meaningless.  We would need
+     * a counter to keep track of writes going out and write callbacks
+     * coming in.  For now let's just not use the writing flag at
+     * all.
+     */
+    debugs(79, 3, HERE << this << " calling theFile->write(" << q->size << ")");
+
+    theFile->write(new WriteRequest(q->buf, q->offset, q->size, q->free_func));
+    delete q;
 }
 
 void
-ufsstate_t::readCompleted(const char *buf, int len, int errflag)
+UFSStoreState::readCompleted(const char *buf, int len, int errflag, RefCount<ReadRequest> result)
 {
-
+    assert (result.getRaw());
     reading = false;
-    debug(79, 3) ("storeUfsReadDone: dirno %d, fileno %08X, len %d\n",
-                  swap_dirn, swap_filen, len);
+    debugs(79, 3, "UFSStoreState::readCompleted: dirno " << swap_dirn  <<
+           ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
+           swap_filen  << " len "<< std::setfill(' ') << std::dec << len);
 
     if (len > 0)
         offset_ += len;
 
-    STRCB *callback = read.callback;
+    STRCB *callback_ = read.callback;
 
-    assert(callback);
+    assert(callback_);
 
     read.callback = NULL;
 
     void *cbdata;
 
+    /* A note:
+     * diskd IO queues closes via the diskd queue. So close callbacks
+     * occur strictly after reads and writes.
+     * ufs doesn't queue, it simply completes, so close callbacks occur
+     * strictly after reads and writes.
+     * aufs performs closes syncronously, so close events must be managed
+     * to force strict ordering.
+     * The below does this:
+     * closing is set when theFile->close() has been called, and close only triggers
+     * when no io's are pending.
+     * writeCompleted likewise.
+     */
     if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
         if (len > 0 && read_buf != buf)
             memcpy(read_buf, buf, len);
 
-        callback(cbdata, read_buf, len);
-    } else if (closing)
-        fatal("Sync ufs doesn't support overlapped close and read calls\n");
-}
-
-void
-UFSFile::WriteDone (int fd, int errflag, size_t len, void *me)
-{
-    UFSFile *aFile = static_cast<UFSFile *>(me);
-    aFile->writeDone (fd, errflag, len);
-}
-
-void
-UFSFile::writeDone(int rvfd, int errflag, size_t len)
-{
-    assert (rvfd == fd);
-    debug(79, 3) ("storeUfsWriteDone: FD %d, len %ld\n",
-                  fd, (long int) len);
-
-    if (errflag) {
-        debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag);
-        doClose();
-        ioRequestor->writeCompleted (DISK_ERROR,0);
-        return;
+        callback_(cbdata, read_buf, len, this);
     }
 
-    ioRequestor->writeCompleted(DISK_OK, len);
+    if (flags.try_closing || (theFile != NULL && theFile->error()) )
+        tryClosing();
 }
 
 void
-ufsstate_t::writeCompleted(int errflag, size_t len)
+UFSStoreState::writeCompleted(int errflag, size_t len, RefCount<WriteRequest> writeRequest)
 {
-    debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, len %ld\n",
-                  swap_dirn, swap_filen, (long int) len);
-    writing = false;
-
-    if (theFile->error())
-        doCallback(DISK_ERROR);
+    debugs(79, 3, HERE << "dirno " << swap_dirn << ", fileno " <<
+           std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen <<
+           ", len " << len);
+    /*
+     * DPW 2006-05-24
+     * See doWrites() for why we don't update UFSStoreState::writing
+     * here anymore.
+     */
 
     offset_ += len;
 
-    if (closing)
-        ((UFSFile *)theFile.getRaw())->close();
+    if (theFile->error()) {
+        debugs(79,2,HERE << " detected an error, will try to close");
+        tryClosing();
+    }
+
+    /*
+     * HNO 2009-07-24
+     * Kick any pending write/close operations alive
+     */
+    drainWriteQueue();
 }
 
 void
-ufsstate_t::doCallback(int errflag)
-{
-    debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag);
-    /* We are finished with the file */
-    theFile = NULL;
-    void *cbdata;
-
-    if (cbdataReferenceValidDone(callback_data, &cbdata))
-        callback(cbdata, errflag, this);
-
+UFSStoreState::doCloseCallback(int errflag)
+{
+    debugs(79, 3, "storeUfsIOCallback: errflag=" << errflag);
+    /*
+     * DPW 2006-05-24
+     * When we signal the higher layer with this callback, it might unlock
+     * the StoreEntry and its associated data.  We must "free" any queued
+     * I/Os (especially writes) now, otherwise the StoreEntry's mem_node's
+     * will have their write_pending flag set, and we'll get an assertion.
+     */
+    freePending();
+    STIOCB *theCallback = callback;
     callback = NULL;
-}
-
 
-/*
- * Clean up any references from the SIO before it get's released.
- */
-ufsstate_t::~ufsstate_t()
-{}
+    void *cbdata;
 
+    if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback)
+        theCallback(cbdata, errflag, this);
 
+    /*
+     * We are finished with theFile since the lower layer signalled
+     * us that the file has been closed.  This must be the last line,
+     * as theFile may be the only object holding us in memory.
+     */
+    theFile = NULL;    // refcounted
+}
 
 /* ============= THE REAL UFS CODE ================ */
 
-UFSStoreState::UFSStoreState() : opening (false), creating (false), closing (false), reading(false), writing(false), pending_reads(NULL), pending_writes (NULL){}
+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)
+{
+    swap_filen = anEntry->swap_filen;
+    swap_dirn = SD->index;
+    mode = O_BINARY;
+    callback = callback_;
+    callback_data = cbdataReference(callback_data_);
+    e = anEntry;
+    flags.write_draining = false;
+    flags.try_closing = false;
+}
 
 UFSStoreState::~UFSStoreState()
+{
+    assert(pending_reads == NULL);
+    assert(pending_writes == NULL);
+}
+
+void
+UFSStoreState::freePending()
 {
     _queued_read *qr;
 
@@ -432,6 +426,8 @@ UFSStoreState::~UFSStoreState()
         delete qr;
     }
 
+    debugs(79,3,HERE << "UFSStoreState::freePending: freed pending reads");
+
     _queued_write *qw;
 
     while ((qw = (_queued_write *)linklistShift(&pending_writes))) {
@@ -439,6 +435,8 @@ UFSStoreState::~UFSStoreState()
             qw->free_func(const_cast<char *>(qw->buf));
         delete qw;
     }
+
+    debugs(79,3,HERE << "UFSStoreState::freePending: freed pending writes");
 }
 
 bool
@@ -449,112 +447,122 @@ UFSStoreState::kickReadQueue()
     if (NULL == q)
         return false;
 
-    debug(79, 3) ("UFSStoreState::kickReadQueue: reading queued request of %ld bytes\n",
-                  (long int) q->size);
+    debugs(79, 3, "UFSStoreState::kickReadQueue: reading queued request of " << q->size << " bytes");
 
     void *cbdata;
 
-    if (cbdataReferenceValidDone(q->callback_data, &cbdata))
+    if (cbdataReferenceValidDone(q->callback_data, &cbdata)) {
         read_(q->buf, q->size, q->offset, q->callback, cbdata);
+    } else {
+        debugs(79, 2, "UFSStoreState::kickReadQueue: this: " << this << " cbdataReferenceValidDone returned false." << " closing: " << closing << " flags.try_closing: " << flags.try_closing);
+        delete q;
+        return false;
+    }
 
     delete q;
 
     return true;
 }
 
-MemPool * UFSStoreState::_queued_read::Pool = NULL;
-
-void *
-UFSStoreState::_queued_read::operator new(size_t size)
-{
-    if (!Pool)
-        Pool = memPoolCreate("AUFS Queued read data",sizeof (_queued_read));
-
-    return memPoolAlloc (Pool);
-}
-
-void
-UFSStoreState::_queued_read::operator delete (void *address)
-{
-    memPoolFree (Pool, address);
-}
-
 void
-UFSStoreState::queueRead(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data)
+UFSStoreState::queueRead(char *buf, size_t size, off_t aOffset, STRCB *callback_, void *callback_data_)
 {
-    debug(79, 3) ("UFSStoreState::queueRead: queueing read\n");
+    debugs(79, 3, "UFSStoreState::queueRead: queueing read");
     assert(opening);
     assert (pending_reads == NULL);
     _queued_read *q = new _queued_read;
     q->buf = buf;
     q->size = size;
-    q->offset = offset;
-    q->callback = callback;
-    q->callback_data = cbdataReference(callback_data);
+    q->offset = aOffset;
+    q->callback = callback_;
+    q->callback_data = cbdataReference(callback_data_);
     linklistPush(&pending_reads, q);
 }
 
-MemPool * UFSStoreState::_queued_write::Pool = NULL;
+/*
+ * DPW 2006-05-24
+ * drainWriteQueue() is a loop around doWrite().
+ */
+void
+UFSStoreState::drainWriteQueue()
+{
+    /*
+     * DPW 2007-04-12
+     * We might find that flags.write_draining is already set
+     * because schemes like diskd can process I/O acks
+     * before sending another I/O request.    e.g. the following
+     * sequence of events: open request -> write request ->
+     * drainWriteQueue() -> queue full -> callbacks -> openDone() ->
+     * drainWriteQueue().
+     */
+    if (flags.write_draining)
+        return;
+
+    if (!theFile->canWrite())
+        return;
 
-void *
-UFSStoreState::_queued_write::operator new(size_t size)
-{
-    if (!Pool)
-        Pool = memPoolCreate("AUFS Queued write data",sizeof (_queued_write));
+    flags.write_draining = true;
 
-    return memPoolAlloc (Pool);
-}
+    while (pending_writes != NULL) {
+        doWrite();
+    }
 
-void
-UFSStoreState::_queued_write::operator delete (void *address)
-{
-    memPoolFree (Pool, address);
+    flags.write_draining = false;
+
+    if (flags.try_closing)
+        tryClosing();
 }
 
-bool
-UFSStoreState::kickWriteQueue()
+/*
+ * DPW 2006-05-24
+ * This blows. DiskThreadsDiskFile::close() won't actually do the close
+ * if ioInProgress() is true.  So we have to check it here.  Maybe someday
+ * DiskThreadsDiskFile::close() will be modified to have a return value,
+ * or will remember to do the close for us.
+ */
+void
+UFSStoreState::tryClosing()
 {
-    _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
-
-    if (NULL == q)
-        return false;
+    debugs(79,3,HERE << this << " tryClosing()" <<
+           " closing = " << closing <<
+           " flags.try_closing = " << flags.try_closing <<
+           " ioInProgress = " << theFile->ioInProgress());
 
-    debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
-                  (long int) q->size);
+    if (theFile->ioInProgress()) {
+        debugs(79, 3, HERE << this <<
+               " won't close since ioInProgress is true, bailing");
+        flags.try_closing = true;
+        return;
+    }
 
-    write(const_cast<char *>(q->buf), q->size, q->offset, q->free_func);
-    delete q;
-    return true;
+    closing = true;
+    flags.try_closing = false;
+    theFile->close();
 }
 
 void
-UFSStoreState::queueWrite(char const *buf, size_t size, off_t offset, FREE * free_func)
+UFSStoreState::queueWrite(char const *buf, size_t size, off_t aOffset, FREE * free_func)
 {
-    debug(79, 3) ("UFSStoreState::queueWrite: queuing write\n");
+    debugs(79, 3, HERE << this << " UFSStoreState::queueWrite: queueing write of size " << size);
 
     _queued_write *q;
     q = new _queued_write;
     q->buf = buf;
     q->size = size;
-    q->offset = offset;
+    q->offset = aOffset;
     q->free_func = free_func;
     linklistPush(&pending_writes, q);
 }
 
 StoreIOState::Pointer
-UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-                  STIOCB * callback, void *callback_data)
+UFSStrategy::open(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * file_callback,
+                  StoreIOState::STIOCB * aCallback, void *callback_data)
 {
-    assert (((UfsSwapDir *)SD)->IO == this);
-    debug(79, 3) ("UFSStrategy::open: fileno %08X\n", e->swap_filen);
-
-    if (shedLoad()) {
-        openFailed();
-        return NULL;
-    }
+    assert (((UFSSwapDir *)SD)->IO == this);
+    debugs(79, 3, "UFSStrategy::open: fileno "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << e->swap_filen);
 
     /* to consider: make createstate a private UFSStrategy call */
-    StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
+    StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
 
     sio->mode |= O_RDONLY;
 
@@ -566,6 +574,9 @@ UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
 
     DiskFile::Pointer myFile = newFile (path);
 
+    if (myFile.getRaw() == NULL)
+        return NULL;
+
     state->theFile = myFile;
 
     state->opening = true;
@@ -579,23 +590,17 @@ UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
 }
 
 StoreIOState::Pointer
-UFSStrategy::create(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
-                    STIOCB * callback, void *callback_data)
+UFSStrategy::create(SwapDir * SD, StoreEntry * e, StoreIOState::STFNCB * file_callback,
+                    StoreIOState::STIOCB * aCallback, void *callback_data)
 {
-    assert (((UfsSwapDir *)SD)->IO == this);
+    assert (((UFSSwapDir *)SD)->IO == this);
     /* Allocate a number */
     sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
-    debug(79, 3) ("UFSStrategy::create: fileno %08X\n", filn);
-
-    if (shedLoad()) {
-        openFailed();
-        ((UFSSwapDir *)SD)->mapBitReset (filn);
-        return NULL;
-    }
+    debugs(79, 3, "UFSStrategy::create: fileno "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << filn);
 
     /* Shouldn't we handle a 'bitmap full' error here? */
 
-    StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
+    StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
 
     sio->mode |= O_WRONLY | O_CREAT | O_TRUNC;
 
@@ -609,6 +614,11 @@ UFSStrategy::create(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
 
     DiskFile::Pointer myFile = newFile (path);
 
+    if (myFile.getRaw() == NULL) {
+        ((UFSSwapDir *)SD)->mapBitReset (filn);
+        return NULL;
+    }
+
     state->theFile = myFile;
 
     state->creating = true;
@@ -625,3 +635,28 @@ UFSStrategy::create(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
 
     return sio;
 }
+
+int
+UFSStrategy::callback()
+{
+    return io->callback();
+}
+
+void
+UFSStrategy::init()
+{
+    io->init();
+}
+
+void
+UFSStrategy::sync()
+{
+    io->sync();
+}
+
+void
+UFSStrategy::statfs(StoreEntry & sentry)const
+{
+    io->statfs(sentry);
+}
+