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