kmsg: add ioctl for adding and deleting kmsg* devices 82/60882/3
authorMarcin Niesluchowski <m.niesluchow@samsung.com>
Thu, 18 Jun 2015 09:31:00 +0000 (11:31 +0200)
committerJoonyoung Shim <jy0922.shim@samsung.com>
Fri, 11 Mar 2016 00:50:49 +0000 (16:50 -0800)
There is no possibility to add/delete kmsg* buffers from userspace.

Adds following ioctl for main kmsg device adding and deleting
additional kmsg devices:
* KMSG_CMD_BUFFER_ADD
* KMSG_CMD_BUFFER_DEL

Signed-off-by: Marcin Niesluchowski <m.niesluchow@samsung.com>
Change-Id: Idead7a787892706249f50f1a19ca7a568753845a

Documentation/ioctl/ioctl-number.txt
drivers/char/mem.c
include/linux/printk.h
include/uapi/linux/Kbuild
include/uapi/linux/kmsg_ioctl.h [new file with mode: 0644]
kernel/printk_kmsg.c

index 237acab..3c5e4a7 100644 (file)
@@ -308,6 +308,7 @@ Code  Seq#(hex)     Include File            Comments
                                        <mailto:vgo@ratio.de>
 0xB1   00-1F   PPPoX                   <mailto:mostrows@styx.uwaterloo.ca>
 0xB3   00      linux/mmc/ioctl.h
+0xBB   00-02   uapi/linux/kmsg_ioctl.h
 0xC0   00-0F   linux/usb/iowarrior.h
 0xCB   00-1F   CBM serial IEC bus      in development:
                                        <mailto:michael.klein@puffin.lb.shuttle.de>
index 1dcc6b3..ec7275d 100644 (file)
@@ -896,7 +896,7 @@ static int memory_open(struct inode *inode, struct file *filp)
        minor = iminor(inode);
        if (minor >= ARRAY_SIZE(devlist))
 #ifdef CONFIG_MULTIPLE_KMSG
-               return kmsg_memory_open(inode, filp);
+               return kmsg_memory_open_ext(inode, filp);
 #else
                return -ENXIO;
 #endif
index 303418b..40b0d07 100644 (file)
@@ -356,6 +356,7 @@ extern void dump_stack(void) __cold;
 #endif
 
 extern const struct file_operations kmsg_fops;
+extern const struct file_operations kmsg_fops_ext;
 
 #ifdef CONFIG_MULTIPLE_KMSG
 struct file;
@@ -369,6 +370,7 @@ extern struct class *mem_class;
 
 extern struct device *init_kmsg(int minor, umode_t mode);
 extern int kmsg_memory_open(struct inode *inode, struct file *filp);
+extern int kmsg_memory_open_ext(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);
@@ -385,6 +387,11 @@ static inline int kmsg_memory_open(struct inode *inode, struct file *filp)
        return -ENXIO;
 }
 
+static inline int kmsg_memory_open_ext(struct inode *inode, struct file *filp)
+{
+       return -ENXIO;
+}
+
 static inline int kmsg_mode(int minor, umode_t *mode)
 {
        return -ENXIO;
index 405887b..8cef1e9 100644 (file)
@@ -214,6 +214,10 @@ header-y += kexec.h
 header-y += keyboard.h
 header-y += keyctl.h
 
+ifdef CONFIG_MULTIPLE_KMSG
+header-y += kmsg_ioctl.h
+endif
+
 ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm.h \
                  $(srctree)/arch/$(SRCARCH)/include/asm/kvm.h),)
 header-y += kvm.h
diff --git a/include/uapi/linux/kmsg_ioctl.h b/include/uapi/linux/kmsg_ioctl.h
new file mode 100644 (file)
index 0000000..89c0c61
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * This is ioctl include for kmsg* devices
+ */
+
+#ifndef _KMSG_IOCTL_H_
+#define _KMSG_IOCTL_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+struct kmsg_cmd_buffer_add {
+       size_t size;
+       unsigned short mode;
+       int minor;
+} __attribute__((packed));
+
+#define KMSG_IOCTL_MAGIC       0xBB
+
+/*
+ * A ioctl interface for kmsg device.
+ *
+ * KMSG_CMD_BUFFER_ADD:        Creates additional kmsg device based on its size
+ *                     and mode. Minor of created device is put.
+ * KMSG_CMD_BUFFER_DEL:        Removes additional kmsg device based on its minor
+ */
+#define KMSG_CMD_BUFFER_ADD            _IOWR(KMSG_IOCTL_MAGIC, 0x00, \
+                                             struct kmsg_cmd_buffer_add)
+#define KMSG_CMD_BUFFER_DEL            _IOW(KMSG_IOCTL_MAGIC, 0x01, int)
+
+#endif
index 5b2afd9..00352ab 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
+#ifdef CONFIG_PRINTK
+#include <uapi/linux/kmsg_ioctl.h>
+#endif
+
 #ifdef CONFIG_DEBUG_LL
 extern void printascii(char *);
 #endif
@@ -1324,9 +1328,125 @@ const struct file_operations kmsg_fops = {
        .aio_write = devkmsg_writev,
        .llseek = devkmsg_llseek,
        .poll = devkmsg_poll,
+       .unlocked_ioctl = devkmsg_ioctl,
+       .compat_ioctl = devkmsg_ioctl,
        .release = devkmsg_release,
 };
 
+#define MAX_MINOR_LEN  20
+
+static int kmsg_open_ext(struct inode *inode, struct file *file)
+{
+       return kmsg_fops.open(inode, file);
+}
+
+static ssize_t kmsg_writev_ext(struct kiocb *iocb, const struct iovec *iov, unsigned long count, loff_t pos)
+{
+       return kmsg_fops.aio_write(iocb, iov, count, pos);
+}
+
+static ssize_t kmsg_read_ext(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       return kmsg_fops.read(file, buf, count, ppos);
+}
+
+static loff_t kmsg_llseek_ext(struct file *file, loff_t offset, int whence)
+{
+       return kmsg_fops.llseek(file, offset, whence);
+}
+
+static unsigned int kmsg_poll_ext(struct file *file,
+                                 struct poll_table_struct *wait)
+{
+       return kmsg_fops.poll(file, wait);
+}
+
+static long kmsg_ioctl_buffers(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       size_t size;
+       umode_t mode;
+       char name[4 + MAX_MINOR_LEN + 1];
+       struct device *dev;
+       int minor;
+
+       if (iminor(file->f_inode) != log_buf.minor)
+               return -ENOTTY;
+
+       switch (cmd) {
+       case KMSG_CMD_BUFFER_ADD:
+               if (copy_from_user(&size, argp, sizeof(size)))
+                       return -EFAULT;
+               argp += sizeof(size);
+               if (copy_from_user(&mode, argp, sizeof(mode)))
+                       return -EFAULT;
+               argp += sizeof(mode);
+               minor = kmsg_sys_buffer_add(size, mode);
+               if (minor < 0)
+                       return minor;
+               sprintf(name, "kmsg%d", minor);
+               dev = device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
+                                   NULL, name);
+               if (IS_ERR(dev)) {
+                       kmsg_sys_buffer_del(minor);
+                       return PTR_ERR(dev);
+               }
+               if (copy_to_user(argp, &minor, sizeof(minor))) {
+                       device_destroy(mem_class, MKDEV(MEM_MAJOR, minor));
+                       kmsg_sys_buffer_del(minor);
+                       return -EFAULT;
+               }
+               return 0;
+       case KMSG_CMD_BUFFER_DEL:
+               if (copy_from_user(&minor, argp, sizeof(minor)))
+                       return -EFAULT;
+               if (minor <= log_buf.minor)
+                       return -EINVAL;
+               device_destroy(mem_class, MKDEV(MEM_MAJOR, minor));
+               kmsg_sys_buffer_del(minor);
+               return 0;
+       }
+       return -ENOTTY;
+}
+
+static long kmsg_unlocked_ioctl_ext(struct file *file, unsigned int cmd,
+                                   unsigned long arg)
+{
+       long ret = kmsg_ioctl_buffers(file, cmd, arg);
+
+       if (ret == -ENOTTY)
+               return kmsg_fops.unlocked_ioctl(file, cmd, arg);
+       return ret;
+}
+
+static long kmsg_compat_ioctl_ext(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       long ret = kmsg_ioctl_buffers(file, cmd, arg);
+
+       if (ret == -ENOTTY)
+               return kmsg_fops.compat_ioctl(file, cmd, arg);
+       return ret;
+}
+
+static int kmsg_release_ext(struct inode *inode, struct file *file)
+{
+       return kmsg_fops.release(inode, file);
+}
+
+const struct file_operations kmsg_fops_ext = {
+       .open           = kmsg_open_ext,
+       .read           = kmsg_read_ext,
+       .aio_write      = kmsg_writev_ext,
+       .llseek         = kmsg_llseek_ext,
+       .poll           = kmsg_poll_ext,
+       .unlocked_ioctl = kmsg_unlocked_ioctl_ext,
+       .compat_ioctl   = kmsg_compat_ioctl_ext,
+       .release        = kmsg_release_ext,
+};
+
 /* Should be used for device registration */
 struct device *init_kmsg(int minor, umode_t mode)
 {
@@ -1343,6 +1463,13 @@ int kmsg_memory_open(struct inode *inode, struct file *filp)
        return kmsg_fops.open(inode, filp);
 }
 
+int kmsg_memory_open_ext(struct inode *inode, struct file *filp)
+{
+       filp->f_op = &kmsg_fops_ext;
+
+       return kmsg_fops_ext.open(inode, filp);
+}
+
 int kmsg_mode(int minor, umode_t *mode)
 {
        int ret = -ENXIO;