From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754073AbcBXLxo (ORCPT ); Wed, 24 Feb 2016 06:53:44 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:30380 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753436AbcBXLxg (ORCPT ); Wed, 24 Feb 2016 06:53:36 -0500 X-AuditID: cbfec7f5-f79b16d000005389-9d-56cd99baa3f1 From: Kazimierz Krosman To: akpm@linux-foundation.org, peter@hurleysoftware.com, tj@kernel.org, vvs@virtuozzo.com, corbet@lwn.net, arnd@arndb.de, pmladek@suse.cz, gregkh@linuxfoundation.org, daniel@zonque.org, kay.sievers@vrfy.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-api@vger.kernel.org Cc: k.lewandowsk@samsung.com, k.krosman@samsung.com, m.niesluchow@samsung.com, richard.weinberger@gmail.com, b.zolnierkie@samsung.com, luto@amacapital.net, knhoon.baik@samsung.com Subject: [PATCH v6 5/8] kmsg: add function for adding and deleting additional buffers Date: Wed, 24 Feb 2016 12:53:18 +0100 Message-id: <1456314801-32738-6-git-send-email-k.krosman@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1456314801-32738-1-git-send-email-k.krosman@samsung.com> References: <1456314801-32738-1-git-send-email-k.krosman@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpgkeLIzCtJLcpLzFFi42I5/e/4Zd1dM8+GGfS1aFjMWb+GzeLvpGPs FhtnrGe1eHKgndGi6e8rFovmxevZLC48D7Bo/DSX2eLyhnNsFiteHGa02Py9g81iYdsSFovL u+awWaxe28BqcejsDxaLY5f+MVos/L+ZyeLDxA1sFr+WH2W0OLhsFpuDiMf9N39ZPH7/msTo sXPWXXaPFX/Ws3lsWtXJ5nFixm8Wj/1z17B7LO6bzOrRt2UVo8eZBUfYPT5vkvN4vf8Qo8fH 9Z4e23cvZwngi+KySUnNySxLLdK3S+DK2HPpGFPBWbOKw0vvsDcwXtPpYuTgkBAwkWg7n9TF yAlkiklcuLeerYuRi0NIYCmjxKsF21ggnEYmibUNx1lBqtgE9CXOn5vCBJIQEVjFJPGwdQo7 iMMssJ1R4tSBh2wgVcIC4RIb57axgNgsAqoSSzecBLN5BVwlmr98ZoPYJydx8thkVpAzOAXc JE6/LwMJCwGVfN9xmGUCI+8CRoZVjKKppckFxUnpuUZ6xYm5xaV56XrJ+bmbGCHx8nUH49Jj VocYBTgYlXh4H2w4EybEmlhWXJl7iFGCg1lJhDdu2tkwId6UxMqq1KL8+KLSnNTiQ4zSHCxK 4rwzd70PERJITyxJzU5NLUgtgskycXBKNTD2OypMZvyTs3CDxb6AnVxcp29Mz/N+E7vl3odd ISWdJyZlm1vbC3+a3BPzMFO/6d5qhrJ8mXXaK9LyJitJhS4LUPx0Qn7SJStOjq2/lj97uNOr 43A6S4nx19lvP6aEy5/7GCEWmmh2rrEqUrXOyMnO2+Z708WJrfeNHpxdkDoxfyt7z4RfVqVK LMUZiYZazEXFiQAFUl56kwIAAA== Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Marcin Niesluchowski Additional kmsg buffers should be created and deleted dynamically. Adding two functions * kmsg_sys_buffer_add() creates additional kmsg buffer returning minor * kmsg_sys_buffer_del() deletes one based on provided minor Signed-off-by: Marcin Niesluchowski Signed-off-by: Paul Osmialowski [Rebased kmsg patch v5 on Linux 4.5-rc5] Signed-off-by: Kazimierz Krosman --- include/linux/printk.h | 9 +++++ kernel/printk/kmsg.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++-- kernel/printk/printk.c | 12 ++++++ kernel/printk/printk.h | 4 ++ 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index 342e9d0..c146ee4 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -431,6 +431,8 @@ extern const struct file_operations kmsg_fops; extern struct device *init_kmsg(int minor, umode_t mode); extern int kmsg_memory_open(struct inode *inode, struct file *filp); extern int kmsg_mode(int minor, umode_t *mode); +extern int kmsg_sys_buffer_add(size_t size, umode_t mode); +extern void kmsg_sys_buffer_del(int minor); #else @@ -449,6 +451,13 @@ static inline int kmsg_mode(int minor, umode_t *mode) return -ENXIO; } +static inline int kmsg_sys_buffer_add(size_t size, umode_t mode) +{ + return -ENXIO; +} + +static inline void kmsg_sys_buffer_del(int minor) {} + #endif enum { diff --git a/kernel/printk/kmsg.c b/kernel/printk/kmsg.c index b5e07ff..82bc282 100644 --- a/kernel/printk/kmsg.c +++ b/kernel/printk/kmsg.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -141,8 +142,20 @@ static ssize_t kmsg_read(struct log_buffer *log_b, struct file *file, } raw_spin_unlock_irq(&log_b->lock); - ret = wait_event_interruptible(log_b->wait, - user->seq != log_b->next_seq); + if (log_b == &log_buf) { + ret = wait_event_interruptible(log_b->wait, + user->seq != log_b->next_seq); + } else { + rcu_read_unlock(); + kref_get(&log_b->refcount); + ret = wait_event_interruptible(log_b->wait, + user->seq != log_b->next_seq); + if (log_b->minor == -1) + ret = -ENXIO; + if (kref_put(&log_b->refcount, log_buf_release)) + ret = -ENXIO; + rcu_read_lock(); + } if (ret) goto out; raw_spin_lock_irq(&log_b->lock); @@ -311,8 +324,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait) rcu_read_lock(); list_for_each_entry_rcu(log_b, &log_buf.list, list) { if (log_b->minor == minor) { + kref_get(&log_b->refcount); + rcu_read_unlock(); + ret = kmsg_poll(log_b, file, wait); - break; + + if (kref_put(&log_b->refcount, log_buf_release)) + return POLLERR|POLLNVAL; + return ret; } } rcu_read_unlock(); @@ -428,6 +447,88 @@ int kmsg_mode(int minor, umode_t *mode) return ret; } +static DEFINE_SPINLOCK(kmsg_sys_list_lock); + +int kmsg_sys_buffer_add(size_t size, umode_t mode) +{ + unsigned long flags; + int minor = log_buf.minor; + struct log_buffer *log_b; + struct log_buffer *log_b_new; + + if (size < LOG_LINE_MAX + PREFIX_MAX) + return -EINVAL; + + log_b_new = kzalloc(sizeof(struct log_buffer), GFP_KERNEL); + if (!log_b_new) + return -ENOMEM; + + log_b_new->buf = kmalloc(size, GFP_KERNEL); + if (!log_b_new->buf) { + kfree(log_b_new); + return -ENOMEM; + } + + log_b_new->len = size; + log_b_new->lock = __RAW_SPIN_LOCK_UNLOCKED(log_b_new->lock); + init_waitqueue_head(&log_b_new->wait); + kref_init(&log_b_new->refcount); + log_b_new->mode = mode; + + kref_get(&log_b_new->refcount); + + spin_lock_irqsave(&kmsg_sys_list_lock, flags); + + list_for_each_entry(log_b, &log_buf.list, list) { + if (log_b->minor - minor > 1) + break; + + minor = log_b->minor; + } + + if (!(minor & MINORMASK)) { + kref_put(&log_b->refcount, log_buf_release); + spin_unlock_irqrestore(&kmsg_sys_list_lock, flags); + return -ERANGE; + } + + minor += 1; + log_b_new->minor = minor; + + list_add_tail_rcu(&log_b_new->list, &log_b->list); + + spin_unlock_irqrestore(&kmsg_sys_list_lock, flags); + + return minor; +} + +void kmsg_sys_buffer_del(int minor) +{ + unsigned long flags; + struct log_buffer *log_b; + + spin_lock_irqsave(&kmsg_sys_list_lock, flags); + + list_for_each_entry(log_b, &log_buf.list, list) { + if (log_b->minor == minor) + break; + } + + if (log_b == &log_buf) { + spin_unlock_irqrestore(&kmsg_sys_list_lock, flags); + return; + } + + list_del_rcu(&log_b->list); + + spin_unlock_irqrestore(&kmsg_sys_list_lock, flags); + + log_b->minor = -1; + wake_up_interruptible(&log_b->wait); + + kref_put(&log_b->refcount, log_buf_release); +} + static DEFINE_SPINLOCK(dump_list_lock); static LIST_HEAD(dump_list); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index d8626ee..fd5991d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -171,6 +173,7 @@ struct log_buffer log_buf = { .len = __LOG_BUF_K_LEN, .lock = __RAW_SPIN_LOCK_UNLOCKED(log_buf.lock), .wait = __WAIT_QUEUE_HEAD_INITIALIZER(log_buf.wait), + .refcount = { .refcount = { .counter = 0 } }, .first_seq = 0, .first_idx = 0, .next_seq = 0, @@ -216,6 +219,15 @@ u32 log_buf_len_get(void) return log_buf.len; } +void log_buf_release(struct kref *ref) +{ + struct log_buffer *log_b = container_of(ref, struct log_buffer, + refcount); + + kfree(log_b->buf); + kfree(log_b); +} + /* * Check whether there is enough free space for the given message. * diff --git a/kernel/printk/printk.h b/kernel/printk/printk.h index e5c8a46..a873c27 100644 --- a/kernel/printk/printk.h +++ b/kernel/printk/printk.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef CONFIG_PRINTK @@ -111,6 +112,7 @@ struct log_buffer { char *buf; /* cyclic log buffer */ u32 len; /* buffer length */ wait_queue_head_t wait; /* wait queue for kmsg buffer */ + struct kref refcount; /* refcount for kmsg_sys buffers */ #endif /* * The lock protects kmsg buffer, indices, counters. This can be taken within @@ -139,6 +141,8 @@ struct log_buffer { extern struct log_buffer log_buf; +void log_buf_release(struct kref *ref); + ssize_t msg_print_ext_header(char *buf, size_t size, struct printk_log *msg, u64 seq, enum log_flags prev_flags); -- 1.9.1