]> git.ipfire.org Git - thirdparty/squid.git/blob - src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc
Preserve caller context across (and improve) deferred reads (#1025)
[thirdparty/squid.git] / src / DiskIO / DiskThreads / DiskThreadsDiskFile.cc
1 /*
2 * Copyright (C) 1996-2022 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 Disk IO Routines */
10
11 #include "squid.h"
12 #include "comm.h"
13 #include "DiskIO/IORequestor.h"
14 #include "DiskIO/ReadRequest.h"
15 #include "DiskIO/WriteRequest.h"
16 #include "DiskThreadsDiskFile.h"
17 #include "fd.h"
18 #include "fs_io.h"
19 #include "Generic.h"
20 #include "globals.h"
21 #include "StatCounters.h"
22 #include "Store.h"
23
24 #include <cerrno>
25
26 /* === PUBLIC =========================================================== */
27
28 CBDATA_CLASS_INIT(DiskThreadsDiskFile);
29
30 DiskThreadsDiskFile::DiskThreadsDiskFile(char const *aPath)
31 {
32 assert(aPath);
33 debugs(79, 3, "UFSFile::UFSFile: " << aPath);
34 path_ = xstrdup(aPath);
35 }
36
37 DiskThreadsDiskFile::~DiskThreadsDiskFile()
38 {
39 safe_free(path_);
40 doClose();
41 }
42
43 void
44 DiskThreadsDiskFile::open(int flags, mode_t mode, RefCount<IORequestor> callback)
45 {
46 ++statCounter.syscalls.disk.opens;
47 #if !ASYNC_OPEN
48
49 fd = file_open(path_, flags);
50
51 if (fd < 0) {
52 debugs(79, 3, "DiskThreadsDiskFile::open: got failure (" << errno << ")");
53 errorOccured = true;
54 return;
55 }
56
57 #endif
58 ++Opening_FD;
59
60 ioRequestor = callback;
61
62 ++inProgressIOs;
63
64 #if ASYNC_OPEN
65
66 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
67
68 #else
69
70 openDone(fd, NULL, fd, 0);
71
72 #endif
73 }
74
75 void
76 DiskThreadsDiskFile::read(ReadRequest * request)
77 {
78 debugs(79, 3, "DiskThreadsDiskFile::read: " << this << ", size " << request->len);
79 assert (fd > -1);
80 assert (ioRequestor.getRaw());
81 ++statCounter.syscalls.disk.reads;
82 ++inProgressIOs;
83 #if ASYNC_READ
84
85 aioRead(fd, request->offset, request->len, ReadDone, new IoResult<ReadRequest>(this, request));
86 #else
87
88 file_read(fd, request->buf, request->len, request->offset, ReadDone, new IoResult<ReadRequest>(this, request));
89 #endif
90 }
91
92 void
93 DiskThreadsDiskFile::create(int flags, mode_t mode, RefCount<IORequestor> callback)
94 {
95 ++statCounter.syscalls.disk.opens;
96 #if !ASYNC_CREATE
97
98 int fd = file_open(path_, flags);
99
100 if (fd < 0) {
101 debugs(79, 3, "DiskThreadsDiskFile::create: got failure (" << errno << ")");
102 errorOccured = true;
103 return;
104 }
105
106 #endif
107 ++Opening_FD;
108
109 ioRequestor = callback;
110
111 ++inProgressIOs;
112
113 #if ASYNC_CREATE
114
115 aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
116
117 #else
118
119 openDone (fd, NULL, fd, 0);
120
121 #endif
122 }
123
124 bool
125 DiskThreadsDiskFile::error() const
126 {
127 return errorOccured;
128 }
129
130 void
131 DiskThreadsDiskFile::OpenDone(int fd, void *cbdata, const char *buf, int aio_return, int aio_errno)
132 {
133 DiskThreadsDiskFile *myFile = static_cast<DiskThreadsDiskFile *>(cbdata);
134 myFile->openDone (fd, buf, aio_return, aio_errno);
135 }
136
137 void
138 DiskThreadsDiskFile::openDone(int, const char *, int anFD, int errflag)
139 {
140 debugs(79, 3, "DiskThreadsDiskFile::openDone: FD " << anFD << ", errflag " << errflag);
141 --Opening_FD;
142
143 fd = anFD;
144
145 if (errflag || fd < 0) {
146 debugs(79, DBG_CRITICAL, MYNAME << xstrerr(errflag));
147 debugs(79, DBG_IMPORTANT, "\t" << path_);
148 errorOccured = true;
149 } else {
150 ++store_open_disk_fd;
151 commSetCloseOnExec(fd);
152 fd_open(fd, FD_FILE, path_);
153 }
154
155 IORequestor::Pointer t = ioRequestor;
156 --inProgressIOs;
157 t->ioCompletedNotification();
158
159 debugs(79, 3, "DiskThreadsDiskFile::openDone: exiting");
160 }
161
162 void DiskThreadsDiskFile::doClose()
163 {
164 if (fd > -1) {
165 ++statCounter.syscalls.disk.closes;
166 #if ASYNC_CLOSE
167
168 aioClose(fd);
169 fd_close(fd);
170 #else
171
172 aioCancel(fd);
173 file_close(fd);
174 #endif
175
176 --store_open_disk_fd;
177 fd = -1;
178 }
179 }
180
181 void
182 DiskThreadsDiskFile::close()
183 {
184 debugs(79, 3, "DiskThreadsDiskFile::close: " << this << " closing for " << ioRequestor.getRaw());
185
186 if (!ioInProgress()) {
187 doClose();
188 assert (ioRequestor != NULL);
189 ioRequestor->closeCompleted();
190 return;
191 } else {
192 debugs(79, DBG_CRITICAL, "DiskThreadsDiskFile::close: " <<
193 "did NOT close because ioInProgress() is true. now what?");
194 }
195 }
196
197 bool
198 DiskThreadsDiskFile::canRead() const
199 {
200 debugs(79, 3, "DiskThreadsDiskFile::canRead: fd is " << fd);
201 return fd > -1;
202 }
203
204 void
205 DiskThreadsDiskFile::write(WriteRequest * writeRequest)
206 {
207 debugs(79, 3, "DiskThreadsDiskFile::write: FD " << fd);
208 ++statCounter.syscalls.disk.writes;
209 ++inProgressIOs;
210 #if ASYNC_WRITE
211
212 aioWrite(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
213 writeRequest->free_func);
214 #else
215
216 file_write(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
217 writeRequest->free_func);
218 #endif
219 }
220
221 bool
222 DiskThreadsDiskFile::canWrite() const
223 {
224 return fd > -1;
225 }
226
227 bool
228 DiskThreadsDiskFile::ioInProgress() const
229 {
230 return inProgressIOs > 0;
231 }
232
233 /* === STATIC =========================================================== */
234
235 #if ASYNC_READ
236 void
237 DiskThreadsDiskFile::ReadDone(int fd, void *my_data, const char *buf, int len, int errflag)
238 #else
239 void
240 DiskThreadsDiskFile::ReadDone(int fd, const char *buf, int len, int errflag, void *my_data)
241 #endif
242 {
243 IoResult<ReadRequest> * result = static_cast<IoResult<ReadRequest> *>(my_data);
244 assert (result);
245 result->file->readDone(fd, buf, len, errflag, result->request);
246 delete result;
247 }
248
249 void
250 DiskThreadsDiskFile::readDone(int rvfd, const char *buf, int len, int errflag, RefCount<ReadRequest> request)
251 {
252 debugs(79, 3, "DiskThreadsDiskFile::readDone: FD " << rvfd);
253 assert (fd == rvfd);
254
255 ssize_t rlen;
256
257 if (errflag) {
258 debugs(79, 3, "DiskThreadsDiskFile::readDone: got failure (" << errflag << ")");
259 rlen = -1;
260 } else {
261 rlen = (ssize_t) len;
262 }
263
264 #if ASYNC_READ
265 /* translate errflag from errno to Squid disk error */
266 errno = errflag;
267
268 if (errflag)
269 errflag = DISK_ERROR;
270 else
271 errflag = DISK_OK;
272
273 #else
274
275 if (errflag == DISK_EOF)
276 errflag = DISK_OK; /* EOF is signalled by len == 0, not errors... */
277
278 #endif
279
280 --inProgressIOs;
281
282 ioRequestor->readCompleted(buf, rlen, errflag, request);
283 }
284
285 void
286 DiskThreadsDiskFile::
287 #if ASYNC_WRITE
288 WriteDone(int fd, void *my_data, const char *buf, int len, int errflag)
289 #else
290 WriteDone(int fd, int errflag, size_t len, void *my_data)
291 #endif
292 {
293 IoResult<WriteRequest> * result = static_cast<IoResult<WriteRequest> *>(my_data);
294 assert (result);
295 result->file->writeDone(fd, errflag, len, result->request);
296 delete result;
297 }
298
299 void
300 DiskThreadsDiskFile::writeDone(int rvfd, int errflag, size_t len, RefCount<WriteRequest> request)
301 {
302 assert (rvfd == fd);
303 static int loop_detect = 0;
304
305 #if ASYNC_WRITE
306 /* Translate from errno to Squid disk error */
307
308 if (errflag)
309 errflag = errflag == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR;
310 else
311 errflag = DISK_OK;
312
313 #endif
314
315 debugs(79, 3, "DiskThreadsDiskFile::writeDone: FD " << fd << ", len " << len << ", err=" << errflag);
316
317 ++loop_detect;
318 assert(loop_detect < 10);
319
320 --inProgressIOs;
321
322 ioRequestor->writeCompleted(errflag, len, request);
323
324 --loop_detect;
325 }
326
327 /** \cond AUTODOCS_IGNORE */
328 template <class RT>
329 cbdata_type IoResult<RT>::CBDATA_IoResult = CBDATA_UNKNOWN;
330 /** \endcond */
331