]> git.ipfire.org Git - thirdparty/squid.git/blame - src/unlinkd.cc
SourceLayout: Move time related tools to time/libtime.la (#1001)
[thirdparty/squid.git] / src / unlinkd.cc
CommitLineData
429fdbec 1/*
bf95c10a 2 * Copyright (C) 1996-2022 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"
602d9612 24#include "xusleep.h"
528b2c61 25
429fdbec 26/* This code gets linked to Squid */
27
06f8f350 28static int unlinkd_wfd = -1;
29static int unlinkd_rfd = -1;
429fdbec 30
b5d712b5 31static void * hIpc;
5c3c8c03 32static pid_t pid;
33
9bc73deb 34#define UNLINKD_QUEUE_LIMIT 20
35
429fdbec 36void
37unlinkdUnlink(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 110 int xerrno = errno;
d816f28d 111 debugs(2, DBG_IMPORTANT, "ERROR: 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
130void
131unlinkdClose(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();
d816f28d 151 debugs(2, DBG_IMPORTANT, "WARNING: unlinkdClose: (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
177bool
178unlinkdNeeded(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 190void
191unlinkdInit(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