Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145529024
D41448.id128084.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D41448.id128084.diff
View Options
diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c
--- a/usr.sbin/syslogd/syslogd.c
+++ b/usr.sbin/syslogd/syslogd.c
@@ -117,6 +117,7 @@
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
+#include <sys/sysctl.h>
#if defined(INET) || defined(INET6)
#include <netinet/in.h>
@@ -268,6 +269,13 @@
F_PIPE, /* pipe to program */
};
+struct chunk_list {
+ STAILQ_ENTRY(chunk_list) next;
+ ssize_t size;
+ char *ptr;
+ char buf[];
+};
+
/*
* This structure represents the files that will have log
* copies printed.
@@ -302,6 +310,9 @@
struct {
char f_pname[MAXPATHLEN];
int f_procdesc;
+#define DEAD_QUEUE_TIME 10
+ time_t queue_time;
+ STAILQ_HEAD(chunks_head, chunk_list) chunks;
} f_pipe; /* F_PIPE */
} f_un;
#define fu_uname f_un.f_uname
@@ -434,6 +445,8 @@
static bool needdofsync = true; /* Are any file(s) waiting to be fsynced? */
static struct pidfh *pfh;
static bool RFC3164OutputFormat = true; /* Use legacy format by default. */
+static uint64_t pipes_limit = 16*1024*1024, pipes_size;
+static int kq; /* must be accessed from close_filed() and other functions */
struct iovlist;
@@ -473,6 +486,8 @@
static void wallmsg(struct filed *, struct iovec *, const int iovlen);
static int waitdaemon(int);
static void increase_rcvbuf(int);
+static void pipe_queue_write(struct filed *);
+static void pipe_failed(struct filed *f, int e);
static void
close_filed(struct filed *f)
@@ -495,6 +510,19 @@
break;
case F_PIPE:
if (f->fu_pipe_pd >= 0) {
+ struct chunk_list *tmp;
+ struct chunk_list *cl;
+ struct kevent ev;
+
+ STAILQ_FOREACH_SAFE(cl, &f->f_un.f_pipe.chunks, next, tmp) {
+ STAILQ_REMOVE(&f->f_un.f_pipe.chunks, cl, chunk_list, next);
+ if(pipes_limit) pipes_size -= cl->size;
+ free(cl);
+ }
+ EV_SET(&ev, f->f_file, EVFILT_WRITE, EV_DELETE, 0, 0, f);
+ if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
+ warn("failed to remove kevent from kqueue");
+ }
deadq_enter(f->fu_pipe_pd);
f->fu_pipe_pd = -1;
}
@@ -600,14 +628,21 @@
struct kevent ev;
struct socklist *sl;
pid_t spid;
- int ch, kq, ppipe_w = -1, s;
+ int ch, ppipe_w = -1, s;
char *p;
bool bflag = false, pflag = false, Sflag = false;
+ struct filed *f;
+ uint64_t usermem;
+ size_t usermem_len = sizeof(usermem);
+ if (sysctlbyname("hw.usermem", &usermem, &usermem_len, NULL, 0) >= 0) {
+ pipes_limit = usermem / 128;
+ pipes_limit = MAX(pipes_limit, 128*1024);
+ }
if (madvise(NULL, 0, MADV_PROTECT) != 0)
dprintf("madvise() failed: %s\n", strerror(errno));
- while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:M:m:nNoO:p:P:sS:Tuv"))
+ while ((ch = getopt(argc, argv, "468Aa:b:cCdf:Fg:Hkl:M:m:nNoO:p:P:sS:Tuv"))
!= -1)
switch (ch) {
#ifdef INET
@@ -665,6 +700,10 @@
case 'F': /* run in foreground instead of daemon */
Foreground = true;
break;
+ case 'g':
+ if (expand_number(optarg, &pipes_limit) == -1)
+ errx(EX_USAGE, "invalid global pipe limit: %s, exiting", optarg);
+ break;
case 'H':
RemoteHostname = true;
break;
@@ -886,6 +925,18 @@
if (sl->sl_socket != -1 && sl->sl_recv != NULL)
sl->sl_recv(sl);
break;
+ case EVFILT_WRITE:
+ f = ev.udata;
+ if (f->f_type == F_PIPE && f->fu_pipe_pd >= 0)
+ pipe_queue_write(f);
+ else {
+ fprintf(stderr, "delete illegal EVFILT_WRITE fro fd %d\n", f->f_file);
+ EV_SET(&ev, f->f_file, EVFILT_WRITE, EV_DELETE, 0, 0, f);
+ if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1 && errno != ENOENT)
+ warn("failed to remove kevent from kqueue");
+ errno = 0;
+ }
+ break;
case EVFILT_SIGNAL:
switch (ev.ident) {
case SIGHUP:
@@ -903,6 +954,15 @@
}
break;
}
+ STAILQ_FOREACH(f, &fhead, next) {
+ if (f->f_type != F_PIPE || f->fu_pipe_pd < 0)
+ continue;
+ if (STAILQ_EMPTY(&f->f_un.f_pipe.chunks))
+ continue;
+ if (time(NULL) - f->f_un.f_pipe.queue_time < DEAD_QUEUE_TIME)
+ continue;
+ pipe_failed(f, 0);
+ }
}
}
@@ -1842,6 +1902,121 @@
}
#endif
+static void
+pipe_failed(struct filed *f, int e)
+{
+ char buf[512];
+
+ close_filed(f);
+ if (e == 0) { /* DEAD_QUEUE_TIME timeput */
+ errno = 0;
+ snprintf(buf, sizeof(buf), "pipe to %s stalled more then "
+ __XSTRING(DEAD_QUEUE_TIME) " seconds, killed",
+ f->fu_pipe_pname);
+ logerror(buf);
+ } else if (e < 0) {
+ errno = 0;
+ snprintf(buf, sizeof(buf), "pipes to %s try allocated more "
+ "total limit bytes (%lu), killed",
+ f->fu_pipe_pname, pipes_limit);
+ logerror(buf);
+ } else {
+ errno = e;
+ logerror(f->fu_pipe_pname);
+ }
+}
+
+static void
+pipe_queue_write(struct filed *f)
+{
+ struct chunk_list *cl, *tmp;
+
+ STAILQ_FOREACH_SAFE(cl, &f->f_un.f_pipe.chunks, next, tmp) {
+ ssize_t cnt = write(f->f_file, cl->ptr, cl->size);
+ if (cnt < 0) {
+ if (errno != EAGAIN)
+ pipe_failed(f, errno);
+ return;
+ }
+ f->f_un.f_pipe.queue_time = time(NULL);
+ if (pipes_limit) pipes_size -= cnt;
+ if (cnt != cl->size) {
+ struct kevent ev;
+
+ cl->ptr += cnt;
+ cl->size -= cnt;
+ EV_SET(&ev, f->f_file, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, f);
+ if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
+ warn("failed to enable kevent in kqueue");
+ pidfile_remove(pfh);
+ exit(1);
+ }
+ return;
+ }
+ STAILQ_REMOVE(&f->f_un.f_pipe.chunks, cl, chunk_list, next);
+ free(cl);
+ }
+}
+
+static void
+pipe_add_queue(struct filed *f, struct iovlist *il, size_t skip)
+{
+ char *p;
+ struct chunk_list *cl;
+
+ if (time(NULL) - f->f_un.f_pipe.queue_time >= DEAD_QUEUE_TIME) {
+ pipe_failed(f, 0);
+ return;
+ }
+ if (pipes_limit) {
+ if (pipes_size + il->totalsize - skip > pipes_limit) {
+ pipe_failed(f, -1);
+ return;
+ }
+ pipes_size += il->totalsize - skip;
+ }
+ cl = malloc(sizeof(*cl) + il->totalsize - skip);
+ p = cl->ptr = cl->buf;
+ cl->size = il->totalsize - skip;
+ for(size_t i = 0; i < il->iovcnt; i++) {
+ if (skip < il->iov[i].iov_len) {
+ memcpy(p, skip + (char*)il->iov[i].iov_base, il->iov[i].iov_len - skip);
+ p += il->iov[i].iov_len - skip;
+ skip = 0;
+ } else
+ skip -= il->iov[i].iov_len;
+ }
+ STAILQ_INSERT_TAIL(&f->f_un.f_pipe.chunks, cl, next);
+}
+
+static void
+pipe_write(struct filed *f, struct iovlist *il)
+{
+ struct kevent ev;
+
+ if (!STAILQ_EMPTY(&f->f_un.f_pipe.chunks)) {
+ pipe_add_queue(f, il, 0);
+ return;
+ }
+ ssize_t cnt = writev(f->f_file, il->iov, il->iovcnt);
+ if (cnt == (ssize_t)il->totalsize)
+ return;
+ if (cnt < 0 && errno != EAGAIN) {
+ pipe_failed(f, errno);
+ return;
+ }
+ if (cnt < 0)
+ cnt = 0;
+ f->f_un.f_pipe.queue_time = time(NULL);
+ EV_SET(&ev, f->f_file, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, f);
+ if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
+ warn("failed to enable write pipe kevent in kqueue");
+ pidfile_remove(pfh);
+ exit(1);
+ }
+ pipe_add_queue(f, il, cnt);
+}
+
static void
fprintlog_write(struct filed *f, struct iovlist *il, int flags)
{
@@ -1957,10 +2132,7 @@
break;
}
}
- if (writev(f->f_file, il->iov, il->iovcnt) < 0) {
- logerror(f->fu_pipe_pname);
- close_filed(f);
- }
+ pipe_write(f, il);
break;
case F_CONSOLE:
@@ -3067,6 +3239,8 @@
(void)strlcpy(f->fu_pipe_pname, p + 1,
sizeof(f->fu_pipe_pname));
f->f_type = F_PIPE;
+ f->f_un.f_pipe.queue_time = 0;
+ STAILQ_INIT(&f->f_un.f_pipe.chunks);
break;
case '*':
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 22, 1:22 AM (4 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28925028
Default Alt Text
D41448.id128084.diff (8 KB)
Attached To
Mode
D41448: Buffering syslogd output to pipe
Attached
Detach File
Event Timeline
Log In to Comment