int blktap_control_destroy_device(struct blktap *tap) { int err; unsigned long inuse; if (!tap) return 0; set_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse); for (;;) { inuse = tap->dev_inuse; err = blktap_device_destroy(tap); if (err) goto wait; inuse = tap->dev_inuse; err = blktap_ring_destroy(tap); if (err) goto wait; inuse = tap->dev_inuse; err = blktap_sysfs_destroy(tap); if (err) goto wait; break; wait: BTDBG("inuse: 0x%lx, dev_inuse: 0x%lx\n", inuse, tap->dev_inuse); if (wait_event_interruptible(tap->wq, tap->dev_inuse != inuse)) break; } clear_bit(BLKTAP_SHUTDOWN_REQUESTED, &tap->dev_inuse); if (tap->dev_inuse == (1UL << BLKTAP_CONTROL)) { err = 0; clear_bit(BLKTAP_CONTROL, &tap->dev_inuse); } return err; }
static long blktap_ring_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct blktap *tap = filp->private_data; struct blktap_ring *ring = &tap->ring; void __user *ptr = (void *)arg; int err; BTDBG("%d: cmd: %u, arg: %lu\n", tap->minor, cmd, arg); if (!ring->vma || ring->vma->vm_mm != current->mm) return -EACCES; switch(cmd) { case BLKTAP_IOCTL_RESPOND: blktap_read_ring(tap); return 0; case BLKTAP_IOCTL_CREATE_DEVICE_COMPAT: { struct blktap_device_info info; struct blktap2_params params; if (copy_from_user(¶ms, ptr, sizeof(params))) return -EFAULT; info.capacity = params.capacity; info.sector_size = params.sector_size; info.flags = 0; err = blktap_device_create(tap, &info); if (err) return err; if (params.name[0]) { strncpy(tap->name, params.name, sizeof(params.name)); tap->name[sizeof(tap->name)-1] = 0; } return 0; } case BLKTAP_IOCTL_CREATE_DEVICE: { struct blktap_device_info __user *ptr = (void *)arg; struct blktap_device_info info; unsigned long mask; size_t base_sz, sz; mask = BLKTAP_DEVICE_FLAG_RO; mask |= BLKTAP_DEVICE_FLAG_PSZ; mask |= BLKTAP_DEVICE_FLAG_FLUSH; mask |= BLKTAP_DEVICE_FLAG_TRIM; mask |= BLKTAP_DEVICE_FLAG_TRIM_RZ; memset(&info, 0, sizeof(info)); sz = base_sz = BLKTAP_INFO_SIZE_AT(flags); if (copy_from_user(&info, ptr, sz)) return -EFAULT; if ((info.flags & BLKTAP_DEVICE_FLAG_PSZ) != 0) sz = BLKTAP_INFO_SIZE_AT(phys_block_offset); if (info.flags & BLKTAP_DEVICE_FLAG_TRIM) sz = BLKTAP_INFO_SIZE_AT(trim_block_offset); if (sz > base_sz) if (copy_from_user(&info, ptr, sz)) return -EFAULT; if (put_user(info.flags & mask, &ptr->flags)) return -EFAULT; return blktap_device_create(tap, &info); } case BLKTAP_IOCTL_REMOVE_DEVICE: return blktap_device_destroy(tap); } return -ENOTTY; }