unlinkd.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 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 "StatCounters.h"
21#include "store/Disk.h"
22#include "tools.h"
23#include "unlinkd.h"
24#include "xusleep.h"
25
26/* This code gets linked to Squid */
27
28static int unlinkd_wfd = -1;
29static int unlinkd_rfd = -1;
30
31static void * hIpc;
32static pid_t pid;
33
34#define UNLINKD_QUEUE_LIMIT 20
35
36void
37unlinkdUnlink(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, "ERROR: 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
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 */
127 ++queuelen;
128}
129
130void
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);
139
142
143 unlinkd_wfd = -1;
144
145 unlinkd_rfd = -1;
146 }
147
148 if (hIpc) {
149 if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
151 debugs(2, DBG_IMPORTANT, "WARNING: unlinkdClose: (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
166
169
170 unlinkd_wfd = -1;
171
172 unlinkd_rfd = -1;
173}
174
175#endif
176
177bool
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) {
183 if (sd->unlinkdUseful())
184 return true;
185 }
186
187 return false;
188}
189
190void
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] = nullptr;
201 localhost.setLocalhost();
202
203 pid = ipcCreate(
204#if USE_POLL && _SQUID_OSF_
205 /* pipes and poll() don't get along on DUNIX -DW */
207#elif _SQUID_WINDOWS_
208 /* select() will fail on a pipe */
210#else
211 /* We currently need to use FIFO.. see below */
212 IPC_FIFO,
213#endif
215 args,
216 "unlinkd",
217 localhost,
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
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
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
class SquidConfig Config
Definition: SquidConfig.cc:12
StatCounters statCounter
Definition: StatCounters.cc:12
#define assert(EX)
Definition: assert.h:19
void setLocalhost()
Definition: Address.cc:255
struct SquidConfig::@104 Program
char * unlinkd
Definition: SquidConfig.h:203
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:421
struct StatCounters::@136 syscalls
struct StatCounters::@132 unlink
struct StatCounters::@136::@140 disk
RefCount< SwapDir > * swapDirs
Definition: SquidConfig.h:66
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:576
int commUnsetNonBlocking(int fd)
Definition: comm.cc:1097
#define comm_close(x)
Definition: comm.h:27
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define IPC_STREAM
Definition: defines.h:106
#define IPC_FIFO
Definition: defines.h:93
#define IPC_TCP_SOCKET
Definition: defines.h:91
@ FD_PIPE
Definition: enums.h:17
int type
Definition: errorpage.cc:152
void fatal(const char *message)
Definition: fatal.cc:28
void fd_note(int fd, const char *s)
Definition: fd.cc:217
#define fd_table
Definition: fde.h:189
void safeunlink(const char *s, int quiet)
Definition: fs_io.cc:469
void file_close(int fd)
Definition: fs_io.cc:73
pid_t ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
Definition: ipc.cc:62
#define MAXPATHLEN
Definition: stdio.h:62
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
void debug_trap(const char *message)
Definition: tools.cc:455
#define NULL
Definition: types.h:166
void unlinkdUnlink(const char *path)
Definition: unlinkd.cc:37
bool unlinkdNeeded(void)
Definition: unlinkd.cc:178
void unlinkdClose(void)
Definition: unlinkd.cc:131
void unlinkdInit(void)
Definition: unlinkd.cc:191
static void * hIpc
Definition: unlinkd.cc:31
static int unlinkd_rfd
Definition: unlinkd.cc:29
static pid_t pid
Definition: unlinkd.cc:32
static int unlinkd_wfd
Definition: unlinkd.cc:28
#define UNLINKD_QUEUE_LIMIT
Definition: unlinkd.cc:34
const char * xstrerr(int error)
Definition: xstrerror.cc:83
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
SQUIDCEXTERN int xusleep(unsigned int)
Definition: xusleep.c:20

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors