1 /*
2 * Copyright (C) 1996-2021 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 Squid-side DISKD I/O functions. */
10
11 #include "squid.h"
12 #include "ConfigOption.h"
13 #include "diomsg.h"
14 #include "DiskdFile.h"
15 #include "DiskdIOStrategy.h"
16 #include "DiskIO/IORequestor.h"
17 #include "DiskIO/ReadRequest.h"
18 #include "DiskIO/WriteRequest.h"
19 #include "StatCounters.h"
20
21 #if HAVE_SYS_IPC_H
22 #include <sys/ipc.h>
23 #endif
24 #if HAVE_SYS_MSG_H
25 #include <sys/msg.h>
26 #endif
27 #if HAVE_SYS_SHM_H
28 #include <sys/shm.h>
29 #endif
30
31 CBDATA_CLASS_INIT(DiskdFile);
32
DiskdFile(char const * aPath,DiskdIOStrategy * anIO)33 DiskdFile::DiskdFile(char const *aPath, DiskdIOStrategy *anIO) :
34 errorOccured(false),
35 IO(anIO),
36 mode(0),
37 inProgressIOs(0)
38 {
39 assert(aPath);
40 debugs(79, 3, "DiskdFile::DiskdFile: " << aPath);
41 path_ = xstrdup(aPath);
42 id = diskd_stats.sio_id;
43 ++diskd_stats.sio_id;
44 }
45
~DiskdFile()46 DiskdFile::~DiskdFile()
47 {
48 assert(inProgressIOs == 0);
49 safe_free (path_);
50 }
51
52 void
open(int flags,mode_t,RefCount<IORequestor> callback)53 DiskdFile::open(int flags, mode_t, RefCount<IORequestor> callback)
54 {
55 debugs(79, 3, "DiskdFile::open: " << this << " opening for " << callback.getRaw());
56 assert(ioRequestor.getRaw() == NULL);
57 ioRequestor = callback;
58 assert(callback.getRaw());
59 mode = flags;
60 ssize_t shm_offset;
61 char *buf = (char *)IO->shm.get(&shm_offset);
62 xstrncpy(buf, path_, SHMBUF_BLKSZ);
63 ioAway();
64 int x = IO->send(_MQD_OPEN,
65 id,
66 this,
67 strlen(buf) + 1,
68 mode,
69 shm_offset,
70 NULL);
71
72 if (x < 0) {
73 ioCompleted();
74 errorOccured = true;
75 // IO->shm.put (shm_offset);
76 ioRequestor->ioCompletedNotification();
77 ioRequestor = NULL;
78 }
79
80 ++diskd_stats.open.ops;
81 }
82
83 void
create(int flags,mode_t,RefCount<IORequestor> callback)84 DiskdFile::create(int flags, mode_t, RefCount<IORequestor> callback)
85 {
86 debugs(79, 3, "DiskdFile::create: " << this << " creating for " << callback.getRaw());
87 assert (ioRequestor.getRaw() == NULL);
88 ioRequestor = callback;
89 assert (callback.getRaw());
90 mode = flags;
91 ssize_t shm_offset;
92 char *buf = (char *)IO->shm.get(&shm_offset);
93 xstrncpy(buf, path_, SHMBUF_BLKSZ);
94 ioAway();
95 int x = IO->send(_MQD_CREATE,
96 id,
97 this,
98 strlen(buf) + 1,
99 mode,
100 shm_offset,
101 NULL);
102
103 if (x < 0) {
104 int xerrno = errno;
105 ioCompleted();
106 errorOccured = true;
107 // IO->shm.put (shm_offset);
108 debugs(79, DBG_IMPORTANT, "storeDiskdSend CREATE: " << xstrerr(xerrno));
109 notifyClient();
110 ioRequestor = NULL;
111 return;
112 }
113
114 ++diskd_stats.create.ops;
115 }
116
117 void
read(ReadRequest * aRead)118 DiskdFile::read(ReadRequest *aRead)
119 {
120 assert (ioRequestor.getRaw() != NULL);
121 ssize_t shm_offset;
122 char *rbuf = (char *)IO->shm.get(&shm_offset);
123 assert(rbuf);
124 ioAway();
125 int x = IO->send(_MQD_READ,
126 id,
127 this,
128 aRead->len,
129 aRead->offset,
130 shm_offset,
131 aRead);
132
133 if (x < 0) {
134 int xerrno = errno;
135 ioCompleted();
136 errorOccured = true;
137 // IO->shm.put (shm_offset);
138 debugs(79, DBG_IMPORTANT, "storeDiskdSend READ: " << xstrerr(xerrno));
139 notifyClient();
140 ioRequestor = NULL;
141 return;
142 }
143
144 ++diskd_stats.read.ops;
145 }
146
147 void
close()148 DiskdFile::close()
149 {
150 debugs(79, 3, "DiskdFile::close: " << this << " closing for " << ioRequestor.getRaw());
151 assert (ioRequestor.getRaw());
152 ioAway();
153 int x = IO->send(_MQD_CLOSE,
154 id,
155 this,
156 0,
157 0,
158 -1,
159 NULL);
160
161 if (x < 0) {
162 int xerrno = errno;
163 ioCompleted();
164 errorOccured = true;
165 debugs(79, DBG_IMPORTANT, "storeDiskdSend CLOSE: " << xstrerr(xerrno));
166 notifyClient();
167 ioRequestor = NULL;
168 return;
169 }
170
171 ++diskd_stats.close.ops;
172 }
173
174 bool
error() const175 DiskdFile::error() const
176 {
177 return errorOccured;
178 }
179
180 bool
canRead() const181 DiskdFile::canRead() const
182 {
183 return !error();
184 }
185
186 bool
canNotifyClient() const187 DiskdFile::canNotifyClient() const
188 {
189 if (!ioRequestor.getRaw()) {
190 debugs(79, 3, "DiskdFile::canNotifyClient: No ioRequestor to notify");
191 return false;
192 }
193
194 return true;
195 }
196
197 void
notifyClient()198 DiskdFile::notifyClient()
199 {
200 if (!canNotifyClient()) {
201 return;
202 }
203
204 ioRequestor->ioCompletedNotification();
205 }
206
207 void
completed(diomsg * M)208 DiskdFile::completed(diomsg *M)
209 {
210 assert (M->newstyle);
211
212 switch (M->mtype) {
213
214 case _MQD_OPEN:
215 openDone(M);
216 break;
217
218 case _MQD_CREATE:
219 createDone(M);
220 break;
221
222 case _MQD_CLOSE:
223 closeDone(M);
224 break;
225
226 case _MQD_READ:
227 readDone(M);
228 break;
229
230 case _MQD_WRITE:
231 writeDone(M);
232 break;
233
234 case _MQD_UNLINK:
235 assert (0);
236 break;
237
238 default:
239 assert(0);
240 break;
241 }
242 }
243
244 void
openDone(diomsg * M)245 DiskdFile::openDone(diomsg *M)
246 {
247 ++statCounter.syscalls.disk.opens;
248 debugs(79, 3, "storeDiskdOpenDone: status " << M->status);
249
250 if (M->status < 0) {
251 ++diskd_stats.open.fail;
252 errorOccured = true;
253 } else {
254 ++diskd_stats.open.success;
255 }
256
257 ioCompleted();
258 notifyClient();
259 }
260
261 void
createDone(diomsg * M)262 DiskdFile::createDone(diomsg *M)
263 {
264 ++statCounter.syscalls.disk.opens;
265 debugs(79, 3, "storeDiskdCreateDone: status " << M->status);
266
267 if (M->status < 0) {
268 ++diskd_stats.create.fail;
269 errorOccured = true;
270 } else {
271 ++diskd_stats.create.success;
272 }
273
274 ioCompleted();
275 notifyClient();
276 }
277
278 void
write(WriteRequest * aRequest)279 DiskdFile::write(WriteRequest *aRequest)
280 {
281 debugs(79, 3, "DiskdFile::write: this " << (void *)this << ", buf " << (void *)aRequest->buf << ", off " << aRequest->offset << ", len " << aRequest->len);
282 ssize_t shm_offset;
283 char *sbuf = (char *)IO->shm.get(&shm_offset);
284 memcpy(sbuf, aRequest->buf, aRequest->len);
285
286 if (aRequest->free_func)
287 aRequest->free_func(const_cast<char *>(aRequest->buf));
288
289 ioAway();
290
291 int x = IO->send(_MQD_WRITE,
292 id,
293 this,
294 aRequest->len,
295 aRequest->offset,
296 shm_offset,
297 aRequest);
298
299 if (x < 0) {
300 int xerrno = errno;
301 ioCompleted();
302 errorOccured = true;
303 debugs(79, DBG_IMPORTANT, "storeDiskdSend WRITE: " << xstrerr(xerrno));
304 // IO->shm.put (shm_offset);
305 notifyClient();
306 ioRequestor = NULL;
307 return;
308 }
309
310 ++diskd_stats.write.ops;
311 }
312
313 void
ioAway()314 DiskdFile::ioAway()
315 {
316 ++inProgressIOs;
317 }
318
319 void
ioCompleted()320 DiskdFile::ioCompleted()
321 {
322 --inProgressIOs;
323 }
324
325 void
closeDone(diomsg * M)326 DiskdFile::closeDone(diomsg * M)
327 {
328 ++statCounter.syscalls.disk.closes;
329 debugs(79, 3, "DiskdFile::closeDone: status " << M->status);
330
331 if (M->status < 0) {
332 ++diskd_stats.close.fail;
333 errorOccured = true;
334 } else {
335 ++diskd_stats.close.success;
336 }
337
338 ioCompleted();
339
340 if (canNotifyClient())
341 ioRequestor->closeCompleted();
342
343 ioRequestor = NULL;
344 }
345
346 void
readDone(diomsg * M)347 DiskdFile::readDone(diomsg * M)
348 {
349 ++statCounter.syscalls.disk.reads;
350 debugs(79, 3, "DiskdFile::readDone: status " << M->status);
351 assert (M->requestor);
352 ReadRequest::Pointer readRequest = dynamic_cast<ReadRequest *>(M->requestor);
353
354 /* remove the free protection */
355 if (readRequest != NULL) {
356 const uint32_t lcount = readRequest->unlock();
357 if (lcount == 0)
358 debugs(79, DBG_IMPORTANT, "invariant check failed: readRequest reference count is 0");
359 }
360
361 if (M->status < 0) {
362 ++diskd_stats.read.fail;
363 ioCompleted();
364 errorOccured = true;
365 ioRequestor->readCompleted(NULL, -1, DISK_ERROR, readRequest);
366 return;
367 }
368
369 ++diskd_stats.read.success;
370
371 ioCompleted();
372 ioRequestor->readCompleted (IO->shm.buf + M->shm_offset, M->status, DISK_OK, readRequest);
373 }
374
375 void
writeDone(diomsg * M)376 DiskdFile::writeDone(diomsg *M)
377 {
378 ++statCounter.syscalls.disk.writes;
379 debugs(79, 3, "storeDiskdWriteDone: status " << M->status);
380 assert (M->requestor);
381 WriteRequest::Pointer writeRequest = dynamic_cast<WriteRequest *>(M->requestor);
382
383 /* remove the free protection */
384 if (writeRequest != NULL) {
385 const uint32_t lcount = writeRequest->unlock();
386 if (lcount == 0)
387 debugs(79, DBG_IMPORTANT, "invariant check failed: writeRequest reference count is 0");
388 }
389
390 if (M->status < 0) {
391 errorOccured = true;
392 ++diskd_stats.write.fail;
393 ioCompleted();
394 ioRequestor->writeCompleted (DISK_ERROR,0, writeRequest);
395 return;
396 }
397
398 ++diskd_stats.write.success;
399 ioCompleted();
400 ioRequestor->writeCompleted (DISK_OK,M->status, writeRequest);
401 }
402
403 bool
ioInProgress() const404 DiskdFile::ioInProgress()const
405 {
406 return inProgressIOs != 0;
407 }
408
409