unlinkd.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 "SquidTime.h"
21 #include "StatCounters.h"
22 #include "store/Disk.h"
23 #include "tools.h"
24 #include "xusleep.h"
25 
26 /* This code gets linked to Squid */
27 
28 static int unlinkd_wfd = -1;
29 static int unlinkd_rfd = -1;
30 
31 static void * hIpc;
32 static pid_t pid;
33 
34 #define UNLINKD_QUEUE_LIMIT 20
35 
36 void
37 unlinkdUnlink(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, "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  */
126  ++statCounter.syscalls.disk.unlinks;
127  ++queuelen;
128 }
129 
130 void
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);
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;
146  }
147 
148  if (hIpc) {
149  if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
150  getCurrentTime();
151  debugs(2, DBG_IMPORTANT, "unlinkdClose: WARNING: (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 
165  file_close(unlinkd_wfd);
166 
167  if (unlinkd_wfd != unlinkd_rfd)
168  file_close(unlinkd_rfd);
169 
170  unlinkd_wfd = -1;
171 
172  unlinkd_rfd = -1;
173 }
174 
175 #endif
176 
177 bool
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 
190 void
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] = NULL;
201  localhost.setLocalhost();
202 
203  pid = ipcCreate(
204 #if USE_POLL && _SQUID_OSF_
205  /* pipes and poll() don't get along on DUNIX -DW */
206  IPC_STREAM,
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,
218  &unlinkd_rfd,
219  &unlinkd_wfd,
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 
231  commUnsetFdTimeout(unlinkd_rfd);
232  commUnsetFdTimeout(unlinkd_wfd);
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 
243  if (FD_PIPE == fd_table[unlinkd_wfd].type)
244  commUnsetNonBlocking(unlinkd_wfd);
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 
bool unlinkdNeeded(void)
Definition: unlinkd.cc:178
#define fd_table
Definition: fde.h:157
StatCounters statCounter
Definition: StatCounters.cc:12
#define assert(EX)
Definition: assert.h:17
static int unlinkd_wfd
Definition: unlinkd.cc:28
int commUnsetNonBlocking(int fd)
Definition: comm.cc:1109
void fd_note(int fd, const char *s)
Definition: fd.cc:250
void safeunlink(const char *s, int quiet)
Definition: fs_io.cc:497
int type
Definition: errorpage.cc:152
void setLocalhost()
Definition: Address.cc:255
int i
Definition: membanger.c:49
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
static void * hIpc
Definition: unlinkd.cc:31
struct StatCounters::@132 unlink
const char * xstrerr(int error)
Definition: xstrerror.cc:83
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
struct StatCounters::@136 syscalls
#define DBG_IMPORTANT
Definition: Debug.h:46
char * unlinkd
Definition: SquidConfig.h:198
struct StatCounters::@136::@139 disk
void unlinkdClose(void)
Definition: unlinkd.cc:131
#define IPC_STREAM
Definition: defines.h:161
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
void fatal(const char *message)
Definition: fatal.cc:28
virtual bool unlinkdUseful() const =0
whether SwapDir may benefit from unlinkd
static pid_t pid
Definition: unlinkd.cc:32
#define IPC_TCP_SOCKET
Definition: defines.h:146
void const char * buf
Definition: stub_helper.cc:16
struct SquidConfig::@104 Program
static int unlinkd_rfd
Definition: unlinkd.cc:29
time_t getCurrentTime(void)
Get current time.
RefCount< SwapDir > * swapDirs
Definition: SquidConfig.h:62
Definition: enums.h:17
void unlinkdUnlink(const char *path)
Definition: unlinkd.cc:37
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:422
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:539
#define UNLINKD_QUEUE_LIMIT
Definition: unlinkd.cc:34
#define IPC_FIFO
Definition: defines.h:148
void unlinkdInit(void)
Definition: unlinkd.cc:191
void debug_trap(const char *message)
Definition: tools.cc:403
void file_close(int fd)
Definition: fs_io.cc:76
class SquidConfig Config
Definition: SquidConfig.cc:12
#define comm_close(x)
Definition: comm.h:28
#define NULL
Definition: types.h:166
SQUIDCEXTERN int xusleep(unsigned int)
Definition: xusleep.c:20

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors