]> git.ipfire.org Git - thirdparty/squid.git/blob - src/unlinkd.cc
Activate extra compiler checks (#667)
[thirdparty/squid.git] / src / unlinkd.cc
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 02 Unlink Daemon */
10
11 #include "squid.h"
12
13 #if USE_UNLINKD
14 #include "fd.h"
15 #include "fde.h"
16 #include "fs_io.h"
17 #include "globals.h"
18 #include "SquidConfig.h"
19 #include "SquidIpc.h"
20 #include "SquidTime.h"
21 #include "StatCounters.h"
22 #include "store/Disk.h"
23 #include "tools.h"
24 #include "unlinkd.h"
25 #include "xusleep.h"
26
27 /* This code gets linked to Squid */
28
29 static int unlinkd_wfd = -1;
30 static int unlinkd_rfd = -1;
31
32 static void * hIpc;
33 static pid_t pid;
34
35 #define UNLINKD_QUEUE_LIMIT 20
36
37 void
38 unlinkdUnlink(const char *path)
39 {
40 char buf[MAXPATHLEN];
41 int l;
42 int bytes_written;
43 static int queuelen = 0;
44
45 if (unlinkd_wfd < 0) {
46 debug_trap("unlinkdUnlink: unlinkd_wfd < 0");
47 safeunlink(path, 0);
48 return;
49 }
50
51 /*
52 * If the queue length is greater than our limit, then we pause
53 * for a small amount of time, hoping that unlinkd has some
54 * feedback for us. Maybe it just needs a slice of the CPU's
55 * time.
56 */
57 if (queuelen >= UNLINKD_QUEUE_LIMIT) {
58 #if defined(USE_EPOLL) || defined(USE_KQUEUE) || defined(USE_DEVPOLL)
59 /*
60 * DPW 2007-04-23
61 * We can't use fd_set when using epoll() or kqueue(). In
62 * these cases we block for 10 ms.
63 */
64 xusleep(10000);
65 #else
66 /*
67 * DPW 2007-04-23
68 * When we can use select, block for up to 100 ms.
69 */
70 struct timeval to;
71 fd_set R;
72 FD_ZERO(&R);
73 FD_SET(unlinkd_rfd, &R);
74 to.tv_sec = 0;
75 to.tv_usec = 100000;
76 select(unlinkd_rfd + 1, &R, NULL, NULL, &to);
77 #endif
78 }
79
80 /*
81 * If there is at least one outstanding unlink request, then
82 * try to read a response. If there's nothing to read we'll
83 * get an EWOULDBLOCK or whatever. If we get a response, then
84 * decrement the queue size by the number of newlines read.
85 */
86 if (queuelen > 0) {
87 int bytes_read;
88 int i;
89 char rbuf[512];
90 bytes_read = read(unlinkd_rfd, rbuf, 511);
91
92 if (bytes_read > 0) {
93 rbuf[bytes_read] = '\0';
94
95 for (i = 0; i < bytes_read; ++i)
96 if ('\n' == rbuf[i])
97 --queuelen;
98
99 assert(queuelen >= 0);
100 }
101 }
102
103 l = strlen(path);
104 assert(l < MAXPATHLEN);
105 xstrncpy(buf, path, MAXPATHLEN);
106 buf[l] = '\n';
107 ++l;
108 bytes_written = write(unlinkd_wfd, buf, l);
109
110 if (bytes_written < 0) {
111 int xerrno = errno;
112 debugs(2, DBG_IMPORTANT, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerr(xerrno));
113 safeunlink(path, 0);
114 return;
115 } else if (bytes_written != l) {
116 debugs(2, DBG_IMPORTANT, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes");
117 safeunlink(path, 0);
118 return;
119 }
120
121 ++statCounter.unlink.requests;
122 /*
123 * Increment this syscalls counter here, even though the syscall
124 * is executed by the helper process. We try to be consistent
125 * in counting unlink operations.
126 */
127 ++statCounter.syscalls.disk.unlinks;
128 ++queuelen;
129 }
130
131 void
132 unlinkdClose(void)
133 #if _SQUID_WINDOWS_
134 {
135
136 if (unlinkd_wfd > -1) {
137 debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd);
138 shutdown(unlinkd_wfd, SD_BOTH);
139 comm_close(unlinkd_wfd);
140
141 if (unlinkd_wfd != unlinkd_rfd)
142 comm_close(unlinkd_rfd);
143
144 unlinkd_wfd = -1;
145
146 unlinkd_rfd = -1;
147 }
148
149 if (hIpc) {
150 if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
151 getCurrentTime();
152 debugs(2, DBG_IMPORTANT, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds");
153 }
154
155 CloseHandle(hIpc);
156 }
157 }
158 #else
159 {
160
161 if (unlinkd_wfd < 0)
162 return;
163
164 debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd);
165
166 file_close(unlinkd_wfd);
167
168 if (unlinkd_wfd != unlinkd_rfd)
169 file_close(unlinkd_rfd);
170
171 unlinkd_wfd = -1;
172
173 unlinkd_rfd = -1;
174 }
175
176 #endif
177
178 bool
179 unlinkdNeeded(void)
180 {
181 // we should start unlinkd if there are any cache_dirs using it
182 for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
183 const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
184 if (sd->unlinkdUseful())
185 return true;
186 }
187
188 return false;
189 }
190
191 void
192 unlinkdInit(void)
193 {
194 if (unlinkd_wfd >= 0)
195 return; // unlinkd already started
196
197 const char *args[2];
198 Ip::Address localhost;
199
200 args[0] = "(unlinkd)";
201 args[1] = NULL;
202 localhost.setLocalhost();
203
204 pid = ipcCreate(
205 #if USE_POLL && _SQUID_OSF_
206 /* pipes and poll() don't get along on DUNIX -DW */
207 IPC_STREAM,
208 #elif _SQUID_WINDOWS_
209 /* select() will fail on a pipe */
210 IPC_TCP_SOCKET,
211 #else
212 /* We currently need to use FIFO.. see below */
213 IPC_FIFO,
214 #endif
215 Config.Program.unlinkd,
216 args,
217 "unlinkd",
218 localhost,
219 &unlinkd_rfd,
220 &unlinkd_wfd,
221 &hIpc);
222
223 if (pid < 0)
224 fatal("Failed to create unlinkd subprocess");
225
226 xusleep(250000);
227
228 fd_note(unlinkd_wfd, "squid -> unlinkd");
229
230 fd_note(unlinkd_rfd, "unlinkd -> squid");
231
232 commUnsetFdTimeout(unlinkd_rfd);
233 commUnsetFdTimeout(unlinkd_wfd);
234
235 /*
236 * unlinkd_rfd should already be non-blocking because of
237 * ipcCreate. We change unlinkd_wfd to blocking mode because
238 * we never want to lose an unlink request, and we don't have
239 * code to retry if we get EWOULDBLOCK. Unfortunately, we can
240 * do this only for the IPC_FIFO case.
241 */
242 assert(fd_table[unlinkd_rfd].flags.nonblocking);
243
244 if (FD_PIPE == fd_table[unlinkd_wfd].type)
245 commUnsetNonBlocking(unlinkd_wfd);
246
247 debugs(2, DBG_IMPORTANT, "Unlinkd pipe opened on FD " << unlinkd_wfd);
248
249 #if _SQUID_WINDOWS_
250
251 debugs(2, 4, "Unlinkd handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
252
253 #endif
254
255 }
256 #endif /* USE_UNLINKD */
257