diff options
author | Karol Lewandowski <k.lewandowsk@samsung.com> | 2021-11-26 14:24:56 +0100 |
---|---|---|
committer | Karol Lewandowski <k.lewandowsk@samsung.com> | 2021-11-29 14:21:38 +0100 |
commit | c3d0fecd5b217408ad26af6dd46ad18510d2a88f (patch) | |
tree | aea717943a4264282f82c5d83d2e050cb3fa5d07 | |
parent | 286b0bc9c9b44a42f9cfcf1a5c1ffa17a8e8314a (diff) | |
download | linux-tizen-modules-submit/tizen/20211201.082354.tar.gz linux-tizen-modules-submit/tizen/20211201.082354.tar.bz2 linux-tizen-modules-submit/tizen/20211201.082354.zip |
Build package using external linux-tizen-modules-source packagesubmit/tizen/20211201.082354submit/tizen/20211130.104346accepted/tizen/unified/20211202.120725
This package contains only public tizen configuration and deps.
Change-Id: Ib4de81e507cce2773589d8e25b3e120be5f57a48
-rw-r--r-- | kernel/Makefile | 24 | ||||
-rw-r--r-- | kernel/logger.c | 1131 | ||||
-rw-r--r-- | kernel/logger.h | 105 | ||||
-rw-r--r-- | kernel/proc-tsm.c | 270 | ||||
-rw-r--r-- | packaging/linux-tizen-modules-source.spec | 29 | ||||
-rw-r--r-- | packaging/linux-tizen-modules.spec | 4 |
6 files changed, 3 insertions, 1560 deletions
diff --git a/kernel/Makefile b/kernel/Makefile deleted file mode 100644 index 51f5bb4..0000000 --- a/kernel/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -PWD := $(shell pwd) -LD = ${CROSS_COMPILE}ld - -# See commit 0b999ae3614d0 ("Merge tag 'compiler-attributes-for-linus-v5.0-rc7'"[..]) for rationale -CFLAGS_logger.o += -Wno-error=missing-attributes -CFLAGS_proc-tsm.o += -Wno-error=missing-attributes - -# Build is disabled by default so that when new module is added to this repository (and -source package), -# it won't get automatically build in packages using it (that would break these automatically as file list -# would no longer match). -BUILD_logger ?= n -BUILD_proc_tsm ?= n - -obj-$(BUILD_logger) += logger.o -obj-$(BUILD_proc_tsm) += proc-tsm.o - -all: - make -C $(KERNELDIR) M=$(PWD) modules - -modules_install: - make -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_STRIP=$(INSTALL_MOD_STRIP) INSTALL_MOD_PATH=$(PWD)/../$(INSTALL_MOD_PATH) modules_install - -clean: - make -C $(KERNELDIR) M=$(PWD) clean diff --git a/kernel/logger.c b/kernel/logger.c deleted file mode 100644 index eb287e4..0000000 --- a/kernel/logger.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * drivers/misc/logger.c - * - * A Logging Subsystem - * - * Copyright (C) 2007-2008 Google, Inc. - * - * Robert Love <rlove@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#define pr_fmt(fmt) "logger: " fmt - -#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/uaccess.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/vmalloc.h> -#include <linux/uio.h> -#include <linux/fdtable.h> -#include <linux/file.h> - -#include "logger.h" - -/** - * struct logger_log - represents a specific log, such as 'main' or 'radio' - * @buffer: The actual ring buffer - * @misc: The "misc" device representing the log - * @wq: The wait queue for @readers - * @readers: This log's readers - * @mutex: The mutex that protects the @buffer - * @w_off: The current write head offset - * @head: The head, or location that readers start reading at. - * @size: The size of the log - * @logs: The list of log channels - * - * This structure lives from module insertion until module removal, so it does - * not need additional reference counting. The structure is protected by the - * mutex 'mutex'. - */ -struct logger_log { - unsigned char *buffer; - struct miscdevice misc; - wait_queue_head_t wq; - struct list_head readers; - struct mutex mutex; - size_t w_off; - size_t head; - size_t size; - struct list_head logs; -}; - -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 - * @log: The associated log - * @list: The associated entry in @logger_log's list - * @r_off: The current read head offset. - * @r_all: Reader can read all entries - * @r_ver: Reader ABI version - * - * This object lives from open to release, so we don't need additional - * reference counting. The structure is protected by log->mutex. - */ -struct logger_reader { - struct logger_log *log; - struct list_head list; - size_t r_off; - bool r_all; - int r_ver; -}; - -/* logger_offset - returns index 'n' into the log via (optimized) modulus */ -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 - * - * This isn't aesthetic. We have several goals: - * - * 1) Need to quickly obtain the associated log during an I/O operation - * 2) Readers need to maintain state (logger_reader) - * 3) Writers need to be very fast (open() should be a near no-op) - * - * In the reader case, we can trivially go file->logger_reader->logger_log. - * For a writer, we don't want to maintain a logger_reader, so we just go - * file->logger_log. Thus what file->private_data points at depends on whether - * or not the file was opened for reading. This function hides that dirtiness. - */ -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; - } - - return writer->log; -} - -/* - * get_entry_header - returns a pointer to the logger_entry header within - * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must - * be provided. Typically the return value will be a pointer within - * 'logger->buf'. However, a pointer to 'scratch' may be returned if - * 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 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); - return scratch; - } - - return (struct logger_entry *) (log->buffer + off); -} - -/* - * get_entry_msg_len - Grabs the length of the message of the entry - * starting from from 'off'. - * - * An entry length is 2 bytes (16 bits) in host endian order. - * In the log, the length does not include the size of the log entry structure. - * This function returns the size including the log entry structure. - * - * Caller needs to hold log->mutex. - */ -static __u32 get_entry_msg_len(struct logger_log *log, size_t off) -{ - struct logger_entry scratch; - struct logger_entry *entry; - - entry = get_entry_header(log, off, &scratch); - return entry->len; -} - -static size_t get_user_hdr_len(int ver) -{ - if (ver < 2) - return sizeof(struct user_logger_entry_compat); - return sizeof(struct logger_entry); -} - -static ssize_t copy_header_to_user(int ver, struct logger_entry *entry, - char __user *buf) -{ - void *hdr; - size_t hdr_len; - struct user_logger_entry_compat v1; - - if (ver < 2) { - v1.len = entry->len; - v1.__pad = 0; - v1.pid = entry->pid; - v1.tid = entry->tid; - v1.sec = entry->sec; - v1.nsec = entry->nsec; - hdr = &v1; - hdr_len = sizeof(struct user_logger_entry_compat); - } else { - hdr = entry; - hdr_len = sizeof(struct logger_entry); - } - - return copy_to_user(buf, hdr, hdr_len); -} - -/* - * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the - * user-space buffer 'buf'. Returns 'count' on success. - * - * Caller must hold log->mutex. - */ -static ssize_t do_read_log_to_user(struct logger_log *log, - struct logger_reader *reader, - char __user *buf, - size_t count) -{ - struct logger_entry scratch; - struct logger_entry *entry; - size_t len; - size_t msg_start; - - /* - * First, copy the header to userspace, using the version of - * the header requested - */ - entry = get_entry_header(log, reader->r_off, &scratch); - if (copy_header_to_user(reader->r_ver, entry, buf)) - return -EFAULT; - - 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)); - - /* - * We read from the msg in two disjoint operations. First, we read from - * the current msg head offset up to 'count' bytes or to the end of - * the log, whichever comes first. - */ - len = min(count, log->size - msg_start); - if (copy_to_user(buf, log->buffer + msg_start, len)) - return -EFAULT; - - /* - * Second, we read any remaining bytes, starting back at the head of - * the log. - */ - if (count != len) - if (copy_to_user(buf + len, log->buffer, count - len)) - return -EFAULT; - - reader->r_off = logger_offset(log, reader->r_off + - sizeof(struct logger_entry) + count); - - return count + get_user_hdr_len(reader->r_ver); -} - -/* - * get_next_entry_by_uid - Starting at 'off', returns an offset into - * '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) -{ - while (off != log->w_off) { - struct logger_entry *entry; - struct logger_entry scratch; - size_t next_len; - - entry = get_entry_header(log, off, &scratch); - - if (uid_eq(entry->euid, euid)) - return off; - - next_len = sizeof(struct logger_entry) + entry->len; - off = logger_offset(log, off + next_len); - } - - return off; -} - -/* - * logger_read - our log's read() method - * - * Behavior: - * - * - O_NONBLOCK works - * - If there are no log entries to read, blocks until log is written to - * - Atomically reads exactly one log entry - * - * Will set errno to EINVAL if read - * buffer is insufficient to hold next entry. - */ -static ssize_t logger_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - struct logger_reader *reader = file->private_data; - struct logger_log *log = reader->log; - ssize_t ret; - DEFINE_WAIT(wait); - -start: - while (1) { - mutex_lock(&log->mutex); - - prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); - - ret = (log->w_off == reader->r_off); - mutex_unlock(&log->mutex); - if (!ret) - break; - - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -EINTR; - break; - } - - schedule(); - } - - finish_wait(&log->wq, &wait); - if (ret) - return ret; - - mutex_lock(&log->mutex); - - if (!reader->r_all) - reader->r_off = get_next_entry_by_uid(log, - reader->r_off, current_euid()); - - /* is there still something to read or did we race? */ - if (unlikely(log->w_off == reader->r_off)) { - mutex_unlock(&log->mutex); - goto start; - } - - /* get the size of the next entry */ - ret = get_user_hdr_len(reader->r_ver) + - get_entry_msg_len(log, reader->r_off); - if (count < ret) { - ret = -EINVAL; - goto out; - } - - /* get exactly one entry from the log */ - ret = do_read_log_to_user(log, reader, buf, ret); - -out: - mutex_unlock(&log->mutex); - - return ret; -} - -/* - * get_next_entry - return the offset of the first valid entry at least 'len' - * bytes after 'off'. - * - * Caller must hold log->mutex. - */ -static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) -{ - size_t count = 0; - - do { - size_t nr = sizeof(struct logger_entry) + - get_entry_msg_len(log, off); - off = logger_offset(log, off + nr); - count += nr; - } while (count < len); - - return off; -} - -/* - * is_between - is a < c < b, accounting for wrapping of a, b, and c - * positions in the buffer - * - * That is, if a<b, check for c between a and b - * and if a>b, check for c outside (not between) a and b - * - * |------- a xxxxxxxx b --------| - * c^ - * - * |xxxxx b --------- a xxxxxxxxx| - * c^ - * or c^ - */ -static inline int is_between(size_t a, size_t b, size_t c) -{ - if (a < b) { - /* is c between a and b? */ - if (a < c && c <= b) - return 1; - } else { - /* is c outside of b through a? */ - if (c <= b || a < c) - return 1; - } - - return 0; -} - -/* - * fix_up_readers - walk the list of all readers and "fix up" any who were - * lapped by the writer; also do the same for the default "start head". - * We do this by "pulling forward" the readers and start head to the first - * entry after the new write head. - * - * The caller needs to hold log->mutex. - */ -static void fix_up_readers(struct logger_log *log, size_t len) -{ - size_t old = log->w_off; - size_t new = logger_offset(log, old + len); - struct logger_reader *reader; - - if (is_between(old, new, log->head)) - log->head = get_next_entry(log, log->head, len); - - list_for_each_entry(reader, &log->readers, list) - if (is_between(old, new, reader->r_off)) - reader->r_off = get_next_entry(log, reader->r_off, len); -} - -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 = file_path(file, 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'; -} - -/* - * 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_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - 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 len, count, w_off; - bool from_stdio = false; - - if (writer->tag && writer->prio >= 2) - from_stdio = true; - - count = min_t(size_t, iov_iter_count(from), LOGGER_ENTRY_MAX_PAYLOAD); - -#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; - header.sec = now.tv_sec; - header.nsec = now.tv_nsec; - header.euid = current_euid(); - header.len = count; - header.hdr_size = sizeof(struct logger_entry); - - /* null writes succeed, return zero */ - if (unlikely(!header.len)) - return 0; - - mutex_lock(&log->mutex); - - /* Prepend messages from STDOUT and STDERR with a tag and prio */ - if (from_stdio) { - char *p; - size_t chunk_len = 0, c = 0; - /* -2 : priority byte and tag terminating '\0' */ - size_t max_payload = LOGGER_ENTRY_MAX_PAYLOAD - writer->tag_len - 2; - - if (writer->owner != current->group_leader) { - struct file *nfile; - - nfile = make_new_file(file); - if (IS_ERR(nfile)) { - mutex_unlock(&log->mutex); - return PTR_ERR(nfile); - } - - file = nfile; - writer = file->private_data; - } - - /* Allocate STDIO line buffer */ - if (!writer->buffer) { - writer->buffer = kzalloc(LOGGER_ENTRY_MAX_PAYLOAD, GFP_KERNEL); - writer->b_off = 0; - - if (!writer->buffer) { - mutex_unlock(&log->mutex); - return -ENOMEM; - } - } - - /* flush message from a different thread */ - if (writer->b_owner != current && writer->b_off) - flush_thread_data(file); - - count = 0; - /* -1 : leave space for message terminating '\0' */ - c = min_t(size_t, iov_iter_count(from), - max_payload - writer->b_off - 1); - - do { - size_t i; - if (copy_from_iter(writer->buffer + writer->b_off, c, from) != c) { - mutex_unlock(&log->mutex); - return -EFAULT; - } - count += c; - p = NULL; - for (i = 0; i < c; ++i) { - char *t = &writer->buffer[writer->b_off + i]; - if (*t == '\0') - *t = '\n'; - if (*t == '\n') - p = t; - } - if (p) { - *p++ = '\0'; - chunk_len = p - writer->buffer; - } else { - writer->buffer[writer->b_off + c++] = '\0'; - p = &writer->buffer[writer->b_off + c]; - chunk_len = p - writer->buffer; - - BUG_ON(chunk_len > max_payload); - if (chunk_len < max_payload ) { - writer->b_off = writer->b_off + c - 1; - continue; - } - - } - - header.len = chunk_len + writer->tag_len + 2; - fix_up_readers(log, sizeof(struct logger_entry) + header.len); - - write_log_data(log, &header, writer, chunk_len); - - /* move the remaining part of the message */ - memmove(writer->buffer, p, writer->b_off + c - chunk_len); - - /* new b_off points where the rimainder of the string ends */ - writer->b_off = writer->b_off + c - chunk_len; - writer->buffer[writer->b_off] = '\0'; - - } while ((c = min_t(size_t, iov_iter_count(from), max_payload - 1))); - - /* save for remaining unfinished line */ - writer->b_header = header; - writer->b_owner = current; - } else { - - /* - * Fix up any readers, pulling them forward to the first readable - * entry after (what will be) the new write offset. We do this now - * because if we partially fail, we can end up with clobbered log - * entries that encroach on readable buffer. - */ - fix_up_readers(log, sizeof(struct logger_entry) + header.len); - - 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); - - /* 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)); - - len = min(count, log->size - w_off); - - if (copy_from_iter(log->buffer + w_off, len, from) != len) { - /* - * 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. - */ - mutex_unlock(&log->mutex); - return -EFAULT; - } - - if (copy_from_iter(log->buffer, count - len, from) != count - len) { - mutex_unlock(&log->mutex); - return -EFAULT; - } - - log->w_off = logger_offset(log, w_off + count); - } - - mutex_unlock(&log->mutex); - - /* wake up any blocked readers */ - wake_up_interruptible(&log->wq); - - return count; -} - -static struct logger_log *get_log_from_minor(int minor) -{ - struct logger_log *log; - - list_for_each_entry(log, &log_list, logs) - if (log->misc.minor == minor) - return log; - return NULL; -} - -/* - * logger_open - the log's open() file operation - * - * Note how near a no-op this is in the write-only case. Keep it that way! - */ -static int logger_open(struct inode *inode, struct file *file) -{ - struct logger_log *log; - int ret; - - ret = nonseekable_open(inode, file); - if (ret) - return ret; - - log = get_log_from_minor(MINOR(inode->i_rdev)); - if (!log) - return -ENODEV; - - if (file->f_mode & FMODE_READ) { - struct logger_reader *reader; - - reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL); - if (!reader) - return -ENOMEM; - - reader->log = log; - reader->r_ver = 1; - reader->r_all = in_egroup_p(inode->i_gid) || - capable(CAP_SYSLOG); - - INIT_LIST_HEAD(&reader->list); - - mutex_lock(&log->mutex); - reader->r_off = log->head; - list_add_tail(&reader->list, &log->readers); - mutex_unlock(&log->mutex); - - file->private_data = reader; - } 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 - */ -static int logger_release(struct inode *ignored, struct file *file) -{ - if (file->f_mode & FMODE_READ) { - struct logger_reader *reader = file->private_data; - struct logger_log *log = reader->log; - - mutex_lock(&log->mutex); - list_del(&reader->list); - 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; -} - -/* - * logger_poll - the log's poll file operation, for poll/select/epoll - * - * Note we always return POLLOUT, because you can always write() to the log. - * Note also that, strictly speaking, a return value of POLLIN does not - * guarantee that the log is readable without blocking, as there is a small - * chance that the writer can lap the reader in the interim between poll() - * returning and the read() request. - */ -static unsigned int logger_poll(struct file *file, poll_table *wait) -{ - struct logger_reader *reader; - struct logger_log *log; - unsigned int ret = POLLOUT | POLLWRNORM; - - if (!(file->f_mode & FMODE_READ)) - return ret; - - reader = file->private_data; - log = reader->log; - - poll_wait(file, &log->wq, wait); - - mutex_lock(&log->mutex); - if (!reader->r_all) - reader->r_off = get_next_entry_by_uid(log, - reader->r_off, current_euid()); - - if (log->w_off != reader->r_off) - ret |= POLLIN | POLLRDNORM; - mutex_unlock(&log->mutex); - - return ret; -} - -static long logger_set_version(struct logger_reader *reader, void __user *arg) -{ - int version; - - if (copy_from_user(&version, arg, sizeof(int))) - return -EFAULT; - - if ((version < 1) || (version > 2)) - return -EINVAL; - - reader->r_ver = version; - 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; - - mutex_lock(&log->mutex); - - switch (cmd) { - case LOGGER_GET_LOG_BUF_SIZE: - ret = log->size; - break; - case LOGGER_GET_LOG_LEN: - if (!(file->f_mode & FMODE_READ)) { - ret = -EBADF; - break; - } - reader = file->private_data; - if (log->w_off >= reader->r_off) - ret = log->w_off - reader->r_off; - else - ret = (log->size - reader->r_off) + log->w_off; - break; - case LOGGER_GET_NEXT_ENTRY_LEN: - if (!(file->f_mode & FMODE_READ)) { - ret = -EBADF; - break; - } - reader = file->private_data; - - if (!reader->r_all) - reader->r_off = get_next_entry_by_uid(log, - reader->r_off, current_euid()); - - if (log->w_off != reader->r_off) - ret = get_user_hdr_len(reader->r_ver) + - get_entry_msg_len(log, reader->r_off); - else - ret = 0; - break; - case LOGGER_FLUSH_LOG: - if (!(in_egroup_p(file_inode(file)->i_gid) || - capable(CAP_SYSLOG))) { - ret = -EPERM; - break; - } - list_for_each_entry(reader, &log->readers, list) - reader->r_off = log->w_off; - log->head = log->w_off; - ret = 0; - break; - case LOGGER_GET_VERSION: - if (!(file->f_mode & FMODE_READ)) { - ret = -EBADF; - break; - } - reader = file->private_data; - ret = reader->r_ver; - break; - case LOGGER_SET_VERSION: - if (!(file->f_mode & FMODE_READ)) { - ret = -EBADF; - break; - } - 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); - - return ret; -} - -static const struct file_operations logger_fops = { - .owner = THIS_MODULE, - .read = logger_read, - .write_iter = logger_write_iter, - .poll = logger_poll, - .unlocked_ioctl = logger_ioctl, - .compat_ioctl = logger_ioctl, - .open = logger_open, - .release = logger_release, -}; - -/* - * Log size must must be a power of two, and greater than - * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)). - */ -static int __init create_log(char *log_name, int size) -{ - int ret = 0; - struct logger_log *log; - unsigned char *buffer; - - buffer = vmalloc(size); - if (buffer == NULL) - return -ENOMEM; - - log = kzalloc(sizeof(struct logger_log), GFP_KERNEL); - if (log == NULL) { - ret = -ENOMEM; - goto out_free_buffer; - } - log->buffer = buffer; - - log->misc.minor = MISC_DYNAMIC_MINOR; - log->misc.name = kstrdup(log_name, GFP_KERNEL); - if (log->misc.name == NULL) { - ret = -ENOMEM; - goto out_free_log; - } - - log->misc.fops = &logger_fops; - log->misc.parent = NULL; - - init_waitqueue_head(&log->wq); - INIT_LIST_HEAD(&log->readers); - mutex_init(&log->mutex); - log->w_off = 0; - log->head = 0; - log->size = size; - - INIT_LIST_HEAD(&log->logs); - list_add_tail(&log->logs, &log_list); - - /* finally, initialize the misc device for this log */ - 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_misc_name; - } - - pr_info("created %luK log '%s'\n", - (unsigned long)log->size >> 10, log->misc.name); - - return 0; - -out_free_misc_name: - kfree(log->misc.name); - -out_free_log: - kfree(log); - -out_free_buffer: - vfree(buffer); - return ret; -} - -static int __init logger_init(void) -{ - int ret; - - 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, 256*1024); - if (unlikely(ret)) - goto out; - - ret = create_log(LOGGER_LOG_SYSTEM, 256*1024); - if (unlikely(ret)) - goto out; - -out: - return ret; -} - -static void __exit logger_exit(void) -{ - struct logger_log *current_log, *next_log; - - list_for_each_entry_safe(current_log, next_log, &log_list, logs) { - /* we have to delete all the entry inside log_list */ - misc_deregister(¤t_log->misc); - vfree(current_log->buffer); - kfree(current_log->misc.name); - list_del(¤t_log->logs); - kfree(current_log); - } -} - -module_init(logger_init); -module_exit(logger_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Robert Love, <rlove@google.com>"); -MODULE_DESCRIPTION("Android Logger"); diff --git a/kernel/logger.h b/kernel/logger.h deleted file mode 100644 index 8054a3e..0000000 --- a/kernel/logger.h +++ /dev/null @@ -1,105 +0,0 @@ -/* include/linux/logger.h - * - * Copyright (C) 2007-2008 Google, Inc. - * Author: Robert Love <rlove@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_LOGGER_H -#define _LINUX_LOGGER_H - -#include <linux/types.h> -#include <linux/ioctl.h> - -/** - * struct user_logger_entry_compat - defines a single entry that is given to a logger - * @len: The length of the payload - * @__pad: Two bytes of padding that appear to be required - * @pid: The generating process' process ID - * @tid: The generating process' thread ID - * @sec: The number of seconds that have elapsed since the Epoch - * @nsec: The number of nanoseconds that have elapsed since @sec - * @msg: The message that is to be logged - * - * The userspace structure for version 1 of the logger_entry ABI. - * This structure is returned to userspace unless the caller requests - * an upgrade to a newer ABI version. - */ -struct user_logger_entry_compat { - __u16 len; - __u16 __pad; - __s32 pid; - __s32 tid; - __s32 sec; - __s32 nsec; - char msg[0]; -}; - -/** - * struct logger_entry - defines a single entry that is given to a logger - * @len: The length of the payload - * @hdr_size: sizeof(struct logger_entry_v2) - * @pid: The generating process' process ID - * @tid: The generating process' thread ID - * @sec: The number of seconds that have elapsed since the Epoch - * @nsec: The number of nanoseconds that have elapsed since @sec - * @euid: Effective UID of logger - * @msg: The message that is to be logged - * - * The structure for version 2 of the logger_entry ABI. - * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION) - * is called with version >= 2 - */ -struct logger_entry { - __u16 len; - __u16 hdr_size; - __s32 pid; - __s32 tid; - __s32 sec; - __s32 nsec; -#ifndef __KERNEL__ - __s32 euid; -#else - kuid_t euid; -#endif - char msg[0]; -}; - -/** - * struct logger_set_tag - * @len: Length of a NULL-terminated tag including '\0' - * @ptr: Pointer to a user buffer containing the tag - */ -struct logger_set_tag { - __u64 len; - __u64 ptr; -}; - -#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ -#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ -#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ -#define LOGGER_LOG_MAIN "log_main" /* everything else */ - -#define LOGGER_ENTRY_MAX_PAYLOAD 4076 - -#define __LOGGERIO 0xAE - -#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ -#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ -#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ -#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ -#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */ -#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */ -#define LOGGER_SET_TAG _IO(__LOGGERIO, 7) /* stdio tag */ -#define LOGGER_SET_PRIO _IO(__LOGGERIO, 8) /* stdio priority */ - -#endif /* _LINUX_LOGGER_H */ diff --git a/kernel/proc-tsm.c b/kernel/proc-tsm.c deleted file mode 100644 index 4527160..0000000 --- a/kernel/proc-tsm.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * This file is part of stability-monitor-kmod-rpi3 - * - * Copyright © 2019 Samsung Electronics - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see http://www.gnu.org/licenses/ - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/version.h> - -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/sched.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -#include <linux/sched/signal.h> -#include <linux/sched/cputime.h> -#endif -#include <linux/mm.h> -#include <linux/pid_namespace.h> -#include <asm/uaccess.h> -#include <linux/time.h> -#include <linux/posix-timers.h> -#include <linux/kernel_stat.h> -#include <linux/fdtable.h> -#include <linux/math64.h> -#include <linux/task_io_accounting_ops.h> -#include <linux/security.h> - -#define DEBUG 0 -#define PAGE_TO_KB(x) ((x) << (PAGE_SHIFT - 10)) - -static struct proc_dir_entry* proc_file; -static char *blacklist[10] = {0, }; -static int blacklist_c = 0; - -module_param_array(blacklist, charp, &blacklist_c, 0000); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) -/* ktime_get_boot_ns() is renamed to ktime_get_boottime_ns() from v5.3 */ -static inline u64 ktime_get_boot_ns(void) { - return ktime_get_boottime_ns(); -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) */ - -static u64 time_now(void) -{ - return div64_ul(ktime_get_boot_ns(), NSEC_PER_USEC); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -static inline u64 cputime_to_usecs(const u64 cputime) -{ - // return cputime >> 12; - return div64_ul(cputime, NSEC_PER_USEC); -} -#endif - -static unsigned int count_open_files(struct files_struct *files) -{ - unsigned int open_files = 0; - int i; - struct fdtable *fdt; - - if (!files) - return 0; - - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - - /* Find the last non zero cell in open fds array */ - for (i = fdt->max_fds / BITS_PER_LONG - 1; i >= 0; i--) { - if (fdt->open_fds[i]) - break; - } - - /* Count set bits */ - for (i = (i + 1) * BITS_PER_LONG - 1; i >= 0; i--) { - if(test_bit(i, fdt->open_fds)) - open_files++; - } - - spin_unlock(&files->file_lock); - return open_files; -} - -static int stability_monitor_show(struct seq_file *m, void *v) -{ - struct sysinfo info; - struct task_struct *task, *t; - struct pid *pid = NULL; - pid_t ppid = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) - u64 uptime, utime, stime, ut, st; -#else - cputime_t uptime, utime, stime, ut, st; -#endif - unsigned long long vm_rss, total_ram; - struct task_io_accounting task_ioac; - unsigned int open_fds; - u32 secid; - char *label; - u32 label_len; - int blacklisted; - int i; - - rcu_read_lock(); - - /* Uptime in us */ - uptime = time_now(); - - /* Memory info */ - si_meminfo(&info); - total_ram = PAGE_TO_KB(info.totalram); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) - seq_put_decimal_ull(m, "", uptime); - seq_put_decimal_ull(m, " ", total_ram); -#else - seq_put_decimal_ull(m, 0, uptime); - seq_put_decimal_ull(m, ' ', total_ram); -#endif - seq_printf(m, "\n"); - - for_each_process(task) { - ppid = task->real_parent->pid; - pid = task_pgrp(task); - if (!pid) - continue; - - task_lock(task); - - if (!task->mm) { - task_unlock(task); - continue; - } - - if (task->flags & (PF_DUMPCORE|PF_SIGNALED|PF_EXITING)) { - task_unlock(task); - continue; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) - security_cred_getsecid(((struct cred *)task->real_cred), &secid); -#else - security_task_getsecid(task, &secid); -#endif - if (!security_secid_to_secctx(secid, &label, &label_len)) { - blacklisted = 0; - for (i = 0; i < blacklist_c; i++) { - if (strcmp(label, blacklist[i]) == 0) { - blacklisted = 1; - break; - } - } - if (blacklisted) { - task_unlock(task); - continue; - } - } - - /* Memory */ - vm_rss = get_mm_rss(task->mm); - - /* Open FDs */ - open_fds = count_open_files(task->files); - - /* CPU time + IO accounting */ - task_cputime_adjusted(task, &utime, &stime); - task_ioac = task->ioac; - t = task; - while_each_thread(task, t) { - task_cputime_adjusted(t, &ut, &st); - utime += ut; - stime += st; - task_io_accounting_add(&task_ioac, &t->ioac); - } - - task_unlock(task); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) - seq_put_decimal_ll(m, "", task->pid); - seq_put_decimal_ll(m, " ", ppid); - seq_put_decimal_ull(m, " ", cputime_to_usecs(utime + stime)); - seq_put_decimal_ull(m, " ", PAGE_TO_KB(vm_rss)); - seq_put_decimal_ll(m, " ", open_fds); -#ifdef CONFIG_TASK_IO_ACCOUNTING - seq_put_decimal_ull(m, " ", task_ioac.read_bytes + task_ioac.write_bytes); -#else - seq_put_decimal_ull(m, " ", 0); -#endif -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) */ - seq_put_decimal_ll(m, 0, task->pid); - seq_put_decimal_ll(m, ' ', ppid); - seq_put_decimal_ull(m, ' ', cputime_to_usecs(utime + stime)); - seq_put_decimal_ull(m, ' ', PAGE_TO_KB(vm_rss)); - seq_put_decimal_ll(m, ' ', open_fds); -#ifdef CONFIG_TASK_IO_ACCOUNTING - seq_put_decimal_ull(m, ' ', task_ioac.read_bytes + task_ioac.write_bytes); -#else - seq_put_decimal_ull(m, ' ', 0); -#endif -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) */ - seq_printf(m, "\n"); - } - - rcu_read_unlock(); - -#if DEBUG - printk(KERN_DEBUG "stability_monitor_show() took %llu us\n", time_now() - uptime); -#endif - - return 0; -} - -static int stability_monitor_open(struct inode *inode, struct file *file) -{ - return single_open_size(file, stability_monitor_show, NULL, 8192); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) -static const struct proc_ops stability_monitor_fops = { - .proc_open = stability_monitor_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_release = single_release, -}; -#else -static const struct file_operations stability_monitor_fops = { - .owner = THIS_MODULE, - .open = stability_monitor_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -static int __init stability_monitor_init(void) -{ - proc_file = proc_create("tsm", 0, NULL, &stability_monitor_fops); - if (!proc_file) - return -ENOMEM; - - return 0; -} - -static void __exit stability_monitor_exit(void) -{ - remove_proc_entry("tsm", NULL); -} - -module_init(stability_monitor_init); -module_exit(stability_monitor_exit); - -MODULE_LICENSE("GPL"); diff --git a/packaging/linux-tizen-modules-source.spec b/packaging/linux-tizen-modules-source.spec deleted file mode 100644 index aa45713..0000000 --- a/packaging/linux-tizen-modules-source.spec +++ /dev/null @@ -1,29 +0,0 @@ -Name: linux-tizen-modules-source -Version: 7.0.1 -Release: 0 -License: GPL-2.0+ -Source0: %{name}-%{version}.tar.xz -Source1: linux-tizen-modules.manifest -Summary: Source code for Tizen-specific kernel modules -Group: System/Kernel -%description -This package contains source code for Tizen-specific kernel modules: -- logger - provides in-kernel ring buffers for purpose of logging (via dlog) -- proc-tsm - provides system-wide process infromation for monitoring purpose (via stability monitor) - -%prep -%setup -q -cp %{SOURCE1} . - -%install -mkdir -p %{buildroot}/usr/src/%{name} - -cp kernel/*.[ch] kernel/Makefile COPYING %{buildroot}/usr/src/%{name} - -%files -%manifest linux-tizen-modules.manifest -%license COPYING -/usr/src/%{name}/COPYING -/usr/src/%{name}/*.c -/usr/src/%{name}/*.h -/usr/src/%{name}/Makefile diff --git a/packaging/linux-tizen-modules.spec b/packaging/linux-tizen-modules.spec index 13a41cc..1855be6 100644 --- a/packaging/linux-tizen-modules.spec +++ b/packaging/linux-tizen-modules.spec @@ -7,7 +7,7 @@ %endif Name: linux-tizen-modules -Version: 7.0.1 +Version: 7.0.2 Release: 0 License: GPL-2.0+ Source0: %{name}-%{version}.tar.xz @@ -16,6 +16,7 @@ Summary: Tizen-specific kernel modules Group: System/Kernel ExclusiveArch: armv7l aarch64 BuildRequires: kmod +BuildRequires: linux-tizen-modules-source BuildRequires: %{buildarch}-rpi3-linux-kernel-devel BuildRequires: %{buildarch}-rpi4-linux-kernel-devel %ifarch aarch64 @@ -56,6 +57,7 @@ Provides: stability-monitor-kernel-module %prep %setup -q cp %{SOURCE1} ./%{name}.manifest +cp -a /usr/src/linux-tizen-modules-source ./kernel %build export BUILD_logger=m |