]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/block/nbd.c
of_mdio: fix MDIO phy device refcounting
[karo-tx-linux.git] / drivers / block / nbd.c
index a4f2c7b7d8cf4582d9c0c04da941c4b881bc6069..293495a75d3d8ce1e0f61e3571ddcc0c1fa14312 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/net.h>
 #include <linux/kthread.h>
 #include <linux/types.h>
+#include <linux/debugfs.h>
 
 #include <asm/uaccess.h>
 #include <asm/types.h>
@@ -40,7 +41,7 @@
 #include <linux/nbd.h>
 
 struct nbd_device {
-       int flags;
+       u32 flags;
        struct socket * sock;   /* If == NULL, device is not ready, yet */
        int magic;
 
@@ -55,15 +56,24 @@ struct nbd_device {
        struct gendisk *disk;
        int blksize;
        loff_t bytesize;
-       pid_t pid; /* pid of nbd-client, if attached */
        int xmit_timeout;
-       int disconnect; /* a disconnect has been requested by user */
+       bool disconnect; /* a disconnect has been requested by user */
 
        struct timer_list timeout_timer;
        struct task_struct *task_recv;
        struct task_struct *task_send;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+       struct dentry *dbg_dir;
+#endif
 };
 
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+static struct dentry *nbd_dbg_dir;
+#endif
+
+#define nbd_name(nbd) ((nbd)->disk->disk_name)
+
 #define NBD_MAGIC 0x68797548
 
 static unsigned int nbds_max = 16;
@@ -135,7 +145,7 @@ static void nbd_xmit_timeout(unsigned long arg)
        if (list_empty(&nbd->queue_head))
                return;
 
-       nbd->disconnect = 1;
+       nbd->disconnect = true;
 
        task = READ_ONCE(nbd->task_recv);
        if (task)
@@ -379,9 +389,9 @@ static ssize_t pid_show(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
        struct gendisk *disk = dev_to_disk(dev);
+       struct nbd_device *nbd = (struct nbd_device *)disk->private_data;
 
-       return sprintf(buf, "%ld\n",
-               (long) ((struct nbd_device *)disk->private_data)->pid);
+       return sprintf(buf, "%d\n", task_pid_nr(nbd->task_recv));
 }
 
 static struct device_attribute pid_attr = {
@@ -389,7 +399,7 @@ static struct device_attribute pid_attr = {
        .show = pid_show,
 };
 
-static int nbd_do_it(struct nbd_device *nbd)
+static int nbd_thread_recv(struct nbd_device *nbd)
 {
        struct request *req;
        int ret;
@@ -397,16 +407,16 @@ static int nbd_do_it(struct nbd_device *nbd)
        BUG_ON(nbd->magic != NBD_MAGIC);
 
        sk_set_memalloc(nbd->sock->sk);
-       nbd->pid = task_pid_nr(current);
+
+       nbd->task_recv = current;
+
        ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
        if (ret) {
                dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
-               nbd->pid = 0;
+               nbd->task_recv = NULL;
                return ret;
        }
 
-       nbd->task_recv = current;
-
        while (1) {
                req = nbd_read_stat(nbd);
                if (IS_ERR(req)) {
@@ -417,6 +427,8 @@ static int nbd_do_it(struct nbd_device *nbd)
                nbd_end_request(nbd, req);
        }
 
+       device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
+
        nbd->task_recv = NULL;
 
        if (signal_pending(current)) {
@@ -431,8 +443,6 @@ static int nbd_do_it(struct nbd_device *nbd)
                ret = -ETIMEDOUT;
        }
 
-       device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
-       nbd->pid = 0;
        return ret;
 }
 
@@ -520,7 +530,7 @@ error_out:
        nbd_end_request(nbd, req);
 }
 
-static int nbd_thread(void *data)
+static int nbd_thread_send(void *data)
 {
        struct nbd_device *nbd = data;
        struct request *req;
@@ -574,7 +584,7 @@ static int nbd_thread(void *data)
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
-static void do_nbd_request(struct request_queue *q)
+static void nbd_request_handler(struct request_queue *q)
                __releases(q->queue_lock) __acquires(q->queue_lock)
 {
        struct request *req;
@@ -610,6 +620,9 @@ static void do_nbd_request(struct request_queue *q)
        }
 }
 
+static int nbd_dev_dbg_init(struct nbd_device *nbd);
+static void nbd_dev_dbg_close(struct nbd_device *nbd);
+
 /* Must be called with tx_lock held */
 
 static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
@@ -633,7 +646,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                if (!nbd->sock)
                        return -EINVAL;
 
-               nbd->disconnect = 1;
+               nbd->disconnect = true;
 
                nbd_send_req(nbd, &sreq);
                return 0;
@@ -661,7 +674,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                        nbd->sock = sock;
                        if (max_part > 0)
                                bdev->bd_invalidated = 1;
-                       nbd->disconnect = 0; /* we're connected now */
+                       nbd->disconnect = false; /* we're connected now */
                        return 0;
                }
                return -EINVAL;
@@ -708,7 +721,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                struct socket *sock;
                int error;
 
-               if (nbd->pid)
+               if (nbd->task_recv)
                        return -EBUSY;
                if (!nbd->sock)
                        return -EINVAL;
@@ -725,14 +738,16 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                else
                        blk_queue_flush(nbd->disk->queue, 0);
 
-               thread = kthread_run(nbd_thread, nbd, "%s",
-                                    nbd->disk->disk_name);
+               thread = kthread_run(nbd_thread_send, nbd, "%s",
+                                    nbd_name(nbd));
                if (IS_ERR(thread)) {
                        mutex_lock(&nbd->tx_lock);
                        return PTR_ERR(thread);
                }
 
-               error = nbd_do_it(nbd);
+               nbd_dev_dbg_init(nbd);
+               error = nbd_thread_recv(nbd);
+               nbd_dev_dbg_close(nbd);
                kthread_stop(thread);
 
                mutex_lock(&nbd->tx_lock);
@@ -798,6 +813,161 @@ static const struct block_device_operations nbd_fops =
        .ioctl =        nbd_ioctl,
 };
 
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+
+static int nbd_dbg_tasks_show(struct seq_file *s, void *unused)
+{
+       struct nbd_device *nbd = s->private;
+
+       if (nbd->task_recv)
+               seq_printf(s, "recv: %d\n", task_pid_nr(nbd->task_recv));
+       if (nbd->task_send)
+               seq_printf(s, "send: %d\n", task_pid_nr(nbd->task_send));
+
+       return 0;
+}
+
+static int nbd_dbg_tasks_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nbd_dbg_tasks_show, inode->i_private);
+}
+
+static const struct file_operations nbd_dbg_tasks_ops = {
+       .open = nbd_dbg_tasks_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int nbd_dbg_flags_show(struct seq_file *s, void *unused)
+{
+       struct nbd_device *nbd = s->private;
+       u32 flags = nbd->flags;
+
+       seq_printf(s, "Hex: 0x%08x\n\n", flags);
+
+       seq_puts(s, "Known flags:\n");
+
+       if (flags & NBD_FLAG_HAS_FLAGS)
+               seq_puts(s, "NBD_FLAG_HAS_FLAGS\n");
+       if (flags & NBD_FLAG_READ_ONLY)
+               seq_puts(s, "NBD_FLAG_READ_ONLY\n");
+       if (flags & NBD_FLAG_SEND_FLUSH)
+               seq_puts(s, "NBD_FLAG_SEND_FLUSH\n");
+       if (flags & NBD_FLAG_SEND_TRIM)
+               seq_puts(s, "NBD_FLAG_SEND_TRIM\n");
+
+       return 0;
+}
+
+static int nbd_dbg_flags_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nbd_dbg_flags_show, inode->i_private);
+}
+
+static const struct file_operations nbd_dbg_flags_ops = {
+       .open = nbd_dbg_flags_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int nbd_dev_dbg_init(struct nbd_device *nbd)
+{
+       struct dentry *dir;
+       struct dentry *f;
+
+       dir = debugfs_create_dir(nbd_name(nbd), nbd_dbg_dir);
+       if (IS_ERR_OR_NULL(dir)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs dir for '%s' (%ld)\n",
+                       nbd_name(nbd), PTR_ERR(dir));
+               return PTR_ERR(dir);
+       }
+       nbd->dbg_dir = dir;
+
+       f = debugfs_create_file("tasks", 0444, dir, nbd, &nbd_dbg_tasks_ops);
+       if (IS_ERR_OR_NULL(f)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'tasks', %ld\n",
+                       PTR_ERR(f));
+               return PTR_ERR(f);
+       }
+
+       f = debugfs_create_u64("size_bytes", 0444, dir, &nbd->bytesize);
+       if (IS_ERR_OR_NULL(f)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'size_bytes', %ld\n",
+                       PTR_ERR(f));
+               return PTR_ERR(f);
+       }
+
+       f = debugfs_create_u32("timeout", 0444, dir, &nbd->xmit_timeout);
+       if (IS_ERR_OR_NULL(f)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'timeout', %ld\n",
+                       PTR_ERR(f));
+               return PTR_ERR(f);
+       }
+
+       f = debugfs_create_u32("blocksize", 0444, dir, &nbd->blksize);
+       if (IS_ERR_OR_NULL(f)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'blocksize', %ld\n",
+                       PTR_ERR(f));
+               return PTR_ERR(f);
+       }
+
+       f = debugfs_create_file("flags", 0444, dir, &nbd, &nbd_dbg_flags_ops);
+       if (IS_ERR_OR_NULL(f)) {
+               dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'flags', %ld\n",
+                       PTR_ERR(f));
+               return PTR_ERR(f);
+       }
+
+       return 0;
+}
+
+static void nbd_dev_dbg_close(struct nbd_device *nbd)
+{
+       debugfs_remove_recursive(nbd->dbg_dir);
+}
+
+static int nbd_dbg_init(void)
+{
+       struct dentry *dbg_dir;
+
+       dbg_dir = debugfs_create_dir("nbd", NULL);
+       if (IS_ERR(dbg_dir))
+               return PTR_ERR(dbg_dir);
+
+       nbd_dbg_dir = dbg_dir;
+
+       return 0;
+}
+
+static void nbd_dbg_close(void)
+{
+       debugfs_remove_recursive(nbd_dbg_dir);
+}
+
+#else  /* IS_ENABLED(CONFIG_DEBUG_FS) */
+
+static int nbd_dev_dbg_init(struct nbd_device *nbd)
+{
+       return 0;
+}
+
+static void nbd_dev_dbg_close(struct nbd_device *nbd)
+{
+}
+
+static int nbd_dbg_init(void)
+{
+       return 0;
+}
+
+static void nbd_dbg_close(void)
+{
+}
+
+#endif
+
 /*
  * And here should be modules and kernel interface 
  *  (Just smiley confuses emacs :-)
@@ -851,7 +1021,7 @@ static int __init nbd_init(void)
                 * every gendisk to have its very own request_queue struct.
                 * These structs are big so we dynamically allocate them.
                 */
-               disk->queue = blk_init_queue(do_nbd_request, &nbd_lock);
+               disk->queue = blk_init_queue(nbd_request_handler, &nbd_lock);
                if (!disk->queue) {
                        put_disk(disk);
                        goto out;
@@ -875,6 +1045,8 @@ static int __init nbd_init(void)
 
        printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
 
+       nbd_dbg_init();
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = nbd_dev[i].disk;
                nbd_dev[i].magic = NBD_MAGIC;
@@ -911,6 +1083,9 @@ out:
 static void __exit nbd_cleanup(void)
 {
        int i;
+
+       nbd_dbg_close();
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = nbd_dev[i].disk;
                nbd_dev[i].magic = 0;