Fixup ioctls
[binject.git] / main.c
diff --git a/main.c b/main.c
index 45da4f6e9cc903fb510ebc6374c7c1b276a38392..296cbfe1aac8dc61a535545f41d3acd39d054901 100644 (file)
--- a/main.c
+++ b/main.c
@@ -31,7 +31,6 @@ static int b_major;
 struct b_dev_cpu {
        spinlock_t lock;
        struct list_head done_list;
-       unsigned int done_cmds;
 };
 
 struct b_dev {
@@ -199,7 +198,6 @@ ret_one:
                spin_lock_irq(&bdc->lock);
                if (!list_empty(&bdc->done_list)) {
                        list_splice_init(&bdc->done_list, &bd->reaped_done);
-                       bdc->done_cmds = 0;
                        spliced++;
                }
                spin_unlock_irq(&bdc->lock);
@@ -212,20 +210,18 @@ ret_one:
        return NULL;
 }
 
-static int bd_done_count(struct b_dev *bd)
+static int bd_pending_done(struct b_dev *bd)
 {
-       int cpu, done;
+       int cpu;
 
-       done = 0;
        for_each_possible_cpu(cpu) {
                struct b_dev_cpu *bdc = per_cpu_ptr(bd->cpu_queue, cpu);
 
-               spin_lock_irq(&bdc->lock);
-               done += bdc->done_cmds;
-               spin_unlock_irq(&bdc->lock);
+               if (!list_empty_careful(&bdc->done_list))
+                       return 1;
        }
 
-       return done;
+       return 0;
 }
 
 static struct b_cmd *get_done_command(struct b_dev *bd, int block)
@@ -241,7 +237,7 @@ static struct b_cmd *get_done_command(struct b_dev *bd, int block)
                if (!block)
                        break;
 
-               ret = wait_event_interruptible(bd->wq_done, bd_done_count(bd));
+               ret = wait_event_interruptible(bd->wq_done, bd_pending_done(bd));
                if (ret) {
                        bc = ERR_PTR(-ERESTARTSYS);
                        break;
@@ -290,23 +286,23 @@ static void b_dev_complete_commands(struct b_dev *bd)
 
 static int b_dev_validate_command(struct b_user_cmd *buc)
 {
+       int i;
+
        if (!binject_buc_check_magic(buc))
                return -EINVAL;
 
-       switch (buc->type) {
-       case B_TYPE_WRITE:
-       case B_TYPE_READ:
-       case B_TYPE_DISCARD:
-       case B_TYPE_READVOID:
-       case B_TYPE_WRITEZERO:
-       case B_TYPE_READBARRIER:
-       case B_TYPE_WRITEBARRIER:
-               if (buc->len)
-                       return 0;
-               return -EINVAL;
-       default:
-               return -EINVAL;
+       for (i = 0; i < B_TYPE_NR; i++) {
+               const struct uc_map *ucm = &uc_map[i];
+
+               if (ucm->type != buc->type)
+                       continue;
+               if (ucm->data_transfer && !buc->len)
+                       break;
+
+               return 0;
        }
+
+       return -EINVAL;
 }
 
 static void b_cmd_endio(struct bio *bio, int error)
@@ -326,12 +322,13 @@ static void b_cmd_endio(struct bio *bio, int error)
 
        spin_lock(&bdc->lock);
        list_add_tail(&bc->list, &bdc->done_list);
-       bdc->done_cmds++;
        spin_unlock_irqrestore(&bdc->lock, flags);
 
        atomic_dec(&bd->in_flight);
 
-       wake_up(&bd->wq_done);
+       smp_mb();
+       if (waitqueue_active(&bd->wq_done))
+               wake_up(&bd->wq_done);
 }
 
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
@@ -474,18 +471,11 @@ static unsigned int b_dev_poll(struct file *file, poll_table *wait)
 {
        struct b_dev *bd = file->private_data;
        unsigned int mask = POLLOUT;
-       int cpu;
 
        poll_wait(file, &bd->wq_done, wait);
 
-       for_each_possible_cpu(cpu) {
-               struct b_dev_cpu *bdc = per_cpu_ptr(bd->cpu_queue, cpu);
-
-               if (!list_empty_careful(&bdc->done_list)) {
-                       mask |= POLLIN | POLLRDNORM;
-                       break;
-               }
-       }
+       if (bd_pending_done(bd))
+               mask |= POLLIN | POLLRDNORM;
 
        return mask;
 }
@@ -690,7 +680,6 @@ static int b_add_dev(struct b_ioctl_cmd *bic)
 
                bdc = per_cpu_ptr(bd->cpu_queue, cpu);
                INIT_LIST_HEAD(&bdc->done_list);
-               bdc->done_cmds = 0;
                spin_lock_init(&bdc->lock);
        }
 
@@ -747,21 +736,21 @@ static long b_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return -EFAULT;
 
        switch (cmd) {
-       case 0:
+       case B_IOCTL_ADD:
                ret = b_add_dev(&bic);
                if (!ret && copy_to_user(uarg, &bic, sizeof(bic))) {
                        b_del_dev(&bic);
                        ret = -EFAULT;
                }
                break;
-       case 1:
+       case B_IOCTL_DEL:
                ret =  b_del_dev(&bic);
                break;
        default:
                break;
        }
 
-       return -ENOTTY;
+       return ret;
 }
 
 static const struct file_operations b_misc_fops = {