Commit 5fecf3a1 authored by Daniel Thompson's avatar Daniel Thompson Committed by Al Viro

staging: android: logger: Fix log corruption regression

Since commit cd678fce ("switch logger to ->write_iter()"), any
attempt to write to the log results in the log data being written over
its own metadata, thus rendering the log unreadable.

The problem was first detected when I ran an Android userspace on the
v3.18-rc1 kernel. However the issue can also be observed with a
non-Android userspace by using echo/cat to write to/from /dev/log_main .

This patch resolves the problem by using a temporary to track the status
of not-yet-committed writes to the log buffer.
Signed-off-by: default avatarDaniel Thompson <daniel.thompson@linaro.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent cac7f242
...@@ -420,7 +420,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -420,7 +420,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct logger_log *log = file_get_log(iocb->ki_filp); struct logger_log *log = file_get_log(iocb->ki_filp);
struct logger_entry header; struct logger_entry header;
struct timespec now; struct timespec now;
size_t len, count; size_t len, count, w_off;
count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD); count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
...@@ -452,11 +452,14 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -452,11 +452,14 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
memcpy(log->buffer + log->w_off, &header, len); memcpy(log->buffer + log->w_off, &header, len);
memcpy(log->buffer, (char *)&header + len, sizeof(header) - len); memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
len = min(count, log->size - log->w_off); /* Work with a copy until we are ready to commit the whole entry */
w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry));
if (copy_from_iter(log->buffer + log->w_off, len, from) != len) { len = min(count, log->size - w_off);
if (copy_from_iter(log->buffer + w_off, len, from) != len) {
/* /*
* Note that by not updating w_off, this abandons the * Note that by not updating log->w_off, this abandons the
* portion of the new entry that *was* successfully * portion of the new entry that *was* successfully
* copied, just above. This is intentional to avoid * copied, just above. This is intentional to avoid
* message corruption from missing fragments. * message corruption from missing fragments.
...@@ -470,7 +473,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -470,7 +473,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
return -EFAULT; return -EFAULT;
} }
log->w_off = logger_offset(log, log->w_off + count); log->w_off = logger_offset(log, w_off + count);
mutex_unlock(&log->mutex); mutex_unlock(&log->mutex);
/* wake up any blocked readers */ /* wake up any blocked readers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment