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