From: levin li <xingke....@taobao.com>

This patch provides functions to create a sheep device by writing to
the proc entry, but it hasn't processed the IO requests, it just ends
the requests with -EIO.

It creates sheep devices named /dev/sheepX, but until now, it can not
handle IO request, any read/write request to this device will get EIO

Signed-off-by: levin li <xingke....@taobao.com>
---
 sheepdev/device.c   | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 sheepdev/proc.c     |   4 +
 sheepdev/sheepdev.h |   6 ++
 3 files changed, 273 insertions(+)

diff --git a/sheepdev/device.c b/sheepdev/device.c
index 15e149a..bcf82a2 100644
--- a/sheepdev/device.c
+++ b/sheepdev/device.c
@@ -26,22 +26,285 @@
 #include <linux/kthread.h>
 #include "sheepdev.h"
 
+static int sheepdev_major;
+spinlock_t devices_lock;
+struct list_head dev_list;
+static unsigned long *device_bitmap;
+
+static void sheepdev_get(struct sheepdev *dev)
+{
+       atomic_inc(&dev->struct_refcnt);
+}
+
+static void sheepdev_put(struct sheepdev *dev)
+{
+       if (atomic_dec_and_test(&dev->struct_refcnt))
+               kfree(dev);
+}
+
+static void sheep_end_request_directly(struct request *req, int ret)
+{
+       struct request_queue *q = req->q;
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (!list_empty(&req->queuelist))
+               list_del_init(&req->queuelist);
+       __blk_end_request_all(req, ret);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void remove_device(struct sheepdev *dev)
+{
+       DBPRT("remove device /dev/%s\n", dev->disk->disk_name);
+
+       blk_cleanup_queue(dev->disk->queue);
+       del_gendisk(dev->disk);
+       put_disk(dev->disk);
+
+       clear_bit(dev->minor, device_bitmap);
+       write_lock(&dev->sock_lock);
+       if (dev->sock) {
+               inet_release(dev->sock);
+               dev->sock = NULL;
+       }
+       write_unlock(&dev->sock_lock);
+
+       sheepdev_put(dev);
+}
+
+static int sheepdev_open(struct block_device *blkdev, fmode_t mode)
+{
+       struct gendisk *disk = blkdev->bd_disk;
+       struct sheepdev *dev = disk->private_data;
+
+       spin_lock(&dev->dev_lock);
+       dev->device_refcnt++;
+       spin_unlock(&dev->dev_lock);
+
+       return 0;
+}
+
+static int sheepdev_release(struct gendisk *disk, fmode_t mode)
+{
+       struct sheepdev *dev = disk->private_data;
+
+       spin_lock(&dev->dev_lock);
+       dev->device_refcnt--;
+       spin_unlock(&dev->dev_lock);
+
+       return 0;
+}
+
+static const struct block_device_operations sheepdev_ops = {
+       .owner = THIS_MODULE,
+       .open = sheepdev_open,
+       .release = sheepdev_release,
+};
+
+static void sheep_io_request(struct request_queue *rq)
+{
+       struct request *req;
+       struct gendisk *disk;
+       struct sheepdev *dev;
+
+       while ((req = blk_fetch_request(rq)) != NULL) {
+
+               spin_unlock_irq(rq->queue_lock);
+
+               disk = req->rq_disk;
+               dev = disk->private_data;
+
+               if (req->cmd_type != REQ_TYPE_FS) {
+                       DBPRT("Skip non-fs request\n");
+                       __blk_end_request_all(req, -EIO);
+               }
+
+               sheep_end_request_directly(req, -EIO);
+
+               spin_lock_irq(rq->queue_lock);
+       }
+}
+
+static int sheep_add_disk(struct sheepdev *dev)
+{
+       int ret;
+       struct request_queue *queue;
+
+       dev->disk = alloc_disk(SHEEP_BLKDEV_MINORS);
+       if (!dev->disk) {
+               DBPRT("allocate gendisk failure\n");
+               ret = -EBUSY;
+               return ret;
+       }
+       queue = blk_init_queue(sheep_io_request, &dev->que_lock);
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, queue);
+       dev->disk->major = sheepdev_major;
+       dev->disk->first_minor = dev->minor * SHEEP_BLKDEV_MINORS;
+       dev->disk->queue = queue;
+       dev->disk->fops = &sheepdev_ops;
+       dev->disk->private_data = dev;
+       snprintf(dev->disk->disk_name, sizeof(dev->disk->disk_name),
+                SHEEP_BLKDEV_NAME"%c", dev->minor + 'a');
+
+       set_capacity(dev->disk, 0);
+       add_disk(dev->disk);
+       set_capacity(dev->disk, dev->sectors);
+
+       return 0;
+}
+
+static int sheep_dev_setup(struct sheepdev *dev)
+{
+       int ret;
+
+       ret = sheep_vdi_setup(dev);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&dev->que_lock);
+       spin_lock_init(&dev->dev_lock);
+       spin_lock_init(&dev->sd_req_lock);
+       rwlock_init(&dev->creating_lock);
+       rwlock_init(&dev->sock_lock);
+       init_waitqueue_head(&dev->req_wait);
+       init_waitqueue_head(&dev->fin_wait);
+       init_waitqueue_head(&dev->creating_wait);
+       INIT_LIST_HEAD(&dev->pending_list);
+       INIT_LIST_HEAD(&dev->finish_list);
+       INIT_LIST_HEAD(&dev->dev_list);
+       INIT_LIST_HEAD(&dev->deletion_list);
+       INIT_LIST_HEAD(&dev->sd_req_list);
+
+       dev->obj_state_tree = RB_ROOT;
+       dev->req_id = 1;
+
+       ret = sheep_add_disk(dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int sheep_add_device(const char *addr, int port, const char *vdiname,
+                    int snapshot_id, const char *snapshot_tag)
+{
+       struct sheepdev *dev;
+       int ret = 0;
+
+       DBPRT("[%s:%d] vdiname: %s, snapshot id: %d, snapshot tag: %s\n",
+             addr, port, vdiname, snapshot_id, snapshot_tag);
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       memset(dev, 0, sizeof(*dev));
+       dev->port = port;
+       dev->snapshot_id = snapshot_id;
+       memcpy(dev->ip_addr, addr, sizeof(dev->ip_addr));
+       strcpy(dev->vdiname, vdiname);
+       strcpy(dev->snapshot_tag, snapshot_tag);
+
+       spin_lock(&devices_lock);
+       dev->minor = find_next_zero_bit(device_bitmap, SHEEP_BLKDEV_MINORS, 0);
+       set_bit(dev->minor, device_bitmap);
+       spin_unlock(&devices_lock);
+
+       ret = sheep_dev_setup(dev);
+       if (ret) {
+               clear_bit(dev->minor, device_bitmap);
+               goto out;
+       } else {
+               sheepdev_get(dev);
+               spin_lock(&devices_lock);
+               list_add_tail(&dev->dev_list, &dev_list);
+               spin_unlock(&devices_lock);
+       }
+
+       return ret;
+out:
+       kfree(dev);
+       return ret;
+}
+
+int sheep_remove_device(const char *vdiname, int snapshot_id,
+                       const char *snapshot_tag)
+{
+       struct sheepdev *dev, *t;
+       int ret = 0;
+
+       spin_lock(&devices_lock);
+       list_for_each_entry_safe(dev, t, &dev_list, dev_list) {
+               if (strcmp(vdiname, dev->vdiname) != 0)
+                       continue;
+               if (*(dev->snapshot_tag) != '\0' &&
+                   strcmp(snapshot_tag, dev->snapshot_tag) != 0)
+                       continue;
+               if (snapshot_id != 0 &&
+                   snapshot_id != dev->snapshot_id)
+                       continue;
+
+               spin_unlock(&devices_lock);
+
+               spin_lock(&dev->dev_lock);
+               if (dev->device_refcnt) {
+                       spin_unlock(&dev->dev_lock);
+                       ret = -EBUSY;
+               } else {
+                       spin_unlock(&dev->dev_lock);
+                       list_del_init(&dev->dev_list);
+                       remove_device(dev);
+               }
+
+               return ret;
+       }
+       spin_unlock(&devices_lock);
+
+       return -ENXIO;
+}
+
 static int __init sheep_module_init(void)
 {
        int ret;
 
        DBPRT("Block device driver for Sheepdog\n");
 
+       spin_lock_init(&devices_lock);
+       INIT_LIST_HEAD(&dev_list);
+       device_bitmap = kmalloc(SHEEP_BLKDEV_MINORS / 8, GFP_KERNEL);
+       if (!device_bitmap)
+               return -ENOMEM;
+       memset(device_bitmap, 0, SHEEP_BLKDEV_MINORS / 8);
+
        ret = sheep_proc_init();
        if (ret)
                return ret;
 
+       sheepdev_major = register_blkdev(0, SHEEP_BLKDEV_NAME);
+       if (sheepdev_major < 0) {
+               ret = sheepdev_major;
+               goto error;
+       }
+
        return 0;
+error:
+       sheep_proc_destroy();
+       return ret;
 }
 
 static void __exit sheep_module_exit(void)
 {
+       struct sheepdev *dev, *t;
+
+       list_for_each_entry_safe(dev, t, &dev_list, dev_list) {
+               list_del_init(&dev->dev_list);
+               remove_device(dev);
+       }
+
        sheep_proc_destroy();
+       unregister_blkdev(sheepdev_major, SHEEP_BLKDEV_NAME);
+       kfree(device_bitmap);
 
        DBPRT("Sheepdog Block Device Removed.\n");
 }
diff --git a/sheepdev/proc.c b/sheepdev/proc.c
index a2efbe0..e6a46f7 100644
--- a/sheepdev/proc.c
+++ b/sheepdev/proc.c
@@ -59,6 +59,8 @@ static int process_add_command(char *buf)
                }
        }
 
+       ret = sheep_add_device(addr, port, vdiname, snapshot_id, snapshot_tag);
+
        return ret;
 }
 
@@ -85,6 +87,8 @@ static int process_del_command(char *buf)
                }
        }
 
+       ret = sheep_remove_device(vdiname, snapshot_id, snapshot_tag);
+
        return ret;
 }
 
diff --git a/sheepdev/sheepdev.h b/sheepdev/sheepdev.h
index 91a55ea..5ef7098 100644
--- a/sheepdev/sheepdev.h
+++ b/sheepdev/sheepdev.h
@@ -100,4 +100,10 @@ int send_write_req(struct sheepdev *sheepdev, uint64_t 
oid, uint64_t cow_oid,
                   int create);
 int sheep_vdi_setup(struct sheepdev *sheep_dev);
 
+/* device.c */
+int sheep_add_device(const char *addr, int port, const char *vdiname,
+                    int snapshot_id, const char *snapshot_tag);
+int sheep_remove_device(const char *vdiname, int snapshot_id,
+                       const char *snapshot_tag);
+
 #endif
-- 
1.7.11.7

-- 
sheepdog mailing list
sheepdog@lists.wpkg.org
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to