[WIP] TM1 logger
authorMateusz Majewski <m.majewski2@samsung.com>
Fri, 10 Dec 2021 10:25:18 +0000 (11:25 +0100)
committerMateusz Majewski <m.majewski2@samsung.com>
Fri, 10 Dec 2021 10:25:18 +0000 (11:25 +0100)
Change-Id: I322960e76092fe6570be499d17bec44e2b111680

kernel/logger-tm1.c
kernel/logger.c
packaging/linux-tizen-modules-source.spec

index f36a08769cd75e553b88a9aed2fd311c88e6516f..75044970645de034b63af033e41058450cc6e5c1 100644 (file)
 
 #define pr_fmt(fmt) "logger: " fmt
 
-#include <linux/sched.h>
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0))
+# include <linux/sched/signal.h>
+#else
+# include <linux/sched.h>
+#endif
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
 #include <linux/aio.h>
-#include "logger.h"
+#include <linux/uio.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
 
-#include <asm/ioctls.h>
+#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");
index eb287e4b07af722c94266bd7cc9d42875640e82d..d329fdbd05cedc86d2eccc2b460eb2c89385a155 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
+#include <linux/aio.h>
 #include <linux/uio.h>
 #include <linux/fdtable.h>
 #include <linux/file.h>
@@ -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);
index b36910ecbf2783eb6ec8b5e9b6aa901a7a11679e..e0bdba34bc413386330dc6ac978c3845018c7402 100644 (file)
@@ -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