]>
Commit | Line | Data |
---|---|---|
b9ae18aa | 1 | /* |
262a0e14 | 2 | * $Id$ |
b9ae18aa | 3 | * |
4 | * DEBUG: section 79 Squid-side DISKD I/O functions. | |
5 | * AUTHOR: Duane Wessels | |
6 | * | |
7 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
8 | * ---------------------------------------------------------- | |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from | |
11 | * the Internet community; see the CONTRIBUTORS file for full | |
12 | * details. Many organizations have provided support for Squid's | |
13 | * development; see the SPONSORS file for full details. Squid is | |
14 | * Copyrighted (C) 2001 by the Regents of the University of | |
15 | * California; see the COPYRIGHT file for full details. Squid | |
16 | * incorporates software developed and/or copyrighted by other | |
17 | * sources; see the CREDITS file for full details. | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the GNU General Public License as published by | |
21 | * the Free Software Foundation; either version 2 of the License, or | |
22 | * (at your option) any later version. | |
26ac0430 | 23 | * |
b9ae18aa | 24 | * This program is distributed in the hope that it will be useful, |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
26ac0430 | 28 | * |
b9ae18aa | 29 | * You should have received a copy of the GNU General Public License |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
32 | * | |
33 | * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org> | |
34 | */ | |
35 | ||
582c2af2 | 36 | #include "squid.h" |
d841c88d | 37 | #include "comm/Loops.h" |
b9ae18aa | 38 | #include "ConfigOption.h" |
582c2af2 | 39 | #include "DiskdIOStrategy.h" |
b9ae18aa | 40 | #include "DiskIO/DiskFile.h" |
41 | #include "DiskdFile.h" | |
42 | #include "diomsg.h" | |
582c2af2 | 43 | #include "protos.h" |
b9ae18aa | 44 | #include "Store.h" |
e4f1fdae | 45 | #include "StatCounters.h" |
985c86bc | 46 | #include "SquidTime.h" |
b9ae18aa | 47 | |
582c2af2 FC |
48 | #include <sys/ipc.h> |
49 | #include <sys/msg.h> | |
50 | #include <sys/shm.h> | |
21d845b1 FC |
51 | #if HAVE_ERRNO_H |
52 | #include <errno.h> | |
53 | #endif | |
582c2af2 | 54 | |
b9ae18aa | 55 | diskd_stats_t diskd_stats; |
56 | ||
57 | size_t DiskdIOStrategy::nextInstanceID (0); | |
58 | const int diomsg::msg_snd_rcv_sz = sizeof(diomsg) - sizeof(mtyp_t); | |
59 | ||
60 | size_t | |
61 | DiskdIOStrategy::newInstance() | |
62 | { | |
63 | return ++nextInstanceID; | |
64 | } | |
65 | ||
66 | bool | |
67 | DiskdIOStrategy::shedLoad() | |
68 | { | |
69 | /* | |
70 | * Fail on open() if there are too many requests queued. | |
71 | */ | |
72 | ||
73 | if (away > magic1) { | |
bf8fe701 | 74 | debugs(79, 3, "storeDiskdIO::shedLoad: Shedding, too many requests away"); |
b9ae18aa | 75 | |
76 | return true; | |
77 | } | |
78 | ||
79 | return false; | |
80 | } | |
81 | ||
82 | int | |
83 | DiskdIOStrategy::load() | |
84 | { | |
85 | /* Calculate the storedir load relative to magic2 on a scale of 0 .. 1000 */ | |
86 | /* the parse function guarantees magic2 is positivie */ | |
87 | return away * 1000 / magic2; | |
88 | } | |
89 | ||
90 | void | |
91 | DiskdIOStrategy::openFailed() | |
92 | { | |
cb4185f1 | 93 | ++diskd_stats.open_fail_queue_len; |
b9ae18aa | 94 | } |
95 | ||
96 | DiskFile::Pointer | |
97 | DiskdIOStrategy::newFile(char const *path) | |
98 | { | |
99 | if (shedLoad()) { | |
100 | openFailed(); | |
101 | return NULL; | |
102 | } | |
103 | ||
104 | return new DiskdFile (path, this); | |
105 | } | |
106 | ||
107 | DiskdIOStrategy::DiskdIOStrategy() : magic1(64), magic2(72), away(0) , smsgid(-1), rmsgid(-1), wfd(-1) , instanceID(newInstance()) | |
108 | {} | |
109 | ||
c521ad17 DK |
110 | bool |
111 | DiskdIOStrategy::unlinkdUseful() const | |
112 | { | |
113 | return true; | |
114 | } | |
115 | ||
b9ae18aa | 116 | void |
117 | DiskdIOStrategy::unlinkFile(char const *path) | |
118 | { | |
119 | if (shedLoad()) { | |
120 | /* Damn, we need to issue a sync unlink here :( */ | |
bf8fe701 | 121 | debugs(79, 2, "storeDiskUnlink: Out of queue space, sync unlink"); |
b9ae18aa | 122 | #if USE_UNLINKD |
123 | ||
124 | unlinkdUnlink(path); | |
b9ae18aa | 125 | #else |
126 | ||
127 | unlink(path); | |
128 | #endif | |
129 | ||
130 | return; | |
131 | } | |
132 | ||
133 | /* We can attempt a diskd unlink */ | |
134 | int x; | |
135 | ||
ee139403 | 136 | ssize_t shm_offset; |
b9ae18aa | 137 | |
138 | char *buf; | |
139 | ||
140 | buf = (char *)shm.get(&shm_offset); | |
141 | ||
142 | xstrncpy(buf, path, SHMBUF_BLKSZ); | |
143 | ||
144 | x = send(_MQD_UNLINK, | |
145 | 0, | |
146 | (StoreIOState::Pointer )NULL, | |
147 | 0, | |
148 | 0, | |
149 | shm_offset); | |
150 | ||
151 | if (x < 0) { | |
e0236918 | 152 | debugs(79, DBG_IMPORTANT, "storeDiskdSend UNLINK: " << xstrerror()); |
b9ae18aa | 153 | ::unlink(buf); /* XXX EWW! */ |
154 | // shm.put (shm_offset); | |
155 | } | |
156 | ||
cb4185f1 | 157 | ++diskd_stats.unlink.ops; |
b9ae18aa | 158 | } |
159 | ||
160 | void | |
161 | DiskdIOStrategy::init() | |
162 | { | |
b5d712b5 | 163 | int pid; |
164 | void * hIpc; | |
b9ae18aa | 165 | int rfd; |
166 | int ikey; | |
167 | const char *args[5]; | |
168 | char skey1[32]; | |
169 | char skey2[32]; | |
170 | char skey3[32]; | |
b7ac5457 | 171 | Ip::Address localhost; |
b9ae18aa | 172 | |
173 | ikey = (getpid() << 10) + (instanceID << 2); | |
174 | ikey &= 0x7fffffff; | |
175 | smsgid = msgget((key_t) ikey, 0700 | IPC_CREAT); | |
176 | ||
177 | if (smsgid < 0) { | |
fa84c01d | 178 | debugs(50, DBG_CRITICAL, "storeDiskdInit: msgget: " << xstrerror()); |
b9ae18aa | 179 | fatal("msgget failed"); |
180 | } | |
181 | ||
182 | rmsgid = msgget((key_t) (ikey + 1), 0700 | IPC_CREAT); | |
183 | ||
184 | if (rmsgid < 0) { | |
fa84c01d | 185 | debugs(50, DBG_CRITICAL, "storeDiskdInit: msgget: " << xstrerror()); |
b9ae18aa | 186 | fatal("msgget failed"); |
187 | } | |
188 | ||
189 | shm.init(ikey, magic2); | |
190 | snprintf(skey1, 32, "%d", ikey); | |
191 | snprintf(skey2, 32, "%d", ikey + 1); | |
192 | snprintf(skey3, 32, "%d", ikey + 2); | |
193 | args[0] = "diskd"; | |
194 | args[1] = skey1; | |
195 | args[2] = skey2; | |
196 | args[3] = skey3; | |
197 | args[4] = NULL; | |
cc192b50 | 198 | localhost.SetLocalhost(); |
b5d712b5 | 199 | pid = ipcCreate(IPC_STREAM, |
200 | Config.Program.diskd, | |
201 | args, | |
202 | "diskd", | |
cc192b50 | 203 | localhost, |
b5d712b5 | 204 | &rfd, |
205 | &wfd, | |
206 | &hIpc); | |
207 | ||
208 | if (pid < 0) | |
b9ae18aa | 209 | fatalf("execl: %s", Config.Program.diskd); |
210 | ||
211 | if (rfd != wfd) | |
212 | comm_close(rfd); | |
213 | ||
214 | fd_note(wfd, "squid -> diskd"); | |
215 | ||
933dd095 | 216 | commUnsetFdTimeout(wfd); |
b9ae18aa | 217 | commSetNonBlocking(wfd); |
d841c88d | 218 | Comm::QuickPollRequired(); |
b9ae18aa | 219 | } |
220 | ||
221 | /* | |
222 | * SHM manipulation routines | |
223 | */ | |
224 | void | |
ee139403 | 225 | SharedMemory::put(ssize_t offset) |
b9ae18aa | 226 | { |
227 | int i; | |
228 | assert(offset >= 0); | |
229 | assert(offset < nbufs * SHMBUF_BLKSZ); | |
230 | i = offset / SHMBUF_BLKSZ; | |
231 | assert(i < nbufs); | |
232 | assert(CBIT_TEST(inuse_map, i)); | |
233 | CBIT_CLR(inuse_map, i); | |
234 | --diskd_stats.shmbuf_count; | |
235 | } | |
236 | ||
237 | void * | |
238 | ||
ee139403 | 239 | SharedMemory::get(ssize_t * shm_offset) |
b9ae18aa | 240 | { |
241 | char *aBuf = NULL; | |
242 | int i; | |
243 | ||
cb4185f1 | 244 | for (i = 0; i < nbufs; ++i) { |
b9ae18aa | 245 | if (CBIT_TEST(inuse_map, i)) |
246 | continue; | |
247 | ||
248 | CBIT_SET(inuse_map, i); | |
249 | ||
250 | *shm_offset = i * SHMBUF_BLKSZ; | |
251 | ||
252 | aBuf = buf + (*shm_offset); | |
253 | ||
254 | break; | |
255 | } | |
256 | ||
257 | assert(aBuf); | |
258 | assert(aBuf >= buf); | |
259 | assert(aBuf < buf + (nbufs * SHMBUF_BLKSZ)); | |
cb4185f1 | 260 | ++diskd_stats.shmbuf_count; |
b9ae18aa | 261 | |
262 | if (diskd_stats.max_shmuse < diskd_stats.shmbuf_count) | |
263 | diskd_stats.max_shmuse = diskd_stats.shmbuf_count; | |
264 | ||
265 | return aBuf; | |
266 | } | |
267 | ||
268 | void | |
269 | SharedMemory::init(int ikey, int magic2) | |
270 | { | |
271 | nbufs = (int)(magic2 * 1.3); | |
272 | id = shmget((key_t) (ikey + 2), | |
273 | nbufs * SHMBUF_BLKSZ, 0600 | IPC_CREAT); | |
274 | ||
275 | if (id < 0) { | |
fa84c01d | 276 | debugs(50, DBG_CRITICAL, "storeDiskdInit: shmget: " << xstrerror()); |
b9ae18aa | 277 | fatal("shmget failed"); |
278 | } | |
279 | ||
280 | buf = (char *)shmat(id, NULL, 0); | |
281 | ||
282 | if (buf == (void *) -1) { | |
fa84c01d | 283 | debugs(50, DBG_CRITICAL, "storeDiskdInit: shmat: " << xstrerror()); |
b9ae18aa | 284 | fatal("shmat failed"); |
285 | } | |
286 | ||
287 | inuse_map = (char *)xcalloc((nbufs + 7) / 8, 1); | |
288 | diskd_stats.shmbuf_count += nbufs; | |
289 | ||
cb4185f1 | 290 | for (int i = 0; i < nbufs; ++i) { |
b9ae18aa | 291 | CBIT_SET(inuse_map, i); |
292 | put (i * SHMBUF_BLKSZ); | |
293 | } | |
294 | } | |
295 | ||
296 | void | |
297 | DiskdIOStrategy::unlinkDone(diomsg * M) | |
298 | { | |
bf8fe701 | 299 | debugs(79, 3, "storeDiskdUnlinkDone: file " << shm.buf + M->shm_offset << " status " << M->status); |
e4f1fdae | 300 | ++statCounter.syscalls.disk.unlinks; |
b9ae18aa | 301 | |
302 | if (M->status < 0) | |
cb4185f1 | 303 | ++diskd_stats.unlink.fail; |
b9ae18aa | 304 | else |
cb4185f1 | 305 | ++diskd_stats.unlink.success; |
b9ae18aa | 306 | } |
307 | ||
308 | void | |
309 | DiskdIOStrategy::handle(diomsg * M) | |
310 | { | |
311 | if (!cbdataReferenceValid (M->callback_data)) { | |
312 | /* I.e. already closed file | |
313 | * - say when we have a error opening after | |
314 | * a read was already queued | |
315 | */ | |
26ac0430 | 316 | debugs(79, 3, "storeDiskdHandle: Invalid callback_data " << M->callback_data); |
b9ae18aa | 317 | cbdataReferenceDone (M->callback_data); |
318 | return; | |
319 | } | |
320 | ||
321 | ||
a1ad81aa | 322 | /* set errno passed from diskd. makes debugging more meaningful */ |
323 | if (M->status < 0) | |
324 | errno = -M->status; | |
325 | ||
b9ae18aa | 326 | if (M->newstyle) { |
327 | DiskdFile *theFile = (DiskdFile *)M->callback_data; | |
328 | theFile->RefCountDereference(); | |
329 | theFile->completed (M); | |
330 | } else | |
331 | switch (M->mtype) { | |
332 | ||
333 | case _MQD_OPEN: | |
334 | ||
335 | case _MQD_CREATE: | |
336 | ||
337 | case _MQD_CLOSE: | |
338 | ||
339 | case _MQD_READ: | |
340 | ||
341 | case _MQD_WRITE: | |
342 | assert (0); | |
343 | break; | |
344 | ||
345 | case _MQD_UNLINK: | |
346 | unlinkDone(M); | |
347 | break; | |
348 | ||
349 | default: | |
350 | assert(0); | |
351 | break; | |
352 | } | |
353 | ||
354 | cbdataReferenceDone (M->callback_data); | |
355 | } | |
356 | ||
357 | int | |
ee139403 | 358 | DiskdIOStrategy::send(int mtype, int id, DiskdFile *theFile, size_t size, off_t offset, ssize_t shm_offset, RefCountable_ *requestor) |
b9ae18aa | 359 | { |
b9ae18aa | 360 | diomsg M; |
b9ae18aa | 361 | M.callback_data = cbdataReference(theFile); |
362 | theFile->RefCountReference(); | |
363 | M.requestor = requestor; | |
f30dcf2a | 364 | M.newstyle = true; |
b9ae18aa | 365 | |
366 | if (requestor) | |
367 | requestor->RefCountReference(); | |
368 | ||
f30dcf2a | 369 | return SEND(&M, mtype, id, size, offset, shm_offset); |
b9ae18aa | 370 | } |
371 | ||
372 | int | |
63be0a78 | 373 | DiskdIOStrategy::send(int mtype, int id, RefCount<StoreIOState> sio, size_t size, off_t offset, ssize_t shm_offset) |
b9ae18aa | 374 | { |
b9ae18aa | 375 | diomsg M; |
f30dcf2a | 376 | M.callback_data = cbdataReference(sio.getRaw()); |
377 | M.newstyle = false; | |
378 | ||
379 | return SEND(&M, mtype, id, size, offset, shm_offset); | |
380 | } | |
381 | ||
382 | int | |
ee139403 | 383 | DiskdIOStrategy::SEND(diomsg *M, int mtype, int id, size_t size, off_t offset, ssize_t shm_offset) |
f30dcf2a | 384 | { |
b9ae18aa | 385 | static int send_errors = 0; |
386 | static int last_seq_no = 0; | |
387 | static int seq_no = 0; | |
f30dcf2a | 388 | int x; |
389 | ||
390 | M->mtype = mtype; | |
391 | M->size = size; | |
392 | M->offset = offset; | |
393 | M->status = -1; | |
394 | M->shm_offset = (int) shm_offset; | |
395 | M->id = id; | |
396 | M->seq_no = ++seq_no; | |
b9ae18aa | 397 | |
f30dcf2a | 398 | if (M->seq_no < last_seq_no) |
e0236918 | 399 | debugs(79, DBG_IMPORTANT, "WARNING: sequencing out of order"); |
b9ae18aa | 400 | |
f30dcf2a | 401 | x = msgsnd(smsgid, M, diomsg::msg_snd_rcv_sz, IPC_NOWAIT); |
b9ae18aa | 402 | |
f30dcf2a | 403 | last_seq_no = M->seq_no; |
b9ae18aa | 404 | |
405 | if (0 == x) { | |
cb4185f1 FC |
406 | ++diskd_stats.sent_count; |
407 | ++away; | |
b9ae18aa | 408 | } else { |
e0236918 | 409 | debugs(79, DBG_IMPORTANT, "storeDiskdSend: msgsnd: " << xstrerror()); |
f30dcf2a | 410 | cbdataReferenceDone(M->callback_data); |
b9ae18aa | 411 | assert(++send_errors < 100); |
6a786390 | 412 | if (shm_offset > -1) |
413 | shm.put(shm_offset); | |
b9ae18aa | 414 | } |
415 | ||
416 | /* | |
417 | * We have to drain the queue here if necessary. If we don't, | |
418 | * then we can have a lot of messages in the queue (probably | |
419 | * up to 2*magic1) and we can run out of shared memory buffers. | |
420 | */ | |
421 | /* | |
c8f4eac4 | 422 | * Note that we call Store::Root().callbackk (for all SDs), rather |
423 | * than callback for just this SD, so that while | |
b9ae18aa | 424 | * we're "blocking" on this SD we can also handle callbacks |
425 | * from other SDs that might be ready. | |
426 | */ | |
b9ae18aa | 427 | |
9a518127 | 428 | struct timeval delay = {0, 1}; |
b9ae18aa | 429 | |
9a518127 | 430 | while (away > magic2) { |
b9ae18aa | 431 | select(0, NULL, NULL, NULL, &delay); |
c8f4eac4 | 432 | Store::Root().callback(); |
b9ae18aa | 433 | |
434 | if (delay.tv_usec < 1000000) | |
435 | delay.tv_usec <<= 1; | |
436 | } | |
437 | ||
438 | return x; | |
439 | } | |
440 | ||
441 | ConfigOption * | |
442 | DiskdIOStrategy::getOptionTree() const | |
443 | { | |
444 | ConfigOptionVector *result = new ConfigOptionVector; | |
445 | result->options.push_back(new ConfigOptionAdapter<DiskdIOStrategy>(*const_cast<DiskdIOStrategy *>(this), &DiskdIOStrategy::optionQ1Parse, &DiskdIOStrategy::optionQ1Dump)); | |
446 | result->options.push_back(new ConfigOptionAdapter<DiskdIOStrategy>(*const_cast<DiskdIOStrategy *>(this), &DiskdIOStrategy::optionQ2Parse, &DiskdIOStrategy::optionQ2Dump)); | |
447 | return result; | |
448 | } | |
449 | ||
450 | bool | |
350e2aec | 451 | DiskdIOStrategy::optionQ1Parse(const char *name, const char *value, int isaReconfig) |
b9ae18aa | 452 | { |
453 | if (strcmp(name, "Q1") != 0) | |
454 | return false; | |
455 | ||
456 | int old_magic1 = magic1; | |
457 | ||
458 | magic1 = atoi(value); | |
459 | ||
350e2aec | 460 | if (!isaReconfig) |
b9ae18aa | 461 | return true; |
462 | ||
463 | if (old_magic1 < magic1) { | |
464 | /* | |
465 | * This is because shm.nbufs is computed at startup, when | |
466 | * we call shmget(). We can't increase the Q1/Q2 parameters | |
467 | * beyond their initial values because then we might have | |
468 | * more "Q2 messages" than shared memory chunks, and this | |
469 | * will cause an assertion in storeDiskdShmGet(). | |
470 | */ | |
471 | /* TODO: have DiskdIO hold a link to the swapdir, to allow detailed reporting again */ | |
e0236918 | 472 | debugs(3, DBG_IMPORTANT, "WARNING: cannot increase cache_dir Q1 value while Squid is running."); |
b9ae18aa | 473 | magic1 = old_magic1; |
474 | return true; | |
475 | } | |
476 | ||
477 | if (old_magic1 != magic1) | |
e0236918 | 478 | debugs(3, DBG_IMPORTANT, "cache_dir new Q1 value '" << magic1 << "'"); |
b9ae18aa | 479 | |
480 | return true; | |
481 | } | |
482 | ||
483 | void | |
484 | DiskdIOStrategy::optionQ1Dump(StoreEntry * e) const | |
485 | { | |
486 | storeAppendPrintf(e, " Q1=%d", magic1); | |
487 | } | |
488 | ||
489 | bool | |
350e2aec | 490 | DiskdIOStrategy::optionQ2Parse(const char *name, const char *value, int isaReconfig) |
b9ae18aa | 491 | { |
492 | if (strcmp(name, "Q2") != 0) | |
493 | return false; | |
494 | ||
495 | int old_magic2 = magic2; | |
496 | ||
497 | magic2 = atoi(value); | |
498 | ||
350e2aec | 499 | if (!isaReconfig) |
b9ae18aa | 500 | return true; |
501 | ||
502 | if (old_magic2 < magic2) { | |
503 | /* See comments in Q1 function above */ | |
e0236918 | 504 | debugs(3, DBG_IMPORTANT, "WARNING: cannot increase cache_dir Q2 value while Squid is running."); |
b9ae18aa | 505 | magic2 = old_magic2; |
506 | return true; | |
507 | } | |
508 | ||
509 | if (old_magic2 != magic2) | |
e0236918 | 510 | debugs(3, DBG_IMPORTANT, "cache_dir new Q2 value '" << magic2 << "'"); |
b9ae18aa | 511 | |
512 | return true; | |
513 | } | |
514 | ||
515 | void | |
516 | DiskdIOStrategy::optionQ2Dump(StoreEntry * e) const | |
517 | { | |
518 | storeAppendPrintf(e, " Q2=%d", magic2); | |
519 | } | |
520 | ||
521 | /* | |
522 | * Sync any pending data. We just sit around and read the queue | |
523 | * until the data has finished writing. | |
524 | */ | |
525 | void | |
526 | DiskdIOStrategy::sync() | |
527 | { | |
528 | static time_t lastmsg = 0; | |
529 | ||
530 | while (away > 0) { | |
531 | if (squid_curtime > lastmsg) { | |
e0236918 | 532 | debugs(47, DBG_IMPORTANT, "storeDiskdDirSync: " << away << " messages away"); |
b9ae18aa | 533 | lastmsg = squid_curtime; |
534 | } | |
535 | ||
536 | callback(); | |
537 | } | |
538 | } | |
539 | ||
540 | ||
541 | /* | |
542 | * Handle callbacks. If we have more than magic2 requests away, we block | |
543 | * until the queue is below magic2. Otherwise, we simply return when we | |
544 | * don't get a message. | |
545 | */ | |
546 | ||
547 | int | |
548 | DiskdIOStrategy::callback() | |
549 | { | |
550 | diomsg M; | |
551 | int x; | |
552 | int retval = 0; | |
553 | ||
554 | if (away >= magic2) { | |
cb4185f1 | 555 | ++diskd_stats.block_queue_len; |
b9ae18aa | 556 | retval = 1; |
557 | /* We might not have anything to do, but our queue | |
558 | * is full.. */ | |
559 | } | |
560 | ||
561 | if (diskd_stats.sent_count - diskd_stats.recv_count > | |
562 | diskd_stats.max_away) { | |
563 | diskd_stats.max_away = diskd_stats.sent_count - diskd_stats.recv_count; | |
564 | } | |
565 | ||
566 | while (1) { | |
567 | #ifdef ALWAYS_ZERO_BUFFERS | |
568 | memset(&M, '\0', sizeof(M)); | |
569 | #endif | |
570 | ||
571 | x = msgrcv(rmsgid, &M, diomsg::msg_snd_rcv_sz, 0, IPC_NOWAIT); | |
572 | ||
573 | if (x < 0) | |
574 | break; | |
575 | else if (x != diomsg::msg_snd_rcv_sz) { | |
e0236918 | 576 | debugs(47, DBG_IMPORTANT, "storeDiskdDirCallback: msgget returns " << x); |
b9ae18aa | 577 | break; |
578 | } | |
579 | ||
cb4185f1 | 580 | ++diskd_stats.recv_count; |
b9ae18aa | 581 | --away; |
582 | handle(&M); | |
583 | retval = 1; /* Return that we've actually done some work */ | |
584 | ||
585 | if (M.shm_offset > -1) | |
586 | shm.put ((off_t) M.shm_offset); | |
587 | } | |
588 | ||
589 | return retval; | |
590 | } | |
591 | ||
592 | void | |
593 | DiskdIOStrategy::statfs(StoreEntry & sentry)const | |
594 | { | |
595 | storeAppendPrintf(&sentry, "Pending operations: %d\n", away); | |
596 | } |