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