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