mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-01-19 12:28:07 -05:00
I came up with a new way of avoiding the error handling lockup bug in
rsync. It isn't pretty, but it does work and should completely avoid that class of lockup.
This commit is contained in:
18
io.c
18
io.c
@@ -48,6 +48,8 @@ static void check_timeout(void)
|
||||
{
|
||||
extern int am_server, am_daemon;
|
||||
time_t t;
|
||||
|
||||
err_list_push();
|
||||
|
||||
if (!io_timeout) return;
|
||||
|
||||
@@ -339,6 +341,8 @@ static void writefd_unbuffered(int fd,char *buf,int len)
|
||||
int fd_count, count;
|
||||
struct timeval tv;
|
||||
|
||||
err_list_push();
|
||||
|
||||
no_flush++;
|
||||
|
||||
while (total < len) {
|
||||
@@ -462,6 +466,9 @@ static void mplex_write(int fd, enum logcode code, char *buf, int len)
|
||||
void io_flush(void)
|
||||
{
|
||||
int fd = multiplex_out_fd;
|
||||
|
||||
err_list_push();
|
||||
|
||||
if (!io_buffer_count || no_flush) return;
|
||||
|
||||
if (io_multiplexing_out) {
|
||||
@@ -487,6 +494,7 @@ void io_end_buffering(int fd)
|
||||
a socket to be flushed. Do an explicit shutdown to try to prevent this */
|
||||
void io_shutdown(void)
|
||||
{
|
||||
err_list_push();
|
||||
if (multiplex_out_fd != -1) close(multiplex_out_fd);
|
||||
if (io_error_fd != -1) close(io_error_fd);
|
||||
multiplex_out_fd = -1;
|
||||
@@ -498,6 +506,8 @@ static void writefd(int fd,char *buf,int len)
|
||||
{
|
||||
stats.total_written += len;
|
||||
|
||||
err_list_push();
|
||||
|
||||
if (!io_buffer || fd != multiplex_out_fd) {
|
||||
writefd_unbuffered(fd, buf, len);
|
||||
return;
|
||||
@@ -635,14 +645,6 @@ int io_multiplex_write(enum logcode code, char *buf, int len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* write a message to the special error fd */
|
||||
int io_error_write(int f, enum logcode code, char *buf, int len)
|
||||
{
|
||||
if (f == -1) return 0;
|
||||
mplex_write(f, code, buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* stop output multiplexing */
|
||||
void io_multiplexing_close(void)
|
||||
{
|
||||
|
||||
60
log.c
60
log.c
@@ -67,6 +67,59 @@ static char const *rerr_name(int code)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct err_list {
|
||||
struct err_list *next;
|
||||
char *buf;
|
||||
int len;
|
||||
int written; /* how many bytes we have written so far */
|
||||
};
|
||||
|
||||
static struct err_list *err_list_head;
|
||||
static struct err_list *err_list_tail;
|
||||
|
||||
/* add an error message to the pending error list */
|
||||
static void err_list_add(int code, char *buf, int len)
|
||||
{
|
||||
struct err_list *el;
|
||||
el = (struct err_list *)malloc(sizeof(*el));
|
||||
if (!el) exit_cleanup(RERR_MALLOC);
|
||||
el->next = NULL;
|
||||
el->buf = malloc(len+4);
|
||||
if (!el->buf) exit_cleanup(RERR_MALLOC);
|
||||
memcpy(el->buf+4, buf, len);
|
||||
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
|
||||
el->len = len+4;
|
||||
el->written = 0;
|
||||
if (err_list_tail) {
|
||||
err_list_tail->next = el;
|
||||
} else {
|
||||
err_list_head = el;
|
||||
}
|
||||
err_list_tail = el;
|
||||
}
|
||||
|
||||
|
||||
/* try to push errors off the error list onto the wire */
|
||||
void err_list_push(void)
|
||||
{
|
||||
if (log_error_fd == -1) return;
|
||||
|
||||
while (err_list_head) {
|
||||
struct err_list *el = err_list_head;
|
||||
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
|
||||
if (n == -1) break;
|
||||
if (n > 0) {
|
||||
el->written += n;
|
||||
}
|
||||
if (el->written == el->len) {
|
||||
free(el->buf);
|
||||
err_list_head = el->next;
|
||||
if (!err_list_head) err_list_tail = NULL;
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
{
|
||||
@@ -144,6 +197,7 @@ void log_close()
|
||||
void set_error_fd(int fd)
|
||||
{
|
||||
log_error_fd = fd;
|
||||
set_nonblocking(log_error_fd);
|
||||
}
|
||||
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
@@ -167,8 +221,10 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
/* first try to pass it off the our sibling */
|
||||
if (am_server && io_error_write(log_error_fd, code, buf, len)) {
|
||||
/* first try to pass it off to our sibling */
|
||||
if (am_server && log_error_fd != -1) {
|
||||
err_list_add(code, buf, len);
|
||||
err_list_push();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user