staging: android: logger: Fix log corruption regression
authorDaniel Thompson <daniel.thompson@linaro.org>
Mon, 27 Oct 2014 18:51:43 +0000 (18:51 +0000)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 28 Oct 2014 22:24:30 +0000 (18:24 -0400)
Since commit cd678fce4280 ("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: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
drivers/staging/android/logger.c

index 28b93d39a94eb6b76b72d1db051b2f52b48175e7..a673ffa34aa32a3dc6a6363450f5cfbb93599d98 100644 (file)
@@ -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_entry header;
        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);
 
@@ -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, (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
                 * copied, just above.  This is intentional to avoid
                 * message corruption from missing fragments.
@@ -470,7 +473,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
                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);
 
        /* wake up any blocked readers */