|
@@ -411,69 +411,18 @@ static void fix_up_readers(struct logger_log *log, size_t len)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * do_write_log - writes 'len' bytes from 'buf' to 'log'
|
|
|
- *
|
|
|
- * The caller needs to hold log->mutex.
|
|
|
- */
|
|
|
-static void do_write_log(struct logger_log *log, const void *buf, size_t count)
|
|
|
-{
|
|
|
- size_t len;
|
|
|
-
|
|
|
- len = min(count, log->size - log->w_off);
|
|
|
- memcpy(log->buffer + log->w_off, buf, len);
|
|
|
-
|
|
|
- if (count != len)
|
|
|
- memcpy(log->buffer, buf + len, count - len);
|
|
|
-
|
|
|
- log->w_off = logger_offset(log, log->w_off + count);
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to
|
|
|
- * the log 'log'
|
|
|
- *
|
|
|
- * The caller needs to hold log->mutex.
|
|
|
- *
|
|
|
- * Returns 'count' on success, negative error code on failure.
|
|
|
- */
|
|
|
-static ssize_t do_write_log_from_user(struct logger_log *log,
|
|
|
- const void __user *buf, size_t count)
|
|
|
-{
|
|
|
- size_t len;
|
|
|
-
|
|
|
- len = min(count, log->size - log->w_off);
|
|
|
- if (len && copy_from_user(log->buffer + log->w_off, buf, len))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- if (count != len)
|
|
|
- if (copy_from_user(log->buffer, buf + len, count - len))
|
|
|
- /*
|
|
|
- * Note that by not updating 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.
|
|
|
- */
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- log->w_off = logger_offset(log, log->w_off + count);
|
|
|
-
|
|
|
- return count;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * logger_aio_write - our write method, implementing support for write(),
|
|
|
+ * logger_write_iter - our write method, implementing support for write(),
|
|
|
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
|
|
|
* them above all else.
|
|
|
*/
|
|
|
-static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|
|
- unsigned long nr_segs, loff_t ppos)
|
|
|
+static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|
|
{
|
|
|
struct logger_log *log = file_get_log(iocb->ki_filp);
|
|
|
- size_t orig;
|
|
|
struct logger_entry header;
|
|
|
struct timespec now;
|
|
|
- ssize_t ret = 0;
|
|
|
+ size_t len, count;
|
|
|
+
|
|
|
+ count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
|
|
|
|
|
|
now = current_kernel_time();
|
|
|
|
|
@@ -482,7 +431,7 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|
|
header.sec = now.tv_sec;
|
|
|
header.nsec = now.tv_nsec;
|
|
|
header.euid = current_euid();
|
|
|
- header.len = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
|
|
|
+ header.len = count;
|
|
|
header.hdr_size = sizeof(struct logger_entry);
|
|
|
|
|
|
/* null writes succeed, return zero */
|
|
@@ -491,8 +440,6 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
|
|
mutex_lock(&log->mutex);
|
|
|
|
|
|
- orig = log->w_off;
|
|
|
-
|
|
|
/*
|
|
|
* Fix up any readers, pulling them forward to the first readable
|
|
|
* entry after (what will be) the new write offset. We do this now
|
|
@@ -501,33 +448,35 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|
|
*/
|
|
|
fix_up_readers(log, sizeof(struct logger_entry) + header.len);
|
|
|
|
|
|
- do_write_log(log, &header, sizeof(struct logger_entry));
|
|
|
-
|
|
|
- while (nr_segs-- > 0) {
|
|
|
- size_t len;
|
|
|
- ssize_t nr;
|
|
|
+ len = min(sizeof(header), log->size - log->w_off);
|
|
|
+ memcpy(log->buffer + log->w_off, &header, len);
|
|
|
+ memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
|
|
|
|
|
|
- /* figure out how much of this vector we can keep */
|
|
|
- len = min_t(size_t, iov->iov_len, header.len - ret);
|
|
|
+ len = min(count, log->size - log->w_off);
|
|
|
|
|
|
- /* write out this segment's payload */
|
|
|
- nr = do_write_log_from_user(log, iov->iov_base, len);
|
|
|
- if (unlikely(nr < 0)) {
|
|
|
- log->w_off = orig;
|
|
|
- mutex_unlock(&log->mutex);
|
|
|
- return nr;
|
|
|
- }
|
|
|
+ if (copy_from_iter(log->buffer + log->w_off, len, from) != len) {
|
|
|
+ /*
|
|
|
+ * Note that by not updating 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.
|
|
|
+ */
|
|
|
+ mutex_unlock(&log->mutex);
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
|
|
|
- iov++;
|
|
|
- ret += nr;
|
|
|
+ if (copy_from_iter(log->buffer, count - len, from) != count - len) {
|
|
|
+ mutex_unlock(&log->mutex);
|
|
|
+ return -EFAULT;
|
|
|
}
|
|
|
|
|
|
+ log->w_off = logger_offset(log, log->w_off + count);
|
|
|
mutex_unlock(&log->mutex);
|
|
|
|
|
|
/* wake up any blocked readers */
|
|
|
wake_up_interruptible(&log->wq);
|
|
|
|
|
|
- return ret;
|
|
|
+ return len;
|
|
|
}
|
|
|
|
|
|
static struct logger_log *get_log_from_minor(int minor)
|
|
@@ -736,7 +685,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
static const struct file_operations logger_fops = {
|
|
|
.owner = THIS_MODULE,
|
|
|
.read = logger_read,
|
|
|
- .aio_write = logger_aio_write,
|
|
|
+ .write_iter = logger_write_iter,
|
|
|
.poll = logger_poll,
|
|
|
.unlocked_ioctl = logger_ioctl,
|
|
|
.compat_ioctl = logger_ioctl,
|