From a78ca49d579dcde3d144c8021c2fa180c1843377 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 10 Dec 2021 11:25:18 +0100 Subject: [PATCH] [WIP] TM1 logger Change-Id: I322960e76092fe6570be499d17bec44e2b111680 --- kernel/logger-tm1.c | 313 +++++++++++++++++++--- kernel/logger.c | 3 +- packaging/linux-tizen-modules-source.spec | 2 + 3 files changed, 281 insertions(+), 37 deletions(-) diff --git a/kernel/logger-tm1.c b/kernel/logger-tm1.c index f36a087..7504497 100644 --- a/kernel/logger-tm1.c +++ b/kernel/logger-tm1.c @@ -19,7 +19,14 @@ #define pr_fmt(fmt) "logger: " fmt -#include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) +# include +#else +# include +#endif + #include #include #include @@ -29,9 +36,11 @@ #include #include #include -#include "logger.h" +#include +#include +#include -#include +#include "logger.h" /** * struct logger_log - represents a specific log, such as 'main' or 'radio' @@ -63,6 +72,26 @@ struct logger_log { static LIST_HEAD(log_list); +/** + * struct log_writer - a logging device open for writing + * @log: The associated log + * @list: The associated entry in @logger_log's list + * @b_off: The current position in @buf + * @tag: A tag to be attached to messages + * @prio: Default message priority value + * @buff: Temporary space to assemble messages. + */ +struct logger_writer { + struct logger_log *log; + struct task_struct *owner; + struct task_struct *b_owner; + struct logger_entry b_header; + size_t b_off; + size_t tag_len; + char *tag; + int prio; + char *buffer; +}; /** * struct logger_reader - a logging device open for reading @@ -89,7 +118,6 @@ static size_t logger_offset(struct logger_log *log, size_t n) return n & (log->size - 1); } - /* * file_get_log - Given a file structure, return the associated log * @@ -106,11 +134,15 @@ static size_t logger_offset(struct logger_log *log, size_t n) */ static inline struct logger_log *file_get_log(struct file *file) { + struct logger_writer *writer = file->private_data; + if (file->f_mode & FMODE_READ) { struct logger_reader *reader = file->private_data; + return reader->log; - } else - return file->private_data; + } + + return writer->log; } /* @@ -121,13 +153,15 @@ static inline struct logger_log *file_get_log(struct file *file) * the log entry spans the end and beginning of the circular buffer. */ static struct logger_entry *get_entry_header(struct logger_log *log, - size_t off, struct logger_entry *scratch) + size_t off, + struct logger_entry *scratch) { size_t len = min(sizeof(struct logger_entry), log->size - off); + if (len != sizeof(struct logger_entry)) { - memcpy(((void *) scratch), log->buffer + off, len); - memcpy(((void *) scratch) + len, log->buffer, - sizeof(struct logger_entry) - len); + memcpy(((void *)scratch), log->buffer + off, len); + memcpy(((void *)scratch) + len, log->buffer, + sizeof(struct logger_entry) - len); return scratch; } @@ -157,12 +191,11 @@ static size_t get_user_hdr_len(int ver) { if (ver < 2) return sizeof(struct user_logger_entry_compat); - else - return sizeof(struct logger_entry); + return sizeof(struct logger_entry); } static ssize_t copy_header_to_user(int ver, struct logger_entry *entry, - char __user *buf) + char __user *buf) { void *hdr; size_t hdr_len; @@ -212,7 +245,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log, count -= get_user_hdr_len(reader->r_ver); buf += get_user_hdr_len(reader->r_ver); msg_start = logger_offset(log, - reader->r_off + sizeof(struct logger_entry)); + reader->r_off + sizeof(struct logger_entry)); /* * We read from the msg in two disjoint operations. First, we read from @@ -242,7 +275,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log, * 'log->buffer' which contains the first entry readable by 'euid' */ static size_t get_next_entry_by_uid(struct logger_log *log, - size_t off, kuid_t euid) + size_t off, kuid_t euid) { while (off != log->w_off) { struct logger_entry *entry; @@ -428,6 +461,112 @@ static void do_write_log(struct logger_log *log, const void *buf, size_t count) } +static struct file *replace_file(struct files_struct *files, + struct file *oldf, + struct file *newf) +{ + struct file *file = NULL; + struct fdtable *fdt; + unsigned int i; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + for (i = 0; i < fdt->max_fds && file != oldf; i++) { + if (fdt->fd[i] == oldf) { + file = xchg(&fdt->fd[i], newf); + } + } + spin_unlock(&files->file_lock); + + if (file) + filp_close(file, files); + + return file; +} + +static struct file *make_new_file(struct file *file) +{ + struct logger_writer *writer = file->private_data; + struct logger_writer *nwriter; + struct file *nfile; + char *pbuf, *p; + + pbuf = kzalloc(PATH_MAX, GFP_KERNEL); + if (!pbuf) { + return ERR_PTR(-ENOMEM); + } + + p = d_path(&file->f_path, pbuf, PATH_MAX); + if (!p) { + kfree(pbuf); + return ERR_PTR(-EFAULT); + } + + nfile = filp_open(p, O_WRONLY, 0); + kfree(pbuf); + if (IS_ERR(nfile)) + return nfile; + + nwriter = nfile->private_data; + nwriter->prio = writer->prio; + nwriter->tag = kstrdup(writer->tag, GFP_KERNEL); + nwriter->tag_len = writer->tag_len; + + if (!replace_file(current->files, file, nfile)) { + filp_close(nfile, current->files); + return ERR_PTR(-EFAULT); + } + + return nfile; +} + +static void write_log_data(struct logger_log *log, + struct logger_entry *header, + struct logger_writer *writer, + size_t chunk_len) +{ + size_t len, w_off; + + /* header */ + len = min(sizeof(struct logger_entry), log->size - log->w_off); + memcpy(log->buffer + log->w_off, header, len); + memcpy(log->buffer, (char *)header + len, sizeof(struct logger_entry) - len); + w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry)); + + /* priority */ + log->buffer[w_off] = (unsigned char)writer->prio; + w_off = logger_offset(log, w_off + 1); + + /* tag */ + len = min_t(size_t, writer->tag_len + 1, log->size - w_off); + memcpy(log->buffer + w_off, writer->tag, len); + memcpy(log->buffer, writer->tag + len, writer->tag_len + 1 - len); + w_off = logger_offset(log, w_off + writer->tag_len + 1); + + /* message */ + len = min(chunk_len, log->size - w_off); + memcpy(log->buffer + w_off, writer->buffer, len); + memcpy(log->buffer, writer->buffer + len, chunk_len - len); + log->w_off = logger_offset(log, w_off + chunk_len); +} + +static void flush_thread_data(struct file* file) +{ + struct logger_writer *writer = file->private_data; + struct logger_log *log = file_get_log(file); + size_t chunk_len = 0; + + chunk_len = writer->b_off + 1; + writer->b_header.len = chunk_len + writer->tag_len + 2; + + fix_up_readers(log, sizeof(struct logger_entry) + writer->b_header.len); + + write_log_data(log, &writer->b_header, writer, chunk_len); + + writer->b_off = 0; + writer->buffer[0] = '\0'; +} + /* * do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to * the log 'log' @@ -468,13 +607,27 @@ static ssize_t do_write_log_from_user(struct logger_log *log, static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { - struct logger_log *log = file_get_log(iocb->ki_filp); - size_t orig; + struct file *file = iocb->ki_filp; + struct logger_writer *writer = file->private_data; + struct logger_log *log = file_get_log(file); struct logger_entry header; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) + struct timespec64 now; +#else struct timespec now; +#endif + size_t orig; ssize_t ret = 0; + bool from_stdio = false; + if (writer->tag && writer->prio >= 2) + from_stdio = true; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) + ktime_get_ts64(&now); +#else now = current_kernel_time(); +#endif header.pid = current->tgid; header.tid = current->pid; @@ -577,16 +730,24 @@ static int logger_open(struct inode *inode, struct file *file) mutex_unlock(&log->mutex); file->private_data = reader; - } else - file->private_data = log; + } else { + struct logger_writer *writer; + + writer = kzalloc(sizeof(struct logger_writer), GFP_KERNEL); + if (!writer) + return -ENOMEM; + + writer->log = log; + writer->owner = current->group_leader; + + file->private_data = writer; + } return 0; } /* * logger_release - the log's release file operation - * - * Note this is a total no-op in the write-only case. Keep it that way! */ static int logger_release(struct inode *ignored, struct file *file) { @@ -599,6 +760,20 @@ static int logger_release(struct inode *ignored, struct file *file) mutex_unlock(&log->mutex); kfree(reader); + } else { + struct logger_writer *writer = file->private_data; + struct logger_log *log = writer->log; + bool from_stdio = writer->tag && writer->prio >= 2; + + if (from_stdio && writer->b_off > 0){ + mutex_lock(&log->mutex); + flush_thread_data(file); + mutex_unlock(&log->mutex); + } + + kfree(writer->tag); + kfree(writer->buffer); + kfree(writer); } return 0; @@ -642,6 +817,7 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) static long logger_set_version(struct logger_reader *reader, void __user *arg) { int version; + if (copy_from_user(&version, arg, sizeof(int))) return -EFAULT; @@ -652,12 +828,57 @@ static long logger_set_version(struct logger_reader *reader, void __user *arg) return 0; } +static long logger_set_prio(struct logger_writer *writer, void __user *arg) +{ + int prio; + + prio = (int)(uintptr_t)arg; + + if ((prio < 2) || (prio > 7)) + return -EINVAL; + + writer->prio = prio; + return 0; +} + +static long logger_set_tag(struct logger_writer *writer, void __user *arg) +{ + struct logger_set_tag tag; + int len; + char *p, *q; + + if (copy_from_user(&tag, arg, sizeof(struct logger_set_tag))) + return -EFAULT; + + if (tag.len > LOGGER_ENTRY_MAX_PAYLOAD) + return -EINVAL; + + p = kzalloc(tag.len, GFP_KERNEL); + if (!p) + return -ENOMEM; + + if (copy_from_user(p, (void*)(uintptr_t)tag.ptr, tag.len)) { + kfree(p); + return -EFAULT; + } + p[tag.len - 1] = '\0'; + len = strlen(p); + + q = writer->tag; + writer->tag = p; + writer->tag_len = len; + kfree(q); + + return 0; +} + static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct logger_log *log = file_get_log(file); struct logger_reader *reader; + struct logger_writer *writer; long ret = -EINVAL; - void __user *argp = (void __user *) arg; + void __user *argp = (void __user *)arg; mutex_lock(&log->mutex); @@ -694,12 +915,8 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = 0; break; case LOGGER_FLUSH_LOG: - if (!(file->f_mode & FMODE_WRITE)) { - ret = -EBADF; - break; - } - if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) || - capable(CAP_SYSLOG))) { + if (!(in_egroup_p(file_inode(file)->i_gid) || + capable(CAP_SYSLOG))) { ret = -EPERM; break; } @@ -724,6 +941,24 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) reader = file->private_data; ret = logger_set_version(reader, argp); break; + case LOGGER_SET_PRIO: /* 44552 */ + if ((file->f_mode & FMODE_READ) || + !(file->f_mode & FMODE_WRITE)) { + ret = -EBADF; + break; + } + writer = file->private_data; + ret = logger_set_prio(writer, argp); + break; + case LOGGER_SET_TAG: /* 44551 */ + if ((file->f_mode & FMODE_READ) || + !(file->f_mode & FMODE_WRITE)) { + ret = -EBADF; + break; + } + writer = file->private_data; + ret = logger_set_tag(writer, argp); + break; } mutex_unlock(&log->mutex); @@ -787,15 +1022,18 @@ static int __init create_log(char *log_name, int size) ret = misc_register(&log->misc); if (unlikely(ret)) { pr_err("failed to register misc device for log '%s'!\n", - log->misc.name); - goto out_free_log; + log->misc.name); + goto out_free_misc_name; } pr_info("created %luK log '%s'\n", - (unsigned long) log->size >> 10, log->misc.name); + (unsigned long)log->size >> 10, log->misc.name); return 0; +out_free_misc_name: + kfree(log->misc.name); + out_free_log: kfree(log); @@ -808,15 +1046,19 @@ static int __init logger_init(void) { int ret; - ret = create_log(LOGGER_LOG_MAIN, 2048*1024); + ret = create_log(LOGGER_LOG_MAIN, 256*1024); + if (unlikely(ret)) + goto out; + + ret = create_log(LOGGER_LOG_EVENTS, 256*1024); if (unlikely(ret)) goto out; - ret = create_log(LOGGER_LOG_RADIO, 512*1024); + ret = create_log(LOGGER_LOG_RADIO, 256*1024); if (unlikely(ret)) goto out; - ret = create_log(LOGGER_LOG_SYSTEM, 1024*1024); + ret = create_log(LOGGER_LOG_SYSTEM, 256*1024); if (unlikely(ret)) goto out; @@ -838,8 +1080,7 @@ static void __exit logger_exit(void) } } - -device_initcall(logger_init); +module_init(logger_init); module_exit(logger_exit); MODULE_LICENSE("GPL"); diff --git a/kernel/logger.c b/kernel/logger.c index eb287e4..d329fdb 100644 --- a/kernel/logger.c +++ b/kernel/logger.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -476,7 +477,7 @@ static struct file *make_new_file(struct file *file) return ERR_PTR(-ENOMEM); } - p = file_path(file, pbuf, PATH_MAX); + p = d_path(&file->f_path, pbuf, PATH_MAX); if (!p) { kfree(pbuf); return ERR_PTR(-EFAULT); diff --git a/packaging/linux-tizen-modules-source.spec b/packaging/linux-tizen-modules-source.spec index b36910e..e0bdba3 100644 --- a/packaging/linux-tizen-modules-source.spec +++ b/packaging/linux-tizen-modules-source.spec @@ -21,6 +21,8 @@ mkdir -p %{buildroot}/usr/src/%{name}/kdbus cp kernel/*.[ch] kernel/Makefile COPYING %{buildroot}/usr/src/%{name} cp kernel/kdbus/*.[ch] kernel/kdbus/Makefile %{buildroot}/usr/src/%{name}/kdbus +ls %{buildroot}/usr/src/%{name} + %files %manifest %{name}.manifest %license COPYING -- 2.34.1