]>
Commit | Line | Data |
---|---|---|
429fdbec | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 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 | |
c4ad1349 | 14 | #include "fd.h" |
582c2af2 | 15 | #include "fde.h" |
b3f7fd88 | 16 | #include "fs_io.h" |
582c2af2 | 17 | #include "globals.h" |
2745fea5 | 18 | #include "SquidConfig.h" |
96097880 | 19 | #include "SquidIpc.h" |
5c3c8c03 | 20 | #include "SquidTime.h" |
e4f1fdae | 21 | #include "StatCounters.h" |
2745fea5 | 22 | #include "store/Disk.h" |
5bed43d6 | 23 | #include "tools.h" |
602d9612 | 24 | #include "xusleep.h" |
528b2c61 | 25 | |
429fdbec | 26 | /* This code gets linked to Squid */ |
27 | ||
06f8f350 | 28 | static int unlinkd_wfd = -1; |
29 | static int unlinkd_rfd = -1; | |
429fdbec | 30 | |
b5d712b5 | 31 | static void * hIpc; |
5c3c8c03 | 32 | static pid_t pid; |
33 | ||
9bc73deb | 34 | #define UNLINKD_QUEUE_LIMIT 20 |
35 | ||
429fdbec | 36 | void |
37 | unlinkdUnlink(const char *path) | |
38 | { | |
9bc73deb | 39 | char buf[MAXPATHLEN]; |
429fdbec | 40 | int l; |
e053c141 | 41 | int bytes_written; |
9bc73deb | 42 | static int queuelen = 0; |
62e76326 | 43 | |
06f8f350 | 44 | if (unlinkd_wfd < 0) { |
62e76326 | 45 | debug_trap("unlinkdUnlink: unlinkd_wfd < 0"); |
46 | safeunlink(path, 0); | |
47 | return; | |
429fdbec | 48 | } |
62e76326 | 49 | |
9bc73deb | 50 | /* |
9ece7c7c | 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 | */ | |
9bc73deb | 56 | if (queuelen >= UNLINKD_QUEUE_LIMIT) { |
a1ad2f9b | 57 | #if defined(USE_EPOLL) || defined(USE_KQUEUE) || defined(USE_DEVPOLL) |
26ac0430 AJ |
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); | |
9ece7c7c | 64 | #else |
26ac0430 AJ |
65 | /* |
66 | * DPW 2007-04-23 | |
67 | * When we can use select, block for up to 100 ms. | |
68 | */ | |
e7a67ff1 | 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); | |
9ece7c7c | 76 | #endif |
9bc73deb | 77 | } |
62e76326 | 78 | |
9bc73deb | 79 | /* |
62e76326 | 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 | */ | |
9bc73deb | 85 | if (queuelen > 0) { |
e053c141 | 86 | int bytes_read; |
62e76326 | 87 | int i; |
88 | char rbuf[512]; | |
e053c141 | 89 | bytes_read = read(unlinkd_rfd, rbuf, 511); |
62e76326 | 90 | |
e053c141 FC |
91 | if (bytes_read > 0) { |
92 | rbuf[bytes_read] = '\0'; | |
62e76326 | 93 | |
5db6bf73 | 94 | for (i = 0; i < bytes_read; ++i) |
62e76326 | 95 | if ('\n' == rbuf[i]) |
5e263176 | 96 | --queuelen; |
62e76326 | 97 | |
98 | assert(queuelen >= 0); | |
99 | } | |
9bc73deb | 100 | } |
62e76326 | 101 | |
9bc73deb | 102 | l = strlen(path); |
103 | assert(l < MAXPATHLEN); | |
104 | xstrncpy(buf, path, MAXPATHLEN); | |
5db6bf73 FC |
105 | buf[l] = '\n'; |
106 | ++l; | |
e053c141 | 107 | bytes_written = write(unlinkd_wfd, buf, l); |
62e76326 | 108 | |
e053c141 | 109 | if (bytes_written < 0) { |
b69e9ffa AJ |
110 | int xerrno = errno; |
111 | debugs(2, DBG_IMPORTANT, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerr(xerrno)); | |
62e76326 | 112 | safeunlink(path, 0); |
113 | return; | |
e053c141 | 114 | } else if (bytes_written != l) { |
e0236918 | 115 | debugs(2, DBG_IMPORTANT, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes"); |
62e76326 | 116 | safeunlink(path, 0); |
117 | return; | |
9bc73deb | 118 | } |
62e76326 | 119 | |
e4f1fdae | 120 | ++statCounter.unlink.requests; |
5f0c8452 | 121 | /* |
62e76326 | 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 | */ | |
e4f1fdae | 126 | ++statCounter.syscalls.disk.unlinks; |
5db6bf73 | 127 | ++queuelen; |
429fdbec | 128 | } |
129 | ||
130 | void | |
131 | unlinkdClose(void) | |
7aa9bb3e | 132 | #if _SQUID_WINDOWS_ |
5c3c8c03 | 133 | { |
134 | ||
26ac0430 | 135 | if (unlinkd_wfd > -1) { |
e0236918 | 136 | debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd); |
5c3c8c03 | 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; | |
c521ad17 | 146 | } |
5c3c8c03 | 147 | |
26ac0430 | 148 | if (hIpc) { |
5c3c8c03 | 149 | if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) { |
150 | getCurrentTime(); | |
e0236918 | 151 | debugs(2, DBG_IMPORTANT, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds"); |
5c3c8c03 | 152 | } |
153 | ||
154 | CloseHandle(hIpc); | |
155 | } | |
156 | } | |
157 | #else | |
429fdbec | 158 | { |
5c3c8c03 | 159 | |
3502d32f | 160 | if (unlinkd_wfd < 0) |
62e76326 | 161 | return; |
162 | ||
e0236918 | 163 | debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd); |
62e76326 | 164 | |
06f8f350 | 165 | file_close(unlinkd_wfd); |
62e76326 | 166 | |
18e72ae1 | 167 | if (unlinkd_wfd != unlinkd_rfd) |
62e76326 | 168 | file_close(unlinkd_rfd); |
169 | ||
06f8f350 | 170 | unlinkd_wfd = -1; |
62e76326 | 171 | |
06f8f350 | 172 | unlinkd_rfd = -1; |
429fdbec | 173 | } |
174 | ||
5c3c8c03 | 175 | #endif |
176 | ||
c521ad17 DK |
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 | ||
429fdbec | 190 | void |
191 | unlinkdInit(void) | |
192 | { | |
c521ad17 DK |
193 | if (unlinkd_wfd >= 0) |
194 | return; // unlinkd already started | |
195 | ||
a2c963ae | 196 | const char *args[2]; |
b7ac5457 | 197 | Ip::Address localhost; |
62e76326 | 198 | |
06f8f350 | 199 | args[0] = "(unlinkd)"; |
200 | args[1] = NULL; | |
4dd643d5 | 201 | localhost.setLocalhost(); |
cc192b50 | 202 | |
b5d712b5 | 203 | pid = ipcCreate( |
8a09e810 | 204 | #if USE_POLL && _SQUID_OSF_ |
b5d712b5 | 205 | /* pipes and poll() don't get along on DUNIX -DW */ |
206 | IPC_STREAM, | |
7aa9bb3e | 207 | #elif _SQUID_WINDOWS_ |
26ac0430 AJ |
208 | /* select() will fail on a pipe */ |
209 | IPC_TCP_SOCKET, | |
2b9a692c | 210 | #else |
26ac0430 AJ |
211 | /* We currently need to use FIFO.. see below */ |
212 | IPC_FIFO, | |
2b9a692c | 213 | #endif |
b5d712b5 | 214 | Config.Program.unlinkd, |
215 | args, | |
216 | "unlinkd", | |
cc192b50 | 217 | localhost, |
b5d712b5 | 218 | &unlinkd_rfd, |
219 | &unlinkd_wfd, | |
220 | &hIpc); | |
62e76326 | 221 | |
5c3c8c03 | 222 | if (pid < 0) |
62e76326 | 223 | fatal("Failed to create unlinkd subprocess"); |
b5d712b5 | 224 | |
9ece7c7c | 225 | xusleep(250000); |
b5d712b5 | 226 | |
06f8f350 | 227 | fd_note(unlinkd_wfd, "squid -> unlinkd"); |
b5d712b5 | 228 | |
06f8f350 | 229 | fd_note(unlinkd_rfd, "unlinkd -> squid"); |
b5d712b5 | 230 | |
933dd095 AJ |
231 | commUnsetFdTimeout(unlinkd_rfd); |
232 | commUnsetFdTimeout(unlinkd_wfd); | |
b5d712b5 | 233 | |
9bc73deb | 234 | /* |
62e76326 | 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 | */ | |
7e3ce7b9 | 241 | assert(fd_table[unlinkd_rfd].flags.nonblocking); |
b5d712b5 | 242 | |
7e3ce7b9 | 243 | if (FD_PIPE == fd_table[unlinkd_wfd].type) |
62e76326 | 244 | commUnsetNonBlocking(unlinkd_wfd); |
b5d712b5 | 245 | |
e0236918 | 246 | debugs(2, DBG_IMPORTANT, "Unlinkd pipe opened on FD " << unlinkd_wfd); |
5c3c8c03 | 247 | |
7aa9bb3e | 248 | #if _SQUID_WINDOWS_ |
5c3c8c03 | 249 | |
4a7a3d56 | 250 | debugs(2, 4, "Unlinkd handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid); |
5c3c8c03 | 251 | |
252 | #endif | |
253 | ||
429fdbec | 254 | } |
b6b42084 | 255 | #endif /* USE_UNLINKD */ |
f53969cc | 256 |