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