/* * $Id$ * * DEBUG: section 79 Squid-side DISKD I/O functions. * AUTHOR: Duane Wessels * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * 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. * * CopyRight (c) 2003, Robert Collins <robertc@squid-cache.org> */ #include "squid-old.h" #include <sys/ipc.h> #include <sys/msg.h> #include <sys/shm.h> #include "DiskdFile.h" #include "ConfigOption.h" #include "diomsg.h" #include "DiskdIOStrategy.h" #include "DiskIO/IORequestor.h" #include "DiskIO/ReadRequest.h" #include "DiskIO/WriteRequest.h" #include "StatCounters.h" CBDATA_CLASS_INIT(DiskdFile); void * DiskdFile::operator new(size_t unused) { CBDATA_INIT_TYPE(DiskdFile); DiskdFile *result = cbdataAlloc(DiskdFile); /* Mark result as being owned - we want the refcounter to do the delete * call */ debugs(79, 3, "diskdFile with base " << result << " allocating"); return result; } void DiskdFile::operator delete(void *address) { DiskdFile *t = static_cast<DiskdFile *>(address); debugs(79, 3, "diskdFile with base " << t << " deleting"); cbdataFree(t); } DiskdFile::DiskdFile(char const *aPath, DiskdIOStrategy *anIO) : errorOccured(false), IO(anIO), mode(0), inProgressIOs(0) { assert (aPath); debugs(79, 3, "DiskdFile::DiskdFile: " << aPath); path_ = xstrdup (aPath); id = diskd_stats.sio_id; ++diskd_stats.sio_id; } DiskdFile::~DiskdFile() { assert (inProgressIOs == 0); safe_free (path_); } void DiskdFile::open(int flags, mode_t aMode, RefCount< IORequestor > callback) { debugs(79, 3, "DiskdFile::open: " << this << " opening for " << callback.getRaw()); assert (ioRequestor.getRaw() == NULL); ioRequestor = callback; assert (callback.getRaw()); mode = flags; ssize_t shm_offset; char *buf = (char *)IO->shm.get(&shm_offset); xstrncpy(buf, path_, SHMBUF_BLKSZ); ioAway(); int x = IO->send(_MQD_OPEN, id, this, strlen(buf) + 1, mode, shm_offset, NULL); if (x < 0) { ioCompleted(); errorOccured = true; // IO->shm.put (shm_offset); ioRequestor->ioCompletedNotification(); ioRequestor = NULL; } ++diskd_stats.open.ops; } void DiskdFile::create(int flags, mode_t aMode, RefCount< IORequestor > callback) { debugs(79, 3, "DiskdFile::create: " << this << " creating for " << callback.getRaw()); assert (ioRequestor.getRaw() == NULL); ioRequestor = callback; assert (callback.getRaw()); mode = flags; ssize_t shm_offset; char *buf = (char *)IO->shm.get(&shm_offset); xstrncpy(buf, path_, SHMBUF_BLKSZ); ioAway(); int x = IO->send(_MQD_CREATE, id, this, strlen(buf) + 1, mode, shm_offset, NULL); if (x < 0) { ioCompleted(); errorOccured = true; // IO->shm.put (shm_offset); debugs(79, 1, "storeDiskdSend CREATE: " << xstrerror()); notifyClient(); ioRequestor = NULL; return; } ++diskd_stats.create.ops; } void DiskdFile::read(ReadRequest *aRead) { assert (ioRequestor.getRaw() != NULL); ssize_t shm_offset; char *rbuf = (char *)IO->shm.get(&shm_offset); assert(rbuf); ioAway(); int x = IO->send(_MQD_READ, id, this, aRead->len, aRead->offset, shm_offset, aRead); if (x < 0) { ioCompleted(); errorOccured = true; // IO->shm.put (shm_offset); debugs(79, 1, "storeDiskdSend READ: " << xstrerror()); notifyClient(); ioRequestor = NULL; return; } ++diskd_stats.read.ops; } void DiskdFile::close() { debugs(79, 3, "DiskdFile::close: " << this << " closing for " << ioRequestor.getRaw()); assert (ioRequestor.getRaw()); ioAway(); int x = IO->send(_MQD_CLOSE, id, this, 0, 0, -1, NULL); if (x < 0) { ioCompleted(); errorOccured = true; debugs(79, 1, "storeDiskdSend CLOSE: " << xstrerror()); notifyClient(); ioRequestor = NULL; return; } ++diskd_stats.close.ops; } bool DiskdFile::error() const { return errorOccured; } bool DiskdFile::canRead() const { return !error(); } bool DiskdFile::canNotifyClient() const { if (!ioRequestor.getRaw()) { debugs(79, 3, "DiskdFile::canNotifyClient: No ioRequestor to notify"); return false; } return true; } void DiskdFile::notifyClient() { if (!canNotifyClient()) { return; } ioRequestor->ioCompletedNotification(); } void DiskdFile::completed(diomsg *M) { assert (M->newstyle); switch (M->mtype) { case _MQD_OPEN: openDone(M); break; case _MQD_CREATE: createDone(M); break; case _MQD_CLOSE: closeDone(M); break; case _MQD_READ: readDone(M); break; case _MQD_WRITE: writeDone(M); break; case _MQD_UNLINK: assert (0); break; default: assert(0); break; } } void DiskdFile::openDone(diomsg *M) { ++statCounter.syscalls.disk.opens; debugs(79, 3, "storeDiskdOpenDone: status " << M->status); if (M->status < 0) { ++diskd_stats.open.fail; errorOccured = true; } else { ++diskd_stats.open.success; } ioCompleted(); notifyClient(); } void DiskdFile::createDone(diomsg *M) { ++statCounter.syscalls.disk.opens; debugs(79, 3, "storeDiskdCreateDone: status " << M->status); if (M->status < 0) { ++diskd_stats.create.fail; errorOccured = true; } else { ++diskd_stats.create.success; } ioCompleted(); notifyClient(); } void DiskdFile::write(WriteRequest *aRequest) { debugs(79, 3, "DiskdFile::write: this " << (void *)this << ", buf " << (void *)aRequest->buf << ", off " << aRequest->offset << ", len " << aRequest->len); ssize_t shm_offset; char *sbuf = (char *)IO->shm.get(&shm_offset); memcpy(sbuf, aRequest->buf, aRequest->len); if (aRequest->free_func) aRequest->free_func(const_cast<char *>(aRequest->buf)); ioAway(); int x = IO->send(_MQD_WRITE, id, this, aRequest->len, aRequest->offset, shm_offset, aRequest); if (x < 0) { ioCompleted(); errorOccured = true; debugs(79, 1, "storeDiskdSend WRITE: " << xstrerror()); // IO->shm.put (shm_offset); notifyClient(); ioRequestor = NULL; return; } ++diskd_stats.write.ops; } void DiskdFile::ioAway() { ++inProgressIOs; } void DiskdFile::ioCompleted() { --inProgressIOs; } void DiskdFile::closeDone(diomsg * M) { ++statCounter.syscalls.disk.closes; debugs(79, 3, "DiskdFile::closeDone: status " << M->status); if (M->status < 0) { ++diskd_stats.close.fail; errorOccured = true; } else { ++diskd_stats.close.success; } ioCompleted(); if (canNotifyClient()) ioRequestor->closeCompleted(); ioRequestor = NULL; } void DiskdFile::readDone(diomsg * M) { ++statCounter.syscalls.disk.reads; debugs(79, 3, "DiskdFile::readDone: status " << M->status); assert (M->requestor); ReadRequest::Pointer readRequest = dynamic_cast<ReadRequest *>(M->requestor); /* remove the free protection */ if (readRequest != NULL) readRequest->RefCountDereference(); if (M->status < 0) { ++diskd_stats.read.fail; ioCompleted(); errorOccured = true; ioRequestor->readCompleted(NULL, -1, DISK_ERROR, readRequest); return; } ++diskd_stats.read.success; ioCompleted(); ioRequestor->readCompleted (IO->shm.buf + M->shm_offset, M->status, DISK_OK, readRequest); } void DiskdFile::writeDone(diomsg *M) { ++statCounter.syscalls.disk.writes; debugs(79, 3, "storeDiskdWriteDone: status " << M->status); assert (M->requestor); WriteRequest::Pointer writeRequest = dynamic_cast<WriteRequest *>(M->requestor); /* remove the free protection */ if (writeRequest != NULL) writeRequest->RefCountDereference(); if (M->status < 0) { errorOccured = true; ++diskd_stats.write.fail; ioCompleted(); ioRequestor->writeCompleted (DISK_ERROR,0, writeRequest); return; } ++diskd_stats.write.success; ioCompleted(); ioRequestor->writeCompleted (DISK_OK,M->status, writeRequest); } bool DiskdFile::ioInProgress()const { return inProgressIOs != 0; }