]> git.ipfire.org Git - thirdparty/squid.git/blob - src/fs/ufs/store_io_ufs.cc
Bug #918: Complain loudly if no write permission to cache directory
[thirdparty/squid.git] / src / fs / ufs / store_io_ufs.cc
1
2 /*
3 * $Id: store_io_ufs.cc,v 1.25 2004/11/07 14:03:18 hno Exp $
4 *
5 * DEBUG: section 79 Storage Manager UFS Interface
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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.
24 *
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.
29 *
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
36 #include "squid.h"
37 #include "store_ufs.h"
38 #include "Store.h"
39 #include "ufscommon.h"
40
41 #include "SwapDir.h"
42
43 UfsIO UfsIO::Instance;
44 bool
45 UfsIO::shedLoad()
46 {
47 return false;
48 }
49
50 int
51 UfsIO::load()
52 {
53 /* Return 999 (99.9%) constant load */
54 return 999;
55 }
56
57 StoreIOState::Pointer
58 UfsIO::createState(SwapDir *SD, StoreEntry *e, STIOCB * callback, void *callback_data) const
59 {
60 return new UFSStoreState (SD, e, callback, callback_data);
61 }
62
63 DiskFile::Pointer
64 UfsIO::newFile (char const *path)
65 {
66 return new UFSFile (path);
67 }
68
69 void
70 UfsIO::unlinkFile(char const *path)
71 {
72 #if USE_UNLINKD
73 unlinkdUnlink(path);
74 #elif USE_TRUNCATE
75
76 truncate(path, 0);
77 #else
78
79 ::unlink(path);
80 #endif
81 }
82
83 CBDATA_CLASS_INIT(UFSStoreState);
84
85 void *
86 UFSStoreState::operator new (size_t)
87 {
88 CBDATA_INIT_TYPE(UFSStoreState);
89 return cbdataAlloc(UFSStoreState);
90 }
91
92 void
93 UFSStoreState::operator delete (void *address)
94 {
95 cbdataFree(address);
96 }
97
98 CBDATA_CLASS_INIT(UFSFile);
99 void *
100 UFSFile::operator new (size_t)
101 {
102 CBDATA_INIT_TYPE(UFSFile);
103 UFSFile *result = cbdataAlloc(UFSFile);
104 /* Mark result as being owned - we want the refcounter to do the delete
105 * call */
106 cbdataReference(result);
107 return result;
108 }
109
110 void
111 UFSFile::operator delete (void *address)
112 {
113 UFSFile *t = static_cast<UFSFile *>(address);
114 cbdataFree(address);
115 /* And allow the memory to be freed */
116 cbdataReferenceDone (t);
117 }
118
119 UFSFile::UFSFile (char const *aPath) : fd (-1), closed (true), error_(false)
120 {
121 assert (aPath);
122 debug (79,3)("UFSFile::UFSFile: %s\n", aPath);
123 path_ = xstrdup (aPath);
124 }
125
126 UFSFile::~UFSFile()
127 {
128 safe_free (path_);
129 doClose();
130 }
131
132 void
133 UFSFile::open (int flags, mode_t mode, IORequestor::Pointer callback)
134 {
135 /* Simulate async calls */
136 fd = file_open(path_ , flags);
137 ioRequestor = callback;
138
139 if (fd < 0) {
140 debug(79, 1) ("UFSFile::open: Failed to open %s (%s)\n", path_, xstrerror());
141 error(true);
142 } else {
143 closed = false;
144 store_open_disk_fd++;
145 debug(79, 3) ("UFSFile::open: opened FD %d\n", fd);
146 }
147
148 callback->ioCompletedNotification();
149 }
150
151 void
152 UFSFile::create (int flags, mode_t mode, IORequestor::Pointer callback)
153 {
154 /* We use the same logic path for open */
155 open(flags, mode, callback);
156 }
157
158
159 void UFSFile::doClose()
160 {
161 if (fd > -1) {
162 closed = true;
163 file_close(fd);
164 store_open_disk_fd--;
165 fd = -1;
166 }
167 }
168
169 void
170 UFSFile::close ()
171 {
172 debug (79,3)("UFSFile::close: %p closing for %p\n", this, ioRequestor.getRaw());
173 doClose();
174 assert (ioRequestor.getRaw());
175 ioRequestor->closeCompleted();
176 }
177
178 bool
179 UFSFile::canRead() const
180 {
181 return fd > -1;
182 }
183
184 bool
185 UFSFile::error() const
186 {
187 if ((fd < 0 && !closed) || error_)
188 return true;
189
190 return false;
191 }
192
193 void UFSFile::error(bool const &aBool)
194 {
195 error_ = aBool;
196 }
197
198 void
199 UFSStoreState::ioCompletedNotification()
200 {
201 if (opening) {
202 opening = false;
203 debug(79, 3) ("storeDiskdOpenDone: dirno %d, fileno %08x status %d\n",
204 swap_dirn, swap_filen, theFile->error());
205 assert (FILE_MODE(mode) == O_RDONLY);
206 openDone();
207
208 return;
209 }
210
211 if (creating) {
212 creating = false;
213 debug(79, 3) ("storeDiskdCreateDone: dirno %d, fileno %08x status %d\n",
214 swap_dirn, swap_filen, theFile->error());
215 openDone();
216
217 return;
218 }
219
220 assert (!(closing ||opening));
221 debug(79, 3) ("diskd::ioCompleted: dirno %d, fileno %08x status %d\n", swap_dirn, swap_filen, theFile->error());
222 /* Ok, notification past open means an error has occured */
223 assert (theFile->error());
224 doCallback(DISK_ERROR);
225 }
226
227 void
228 UFSStoreState::openDone()
229 {
230 if (theFile->error()) {
231 doCallback(DISK_ERROR);
232 return;
233 }
234
235 if (FILE_MODE(mode) == O_WRONLY) {
236 if (kickWriteQueue())
237 return;
238 } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) {
239 if (kickReadQueue())
240 return;
241 }
242
243 if (closing && !theFile->ioInProgress())
244 doCallback(theFile->error() ? -1 : 0);
245
246 debug(79, 3) ("squidaiostate_t::openDone: exiting\n");
247 }
248
249 void
250 UFSStoreState::closeCompleted()
251 {
252 assert (closing);
253 debug(79, 3) ("UFSStoreState::closeCompleted: dirno %d, fileno %08x status %d\n",
254 swap_dirn, swap_filen, theFile->error());
255
256 if (theFile->error())
257 doCallback(DISK_ERROR);
258 else
259 doCallback(DISK_OK);
260
261 closing = false;
262 }
263
264 /* Close */
265 void
266 UFSStoreState::close()
267 {
268 debug(79, 3) ("UFSStoreState::close: dirno %d, fileno %08X\n", swap_dirn,
269 swap_filen);
270 /* mark the object to be closed on the next io that completes */
271 closing = true;
272 theFile->close();
273 }
274
275 void
276 UFSStoreState::read_(char *buf, size_t size, off_t offset, STRCB * callback, void *callback_data)
277 {
278 assert(read.callback == NULL);
279 assert(read.callback_data == NULL);
280 assert(!reading);
281 assert(!closing);
282 assert (callback);
283
284 if (!theFile->canRead()) {
285 debug(79, 3) ("UFSStoreState::read_: queueing read because theFile can't read\n");
286 queueRead (buf, size, offset, callback, callback_data);
287 return;
288 }
289
290 read.callback = callback;
291 read.callback_data = cbdataReference(callback_data);
292 debug(79, 3) ("UFSStoreState::read_: dirno %d, fileno %08X\n",
293 swap_dirn, swap_filen);
294 offset_ = offset;
295 read_buf = buf;
296 reading = true;
297 theFile->read(buf, offset, size);
298 }
299
300 void
301 UFSFile::read(char *buf, off_t offset, size_t size)
302 {
303 assert (fd > -1);
304 assert (ioRequestor.getRaw());
305 file_read(fd, buf, size, offset, ReadDone, this);
306 }
307
308 void
309 UFSFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
310 {
311 UFSFile *myFile = static_cast<UFSFile *>(my_data);
312 assert (myFile);
313 myFile->readDone (fd, buf, len, errflag);
314 }
315
316 void
317 UFSFile::write(char const *buf, size_t size, off_t offset, FREE *free_func)
318 {
319 debug(79, 3) ("storeUfsWrite: FD %d\n",fd);
320 file_write(fd,
321 offset,
322 (char *)buf,
323 size,
324 WriteDone,
325 this,
326 free_func);
327 }
328
329 void
330 UFSStoreState::write(char const *buf, size_t size, off_t offset, FREE * free_func)
331 {
332 debug(79, 3) ("UFSStoreState::write: dirn %d, fileno %08X\n", swap_dirn, swap_filen);
333
334 if (!theFile->canWrite()) {
335 assert(creating || writing);
336 queueWrite(buf, size, offset, free_func);
337 return;
338 }
339
340 writing = true;
341 theFile->write(buf,size,offset,free_func);
342 }
343
344 bool
345 UFSFile::ioInProgress()const
346 {
347 /* IO is never pending with UFS */
348 return false;
349 }
350
351 /* === STATIC =========================================================== */
352
353 void
354 UFSFile::readDone(int rvfd, const char *buf, int len, int errflag)
355 {
356 debug (79,3)("UFSFile::readDone: FD %d\n",rvfd);
357 assert (fd == rvfd);
358
359 ssize_t rlen;
360
361 if (errflag) {
362 debug(79, 3) ("UFSFile::readDone: got failure (%d)\n", errflag);
363 rlen = -1;
364 } else {
365 rlen = (ssize_t) len;
366 }
367
368 if (errflag == DISK_EOF)
369 errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */
370
371 ioRequestor->readCompleted(buf, rlen, errflag);
372 }
373
374 void
375 UFSStoreState::readCompleted(const char *buf, int len, int errflag)
376 {
377 reading = false;
378 debug(79, 3) ("storeDiskdReadDone: dirno %d, fileno %08x len %d\n",
379 swap_dirn, swap_filen, len);
380
381 if (len > 0)
382 offset_ += len;
383
384 STRCB *callback = read.callback;
385
386 assert(callback);
387
388 read.callback = NULL;
389
390 void *cbdata;
391
392 /* A note:
393 * diskd IO queues closes via the diskd queue. So close callbacks
394 * occur strictly after reads and writes.
395 * ufs doesn't queue, it simply completes, so close callbacks occur
396 * strictly after reads and writes.
397 * aufs performs closes syncronously, so close events must be managed
398 * to force strict ordering.
399 * The below does this:
400 * closing is set when close() is called, and close only triggers
401 * when no io's are pending.
402 * writeCompleted likewise.
403 */
404 if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
405 if (len > 0 && read_buf != buf)
406 memcpy(read_buf, buf, len);
407
408 callback(cbdata, read_buf, len);
409 } else if (closing && theFile.getRaw()!= NULL && !theFile->ioInProgress())
410 doCallback(errflag);
411 }
412
413 void
414 UFSFile::WriteDone (int fd, int errflag, size_t len, void *me)
415 {
416 UFSFile *aFile = static_cast<UFSFile *>(me);
417 aFile->writeDone (fd, errflag, len);
418 }
419
420 void
421 UFSFile::writeDone(int rvfd, int errflag, size_t len)
422 {
423 assert (rvfd == fd);
424 debug(79, 3) ("storeUfsWriteDone: FD %d, len %ld\n",
425 fd, (long int) len);
426
427 if (errflag) {
428 debug(79, 0) ("storeUfsWriteDone: got failure (%d)\n", errflag);
429 doClose();
430 ioRequestor->writeCompleted (DISK_ERROR,0);
431 return;
432 }
433
434 ioRequestor->writeCompleted(DISK_OK, len);
435 }
436
437 void
438 UFSStoreState::writeCompleted(int errflag, size_t len)
439 {
440 debug(79, 3) ("storeUfsWriteDone: dirno %d, fileno %08X, len %ld\n",
441 swap_dirn, swap_filen, (long int) len);
442 writing = false;
443
444 offset_ += len;
445
446 if (theFile->error()) {
447 doCallback(DISK_ERROR);
448 return;
449 }
450
451 if (closing && !theFile->ioInProgress()) {
452 theFile->close();
453 return;
454 }
455
456 if (!flags.write_kicking) {
457 flags.write_kicking = true;
458 /* While we start and complete syncronously io's. */
459
460 while (kickWriteQueue() && !theFile->ioInProgress())
461
462 ;
463 flags.write_kicking = false;
464
465 if (!theFile->ioInProgress() && closing)
466 doCallback(errflag);
467 }
468 }
469
470 void
471 UFSStoreState::doCallback(int errflag)
472 {
473 debug(79, 3) ("storeUfsIOCallback: errflag=%d\n", errflag);
474 STIOCB *theCallback = callback;
475 callback = NULL;
476
477 void *cbdata;
478
479 if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback)
480 theCallback(cbdata, errflag, this);
481
482 /* We are finished with the file as this is on close or error only.*/
483 /* This must be the last line, as theFile may be the only object holding
484 * us in memory
485 */
486 theFile = NULL;
487 }
488
489 /* ============= THE REAL UFS CODE ================ */
490
491 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)
492 {
493 swap_filen = anEntry->swap_filen;
494 swap_dirn = SD->index;
495 mode = O_BINARY;
496 callback = callback_;
497 callback_data = cbdataReference(callback_data_);
498 e = anEntry;
499 flags.write_kicking = false;
500 }
501
502 UFSStoreState::~UFSStoreState()
503 {
504 _queued_read *qr;
505
506 while ((qr = (_queued_read *)linklistShift(&pending_reads))) {
507 cbdataReferenceDone(qr->callback_data);
508 delete qr;
509 }
510
511 _queued_write *qw;
512
513 while ((qw = (_queued_write *)linklistShift(&pending_writes))) {
514 if (qw->free_func)
515 qw->free_func(const_cast<char *>(qw->buf));
516 delete qw;
517 }
518 }
519
520 bool
521 UFSStoreState::kickReadQueue()
522 {
523 _queued_read *q = (_queued_read *)linklistShift(&pending_reads);
524
525 if (NULL == q)
526 return false;
527
528 debug(79, 3) ("UFSStoreState::kickReadQueue: reading queued request of %ld bytes\n",
529 (long int) q->size);
530
531 void *cbdata;
532
533 if (cbdataReferenceValidDone(q->callback_data, &cbdata))
534 read_(q->buf, q->size, q->offset, q->callback, cbdata);
535
536 delete q;
537
538 return true;
539 }
540
541 void
542 UFSStoreState::queueRead(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data)
543 {
544 debug(79, 3) ("UFSStoreState::queueRead: queueing read\n");
545 assert(opening);
546 assert (pending_reads == NULL);
547 _queued_read *q = new _queued_read;
548 q->buf = buf;
549 q->size = size;
550 q->offset = offset;
551 q->callback = callback;
552 q->callback_data = cbdataReference(callback_data);
553 linklistPush(&pending_reads, q);
554 }
555
556 bool
557 UFSStoreState::kickWriteQueue()
558 {
559 _queued_write *q = (_queued_write *)linklistShift(&pending_writes);
560
561 if (NULL == q)
562 return false;
563
564 debug(79, 3) ("storeAufsKickWriteQueue: writing queued chunk of %ld bytes\n",
565 (long int) q->size);
566
567 write(const_cast<char *>(q->buf), q->size, q->offset, q->free_func);
568 delete q;
569 return true;
570 }
571
572 void
573 UFSStoreState::queueWrite(char const *buf, size_t size, off_t offset, FREE * free_func)
574 {
575 debug(79, 3) ("UFSStoreState::queueWrite: queuing write\n");
576
577 _queued_write *q;
578 q = new _queued_write;
579 q->buf = buf;
580 q->size = size;
581 q->offset = offset;
582 q->free_func = free_func;
583 linklistPush(&pending_writes, q);
584 }
585
586 StoreIOState::Pointer
587 UFSStrategy::open(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
588 STIOCB * callback, void *callback_data)
589 {
590 assert (((UFSSwapDir *)SD)->IO == this);
591 debug(79, 3) ("UFSStrategy::open: fileno %08X\n", e->swap_filen);
592
593 if (shedLoad()) {
594 openFailed();
595 return NULL;
596 }
597
598 /* to consider: make createstate a private UFSStrategy call */
599 StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
600
601 sio->mode |= O_RDONLY;
602
603 UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
604
605 assert (state);
606
607 char *path = ((UFSSwapDir *)SD)->fullPath(e->swap_filen, NULL);
608
609 DiskFile::Pointer myFile = newFile (path);
610
611 state->theFile = myFile;
612
613 state->opening = true;
614
615 myFile->open (sio->mode, 0644, state);
616
617 if (myFile->error())
618 return NULL;
619
620 return sio;
621 }
622
623 StoreIOState::Pointer
624 UFSStrategy::create(SwapDir * SD, StoreEntry * e, STFNCB * file_callback,
625 STIOCB * callback, void *callback_data)
626 {
627 assert (((UFSSwapDir *)SD)->IO == this);
628 /* Allocate a number */
629 sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
630 debug(79, 3) ("UFSStrategy::create: fileno %08X\n", filn);
631
632 if (shedLoad()) {
633 openFailed();
634 ((UFSSwapDir *)SD)->mapBitReset (filn);
635 return NULL;
636 }
637
638 /* Shouldn't we handle a 'bitmap full' error here? */
639
640 StoreIOState::Pointer sio = createState (SD, e, callback, callback_data);
641
642 sio->mode |= O_WRONLY | O_CREAT | O_TRUNC;
643
644 sio->swap_filen = filn;
645
646 UFSStoreState *state = dynamic_cast <UFSStoreState *>(sio.getRaw());
647
648 assert (state);
649
650 char *path = ((UFSSwapDir *)SD)->fullPath(filn, NULL);
651
652 DiskFile::Pointer myFile = newFile (path);
653
654 state->theFile = myFile;
655
656 state->creating = true;
657
658 myFile->create (state->mode, 0644, state);
659
660 if (myFile->error()) {
661 ((UFSSwapDir *)SD)->mapBitReset (filn);
662 return NULL;
663 }
664
665 /* now insert into the replacement policy */
666 ((UFSSwapDir *)SD)->replacementAdd(e);
667
668 return sio;
669 }
670
671 UfsIOModule &
672 UfsIOModule::GetInstance()
673 {
674 if (!Instance)
675 Instance = new UfsIOModule;
676
677 return *Instance;
678 }
679
680 void
681 UfsIOModule::init()
682 {}
683
684 void
685 UfsIOModule::shutdown()
686 {}
687
688 UFSStrategy *
689 UfsIOModule::createSwapDirIOStrategy()
690 {
691 return new InstanceToSingletonAdapter<UfsIO>(&UfsIO::Instance);
692 }
693
694 UfsIOModule *UfsIOModule::Instance = NULL;