]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/ufs/UFSStoreState.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / fs / ufs / UFSStoreState.cc
CommitLineData
cd748f27 1
2/*
262a0e14 3 * $Id$
cd748f27 4 *
5 * DEBUG: section 79 Storage Manager UFS Interface
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
cd748f27 9 * ----------------------------------------------------------
10 *
2b6662ba 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.
cd748f27 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.
26ac0430 24 *
cd748f27 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.
26ac0430 29 *
cd748f27 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
582c2af2 36#include "squid.h"
e6ccf245 37#include "Store.h"
b9ae18aa 38#include "Generic.h"
39#include "DiskIO/DiskFile.h"
40#include "DiskIO/DiskIOStrategy.h"
41#include "DiskIO/ReadRequest.h"
42#include "DiskIO/WriteRequest.h"
582c2af2 43#include "protos.h"
d3b3ab85 44#include "SwapDir.h"
58373ff8
FC
45#include "UFSStrategy.h"
46#include "UFSStoreState.h"
cd748f27 47
58373ff8 48CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs,UFSStoreState);
72711e31 49
d3b3ab85 50void *
58373ff8 51Fs::Ufs::UFSStoreState::operator new (size_t)
d3b3ab85 52{
59b2d47f 53 CBDATA_INIT_TYPE(UFSStoreState);
54 return cbdataAlloc(UFSStoreState);
d3b3ab85 55}
62e76326 56
d3b3ab85 57void
58373ff8 58Fs::Ufs::UFSStoreState::operator delete (void *address)
d3b3ab85 59{
d3b3ab85 60 cbdataFree(address);
d3b3ab85 61}
cd748f27 62
cd748f27 63void
58373ff8 64Fs::Ufs::UFSStoreState::ioCompletedNotification()
cd748f27 65{
d3b3ab85 66 if (opening) {
62e76326 67 opening = false;
bf8fe701 68 debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
69 swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
70 std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
71 std::dec << theFile->error());
72
59b2d47f 73 assert (FILE_MODE(mode) == O_RDONLY);
74 openDone();
75
62e76326 76 return;
d3b3ab85 77 }
62e76326 78
d3b3ab85 79 if (creating) {
62e76326 80 creating = false;
bf8fe701 81 debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
82 swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
83 std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
84 std::dec << theFile->error());
85
59b2d47f 86 openDone();
87
62e76326 88 return;
d3b3ab85 89 }
62e76326 90
59b2d47f 91 assert (!(closing ||opening));
bf8fe701 92 debugs(79, 3, "diskd::ioCompleted: dirno " << swap_dirn << ", fileno "<<
93 std::setfill('0') << std::hex << std::setw(8) << swap_filen <<
94 " status "<< std::setfill(' ') << std::dec << theFile->error());
95
59b2d47f 96 /* Ok, notification past open means an error has occured */
97 assert (theFile->error());
1e0d7905 98 tryClosing();
d3b3ab85 99}
cd748f27 100
d3b3ab85 101void
58373ff8 102Fs::Ufs::UFSStoreState::openDone()
d3b3ab85 103{
1e0d7905 104 if (closing)
fa84c01d 105 debugs(0, DBG_CRITICAL, HERE << "already closing in openDone()!?");
1e0d7905 106
59b2d47f 107 if (theFile->error()) {
1e0d7905 108 tryClosing();
59b2d47f 109 return;
110 }
111
112 if (FILE_MODE(mode) == O_WRONLY) {
1e0d7905 113 drainWriteQueue();
114
59b2d47f 115 } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) {
116 if (kickReadQueue())
117 return;
118 }
119
1e0d7905 120 if (flags.try_closing)
121 tryClosing();
59b2d47f 122
bf8fe701 123 debugs(79, 3, "UFSStoreState::openDone: exiting");
d3b3ab85 124}
125
126void
58373ff8 127Fs::Ufs::UFSStoreState::closeCompleted()
d3b3ab85 128{
59b2d47f 129 assert (closing);
bf8fe701 130 debugs(79, 3, "UFSStoreState::closeCompleted: dirno " << swap_dirn <<
131 ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
132 swap_filen << " status "<< std::setfill(' ') << std::dec <<
133 theFile->error());
62e76326 134
1e0d7905 135 if (theFile->error()) {
136 debugs(79,3,HERE<< "theFile->error() ret " << theFile->error());
3e2cded3 137 doCloseCallback(DISK_ERROR);
1e0d7905 138 } else {
3e2cded3 139 doCloseCallback(DISK_OK);
1e0d7905 140 }
59b2d47f 141
142 closing = false;
143}
144
1e0d7905 145/*
146 * DPW 2006-05-24
147 * This close function is called by the higher layer when it has finished
148 * reading/writing everything, or otherwise wants to close the swap
149 * file. In the case of writing and using aufs storage, close() might
150 * be called before any/all data is written, and even before the open
151 * callback occurs. Thus, we use our tryClosing() method, which knows
152 * when it is safe to actually signal the lower layer for closing.
153 */
59b2d47f 154void
58373ff8 155Fs::Ufs::UFSStoreState::close(int)
59b2d47f 156{
bf8fe701 157 debugs(79, 3, "UFSStoreState::close: dirno " << swap_dirn << ", fileno "<<
158 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
aa1a691e 159 tryClosing(); // UFS does not distinguish different closure types
d3b3ab85 160}
161
162void
58373ff8 163Fs::Ufs::UFSStoreState::read_(char *buf, size_t size, off_t aOffset, STRCB * aCallback, void *aCallbackData)
d3b3ab85 164{
165 assert(read.callback == NULL);
166 assert(read.callback_data == NULL);
167 assert(!reading);
168 assert(!closing);
e4ae841b 169 assert (aCallback);
62e76326 170
d3b3ab85 171 if (!theFile->canRead()) {
bf8fe701 172 debugs(79, 3, "UFSStoreState::read_: queueing read because theFile can't read");
18ec8500 173 queueRead (buf, size, aOffset, aCallback, aCallbackData);
62e76326 174 return;
cd748f27 175 }
62e76326 176
e4ae841b
FC
177 read.callback = aCallback;
178 read.callback_data = cbdataReference(aCallbackData);
bf8fe701 179 debugs(79, 3, "UFSStoreState::read_: dirno " << swap_dirn << ", fileno "<<
180 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
18ec8500 181 offset_ = aOffset;
d3b3ab85 182 read_buf = buf;
183 reading = true;
18ec8500 184 theFile->read(new ReadRequest(buf,aOffset,size));
d3b3ab85 185}
62e76326 186
1e0d7905 187/*
188 * DPW 2006-05-24
189 * This, the public write interface, places the write request at the end
190 * of the pending_writes queue to ensure correct ordering of writes.
191 * We could optimize things a little if there are no other pending
192 * writes and just do the write directly. But for now we'll keep the
193 * code simpler and always go through the pending_writes queue.
194 */
cd748f27 195void
58373ff8 196Fs::Ufs::UFSStoreState::write(char const *buf, size_t size, off_t aOffset, FREE * free_func)
d3b3ab85 197{
bf8fe701 198 debugs(79, 3, "UFSStoreState::write: dirn " << swap_dirn << ", fileno "<<
199 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
62e76326 200
1e0d7905 201 if (theFile->error()) {
e0236918
FC
202 debugs(79, DBG_IMPORTANT,HERE << "avoid write on theFile with error");
203 debugs(79, DBG_IMPORTANT,HERE << "calling free_func for " << (void*) buf);
1e0d7905 204 free_func((void*)buf);
205 return;
206 }
207
18ec8500 208 queueWrite(buf, size, aOffset, free_func);
1e0d7905 209 drainWriteQueue();
210}
211
1e0d7905 212/*
213 * DPW 2006-05-24
214 * This, the private write method, calls the lower level write for the
215 * first write request in the pending_writes queue. doWrite() is only
216 * called by drainWriteQueue().
217 */
218void
58373ff8 219Fs::Ufs::UFSStoreState::doWrite()
1e0d7905 220{
221 debugs(79, 3, HERE << this << " UFSStoreState::doWrite");
222
223 assert(theFile->canWrite());
224
225 _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
226
227 if (q == NULL) {
228 debugs(79, 3, HERE << this << " UFSStoreState::doWrite queue is empty");
229 return;
230 }
231
232 if (theFile->error()) {
e0236918 233 debugs(79, DBG_IMPORTANT,HERE << "avoid write on theFile with error");
1e0d7905 234 debugs(79,3,HERE << "calling free_func for " << (void*) q->buf);
235 /*
236 * DPW 2006-05-24
237 * Note "free_func" is memNodeWriteComplete(), which doesn't
238 * really free the memory. Instead it clears the node's
239 * write_pending flag.
240 */
241 q->free_func((void*)q->buf);
9db2e213 242 delete q;
62e76326 243 return;
d3b3ab85 244 }
62e76326 245
1e0d7905 246 /*
247 * DPW 2006-05-24
248 * UFSStoreState has a 'writing' flag that we used to set here,
249 * but it wasn't really used anywhere. In fact, some lower
250 * layers such as DISKD allow multiple outstanding writes, which
251 * makes the boolean writing flag meaningless. We would need
252 * a counter to keep track of writes going out and write callbacks
253 * coming in. For now let's just not use the writing flag at
254 * all.
255 */
256 debugs(79, 3, HERE << this << " calling theFile->write(" << q->size << ")");
257
258 theFile->write(new WriteRequest(q->buf, q->offset, q->size, q->free_func));
9db2e213 259 delete q;
d3b3ab85 260}
261
262void
58373ff8 263Fs::Ufs::UFSStoreState::readCompleted(const char *buf, int len, int errflag, RefCount<ReadRequest> result)
d3b3ab85 264{
b9ae18aa 265 assert (result.getRaw());
d3b3ab85 266 reading = false;
bf8fe701 267 debugs(79, 3, "UFSStoreState::readCompleted: dirno " << swap_dirn <<
268 ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
269 swap_filen << " len "<< std::setfill(' ') << std::dec << len);
62e76326 270
d3b3ab85 271 if (len > 0)
62e76326 272 offset_ += len;
273
e4ae841b 274 STRCB *callback_ = read.callback;
62e76326 275
e4ae841b 276 assert(callback_);
62e76326 277
d3b3ab85 278 read.callback = NULL;
62e76326 279
d3b3ab85 280 void *cbdata;
62e76326 281
59b2d47f 282 /* A note:
283 * diskd IO queues closes via the diskd queue. So close callbacks
284 * occur strictly after reads and writes.
285 * ufs doesn't queue, it simply completes, so close callbacks occur
286 * strictly after reads and writes.
287 * aufs performs closes syncronously, so close events must be managed
288 * to force strict ordering.
289 * The below does this:
1e0d7905 290 * closing is set when theFile->close() has been called, and close only triggers
59b2d47f 291 * when no io's are pending.
292 * writeCompleted likewise.
293 */
d3b3ab85 294 if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
62e76326 295 if (len > 0 && read_buf != buf)
296 memcpy(read_buf, buf, len);
297
e4ae841b 298 callback_(cbdata, read_buf, len, this);
1e0d7905 299 }
300
8bc0c94b 301 if (flags.try_closing || (theFile != NULL && theFile->error()) )
1e0d7905 302 tryClosing();
d3b3ab85 303}
304
305void
58373ff8 306Fs::Ufs::UFSStoreState::writeCompleted(int errflag, size_t len, RefCount<WriteRequest> writeRequest)
d3b3ab85 307{
983983ce 308 debugs(79, 3, HERE << "dirno " << swap_dirn << ", fileno " <<
26ac0430 309 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen <<
983983ce 310 ", len " << len);
1e0d7905 311 /*
312 * DPW 2006-05-24
313 * See doWrites() for why we don't update UFSStoreState::writing
314 * here anymore.
315 */
62e76326 316
59b2d47f 317 offset_ += len;
318
319 if (theFile->error()) {
983983ce 320 debugs(79,2,HERE << " detected an error, will try to close");
1e0d7905 321 tryClosing();
59b2d47f 322 }
bdf5b250 323
324 /*
8c212619
HN
325 * HNO 2009-07-24
326 * Kick any pending write/close operations alive
bdf5b250 327 */
8c212619 328 drainWriteQueue();
d3b3ab85 329}
330
331void
58373ff8 332Fs::Ufs::UFSStoreState::doCloseCallback(int errflag)
cd748f27 333{
bf8fe701 334 debugs(79, 3, "storeUfsIOCallback: errflag=" << errflag);
1e0d7905 335 /*
336 * DPW 2006-05-24
337 * When we signal the higher layer with this callback, it might unlock
338 * the StoreEntry and its associated data. We must "free" any queued
339 * I/Os (especially writes) now, otherwise the StoreEntry's mem_node's
340 * will have their write_pending flag set, and we'll get an assertion.
341 */
342 freePending();
59b2d47f 343 STIOCB *theCallback = callback;
d3b3ab85 344 callback = NULL;
d3b3ab85 345
59b2d47f 346 void *cbdata;
d3b3ab85 347
59b2d47f 348 if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback)
e5de8b13 349 theCallback(cbdata, errflag, this);
7fbb6b8f 350
1e0d7905 351 /*
352 * We are finished with theFile since the lower layer signalled
353 * us that the file has been closed. This must be the last line,
354 * as theFile may be the only object holding us in memory.
7fbb6b8f 355 */
1e0d7905 356 theFile = NULL; // refcounted
59b2d47f 357}
d3b3ab85 358
359/* ============= THE REAL UFS CODE ================ */
360
58373ff8 361Fs::Ufs::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)
59b2d47f 362{
363 swap_filen = anEntry->swap_filen;
364 swap_dirn = SD->index;
365 mode = O_BINARY;
366 callback = callback_;
367 callback_data = cbdataReference(callback_data_);
368 e = anEntry;
1e0d7905 369 flags.write_draining = false;
370 flags.try_closing = false;
59b2d47f 371}
62e76326 372
58373ff8 373Fs::Ufs::UFSStoreState::~UFSStoreState()
1e0d7905 374{
375 assert(pending_reads == NULL);
376 assert(pending_writes == NULL);
377}
378
379void
58373ff8 380Fs::Ufs::UFSStoreState::freePending()
d3b3ab85 381{
382 _queued_read *qr;
62e76326 383
d3b3ab85 384 while ((qr = (_queued_read *)linklistShift(&pending_reads))) {
62e76326 385 cbdataReferenceDone(qr->callback_data);
386 delete qr;
d3b3ab85 387 }
388
1e0d7905 389 debugs(79,3,HERE << "UFSStoreState::freePending: freed pending reads");
390
5aeabf95 391 _queued_write *qw;
62e76326 392
5aeabf95 393 while ((qw = (_queued_write *)linklistShift(&pending_writes))) {
62e76326 394 if (qw->free_func)
395 qw->free_func(const_cast<char *>(qw->buf));
396 delete qw;
d3b3ab85 397 }
1e0d7905 398
399 debugs(79,3,HERE << "UFSStoreState::freePending: freed pending writes");
d3b3ab85 400}
401
402bool
58373ff8 403Fs::Ufs::UFSStoreState::kickReadQueue()
d3b3ab85 404{
405 _queued_read *q = (_queued_read *)linklistShift(&pending_reads);
62e76326 406
d3b3ab85 407 if (NULL == q)
62e76326 408 return false;
409
4a7a3d56 410 debugs(79, 3, "UFSStoreState::kickReadQueue: reading queued request of " << q->size << " bytes");
62e76326 411
d3b3ab85 412 void *cbdata;
62e76326 413
dc5348e9 414 if (cbdataReferenceValidDone(q->callback_data, &cbdata)) {
62e76326 415 read_(q->buf, q->size, q->offset, q->callback, cbdata);
39d70ea8 416 } else {
dc5348e9
AJ
417 debugs(79, 2, "UFSStoreState::kickReadQueue: this: " << this << " cbdataReferenceValidDone returned false." << " closing: " << closing << " flags.try_closing: " << flags.try_closing);
418 delete q;
419 return false;
420 }
62e76326 421
d3b3ab85 422 delete q;
62e76326 423
d3b3ab85 424 return true;
425}
426
d3b3ab85 427void
58373ff8 428Fs::Ufs::UFSStoreState::queueRead(char *buf, size_t size, off_t aOffset, STRCB *callback_, void *callback_data_)
d3b3ab85 429{
bf8fe701 430 debugs(79, 3, "UFSStoreState::queueRead: queueing read");
d3b3ab85 431 assert(opening);
432 assert (pending_reads == NULL);
433 _queued_read *q = new _queued_read;
434 q->buf = buf;
435 q->size = size;
18ec8500 436 q->offset = aOffset;
e4ae841b
FC
437 q->callback = callback_;
438 q->callback_data = cbdataReference(callback_data_);
d3b3ab85 439 linklistPush(&pending_reads, q);
440}
441
1e0d7905 442/*
443 * DPW 2006-05-24
444 * drainWriteQueue() is a loop around doWrite().
445 */
446void
58373ff8 447Fs::Ufs::UFSStoreState::drainWriteQueue()
cd748f27 448{
2eaddcc2 449 /*
450 * DPW 2007-04-12
451 * We might find that flags.write_draining is already set
452 * because schemes like diskd can process I/O acks
453 * before sending another I/O request. e.g. the following
454 * sequence of events: open request -> write request ->
455 * drainWriteQueue() -> queue full -> callbacks -> openDone() ->
456 * drainWriteQueue().
457 */
458 if (flags.write_draining)
26ac0430 459 return;
62e76326 460
1e0d7905 461 if (!theFile->canWrite())
462 return;
62e76326 463
1e0d7905 464 flags.write_draining = true;
62e76326 465
1e0d7905 466 while (pending_writes != NULL) {
467 doWrite();
468 }
469
470 flags.write_draining = false;
471
472 if (flags.try_closing)
473 tryClosing();
474}
475
476/*
477 * DPW 2006-05-24
478 * This blows. DiskThreadsDiskFile::close() won't actually do the close
479 * if ioInProgress() is true. So we have to check it here. Maybe someday
480 * DiskThreadsDiskFile::close() will be modified to have a return value,
481 * or will remember to do the close for us.
482 */
483void
58373ff8 484Fs::Ufs::UFSStoreState::tryClosing()
1e0d7905 485{
486 debugs(79,3,HERE << this << " tryClosing()" <<
487 " closing = " << closing <<
488 " flags.try_closing = " << flags.try_closing <<
489 " ioInProgress = " << theFile->ioInProgress());
490
491 if (theFile->ioInProgress()) {
26ac0430
AJ
492 debugs(79, 3, HERE << this <<
493 " won't close since ioInProgress is true, bailing");
1e0d7905 494 flags.try_closing = true;
495 return;
496 }
497
498 closing = true;
499 flags.try_closing = false;
500 theFile->close();
d3b3ab85 501}
502
503void
58373ff8 504Fs::Ufs::UFSStoreState::queueWrite(char const *buf, size_t size, off_t aOffset, FREE * free_func)
d3b3ab85 505{
1e0d7905 506 debugs(79, 3, HERE << this << " UFSStoreState::queueWrite: queueing write of size " << size);
62e76326 507
5aeabf95 508 _queued_write *q;
d3b3ab85 509 q = new _queued_write;
510 q->buf = buf;
511 q->size = size;
18ec8500 512 q->offset = aOffset;
d3b3ab85 513 q->free_func = free_func;
514 linklistPush(&pending_writes, q);
515}
516