static long vol_cdev_ioctl()

in ubi/cdev.c [378:584]


static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
			   unsigned long arg)
{
	int err = 0;
	struct ubi_volume_desc *desc = file->private_data;
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	void __user *argp = (void __user *)arg;

	switch (cmd) {
	/* Volume update command */
	case UBI_IOCVOLUP:
	{
		int64_t bytes, rsvd_bytes;

		if (!capable(CAP_SYS_RESOURCE)) {
			err = -EPERM;
			break;
		}

		err = copy_from_user(&bytes, argp, sizeof(int64_t));
		if (err) {
			err = -EFAULT;
			break;
		}

		if (desc->mode == UBI_READONLY) {
			err = -EROFS;
			break;
		}

		rsvd_bytes = (long long)vol->reserved_pebs *
					vol->usable_leb_size;
		if (bytes < 0 || bytes > rsvd_bytes) {
			err = -EINVAL;
			break;
		}

		err = get_exclusive(desc);
		if (err < 0)
			break;

		err = ubi_start_update(ubi, vol, bytes);
		if (bytes == 0) {
			ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
			revoke_exclusive(desc, UBI_READWRITE);
		}
		break;
	}

	/* Atomic logical eraseblock change command */
	case UBI_IOCEBCH:
	{
		struct ubi_leb_change_req req;

		err = copy_from_user(&req, argp,
				     sizeof(struct ubi_leb_change_req));
		if (err) {
			err = -EFAULT;
			break;
		}

		if (desc->mode == UBI_READONLY ||
		    vol->vol_type == UBI_STATIC_VOLUME) {
			err = -EROFS;
			break;
		}

		/* Validate the request */
		err = -EINVAL;
		if (!ubi_leb_valid(vol, req.lnum) ||
		    req.bytes < 0 || req.bytes > vol->usable_leb_size)
			break;

		err = get_exclusive(desc);
		if (err < 0)
			break;

		err = ubi_start_leb_change(ubi, vol, &req);
		if (req.bytes == 0)
			revoke_exclusive(desc, UBI_READWRITE);
		break;
	}

	/* Logical eraseblock erasure command */
	case UBI_IOCEBER:
	{
		int32_t lnum;

		err = get_user(lnum, (__user int32_t *)argp);
		if (err) {
			err = -EFAULT;
			break;
		}

		if (desc->mode == UBI_READONLY ||
		    vol->vol_type == UBI_STATIC_VOLUME) {
			err = -EROFS;
			break;
		}

		if (!ubi_leb_valid(vol, lnum)) {
			err = -EINVAL;
			break;
		}

		dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);
		err = ubi_eba_unmap_leb(ubi, vol, lnum);
		if (err)
			break;

		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
		break;
	}

	/* Logical eraseblock map command */
	case UBI_IOCEBMAP:
	{
		struct ubi_map_req req;

		err = copy_from_user(&req, argp, sizeof(struct ubi_map_req));
		if (err) {
			err = -EFAULT;
			break;
		}
		err = ubi_leb_map(desc, req.lnum);
		break;
	}

	/* Logical eraseblock un-map command */
	case UBI_IOCEBUNMAP:
	{
		int32_t lnum;

		err = get_user(lnum, (__user int32_t *)argp);
		if (err) {
			err = -EFAULT;
			break;
		}
		err = ubi_leb_unmap(desc, lnum);
		break;
	}

	/* Check if logical eraseblock is mapped command */
	case UBI_IOCEBISMAP:
	{
		int32_t lnum;

		err = get_user(lnum, (__user int32_t *)argp);
		if (err) {
			err = -EFAULT;
			break;
		}
		err = ubi_is_mapped(desc, lnum);
		break;
	}

	/* Set volume property command */
	case UBI_IOCSETVOLPROP:
	{
		struct ubi_set_vol_prop_req req;

		err = copy_from_user(&req, argp,
				     sizeof(struct ubi_set_vol_prop_req));
		if (err) {
			err = -EFAULT;
			break;
		}
		switch (req.property) {
		case UBI_VOL_PROP_DIRECT_WRITE:
			mutex_lock(&ubi->device_mutex);
			desc->vol->direct_writes = !!req.value;
			mutex_unlock(&ubi->device_mutex);
			break;
		default:
			err = -EINVAL;
			break;
		}
		break;
	}

	/* Create a R/O block device on top of the UBI volume */
	case UBI_IOCVOLCRBLK:
	{
		struct ubi_volume_info vi;

		ubi_get_volume_info(desc, &vi);
		err = ubiblock_create(&vi);
		break;
	}

	/* Remove the R/O block device */
	case UBI_IOCVOLRMBLK:
	{
		struct ubi_volume_info vi;

		ubi_get_volume_info(desc, &vi);
		err = ubiblock_remove(&vi);
		break;
	}

	default:
		err = -ENOTTY;
		break;
	}
	return err;
}