struct b_dev_cpu {
spinlock_t lock;
struct list_head done_list;
- unsigned int done_cmds;
};
struct b_dev {
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);
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)
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;
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)
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)
{
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;
}
bdc = per_cpu_ptr(bd->cpu_queue, cpu);
INIT_LIST_HEAD(&bdc->done_list);
- bdc->done_cmds = 0;
spin_lock_init(&bdc->lock);
}
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 = {