]>
Commit | Line | Data |
---|---|---|
cd748f27 | 1 | /* |
f6e9a3ee | 2 | * Copyright (C) 1996-2019 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 | 23 | CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs,UFSStoreState); |
72711e31 | 24 | |
cd748f27 | 25 | void |
58373ff8 | 26 | Fs::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 | ||
61beade2 | 58 | /* Ok, notification past open means an error has occurred */ |
59b2d47f | 59 | assert (theFile->error()); |
1e0d7905 | 60 | tryClosing(); |
d3b3ab85 | 61 | } |
cd748f27 | 62 | |
d3b3ab85 | 63 | void |
58373ff8 | 64 | Fs::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 | ||
88 | void | |
58373ff8 | 89 | Fs::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 | 116 | void |
58373ff8 | 117 | Fs::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 | ||
124 | void | |
58373ff8 | 125 | Fs::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 | 158 | bool |
58373ff8 | 159 | Fs::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 | */ | |
192 | void | |
58373ff8 | 193 | Fs::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 | ||
229 | void | |
ced8def3 | 230 | Fs::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 | ||
272 | void | |
ced8def3 | 273 | Fs::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 | ||
298 | void | |
58373ff8 | 299 | Fs::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 |
328 | Fs::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 | 347 | Fs::Ufs::UFSStoreState::~UFSStoreState() |
1e0d7905 | 348 | { |
2f4c26aa AJ |
349 | assert(pending_reads.empty()); |
350 | assert(pending_writes.empty()); | |
1e0d7905 | 351 | } |
352 | ||
353 | void | |
58373ff8 | 354 | Fs::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 | ||
365 | bool | |
58373ff8 | 366 | Fs::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 | */ | |
393 | void | |
58373ff8 | 394 | Fs::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 | */ | |
429 | void | |
58373ff8 | 430 | Fs::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 |