18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) International Business Machines Corp., 2006
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Artem Bityutskiy (Битюцкий Артём)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci * This file includes implementation of UBI character device operations.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * There are two kinds of character devices in UBI: UBI character devices and
128c2ecf20Sopenharmony_ci * UBI volume character devices. UBI character devices allow users to
138c2ecf20Sopenharmony_ci * manipulate whole volumes: create, remove, and re-size them. Volume character
148c2ecf20Sopenharmony_ci * devices provide volume I/O capabilities.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Major and minor numbers are assigned dynamically to both UBI and volume
178c2ecf20Sopenharmony_ci * character devices.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Well, there is the third kind of character devices - the UBI control
208c2ecf20Sopenharmony_ci * character device, which allows to manipulate by UBI devices - create and
218c2ecf20Sopenharmony_ci * delete them. In other words, it is used for attaching and detaching MTD
228c2ecf20Sopenharmony_ci * devices.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/stat.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <linux/ioctl.h>
298c2ecf20Sopenharmony_ci#include <linux/capability.h>
308c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
318c2ecf20Sopenharmony_ci#include <linux/compat.h>
328c2ecf20Sopenharmony_ci#include <linux/math64.h>
338c2ecf20Sopenharmony_ci#include <mtd/ubi-user.h>
348c2ecf20Sopenharmony_ci#include "ubi.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/**
378c2ecf20Sopenharmony_ci * get_exclusive - get exclusive access to an UBI volume.
388c2ecf20Sopenharmony_ci * @desc: volume descriptor
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * This function changes UBI volume open mode to "exclusive". Returns previous
418c2ecf20Sopenharmony_ci * mode value (positive integer) in case of success and a negative error code
428c2ecf20Sopenharmony_ci * in case of failure.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_cistatic int get_exclusive(struct ubi_volume_desc *desc)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int users, err;
478c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	spin_lock(&vol->ubi->volumes_lock);
508c2ecf20Sopenharmony_ci	users = vol->readers + vol->writers + vol->exclusive + vol->metaonly;
518c2ecf20Sopenharmony_ci	ubi_assert(users > 0);
528c2ecf20Sopenharmony_ci	if (users > 1) {
538c2ecf20Sopenharmony_ci		ubi_err(vol->ubi, "%d users for volume %d", users, vol->vol_id);
548c2ecf20Sopenharmony_ci		err = -EBUSY;
558c2ecf20Sopenharmony_ci	} else {
568c2ecf20Sopenharmony_ci		vol->readers = vol->writers = vol->metaonly = 0;
578c2ecf20Sopenharmony_ci		vol->exclusive = 1;
588c2ecf20Sopenharmony_ci		err = desc->mode;
598c2ecf20Sopenharmony_ci		desc->mode = UBI_EXCLUSIVE;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci	spin_unlock(&vol->ubi->volumes_lock);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return err;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci * revoke_exclusive - revoke exclusive mode.
688c2ecf20Sopenharmony_ci * @desc: volume descriptor
698c2ecf20Sopenharmony_ci * @mode: new mode to switch to
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistatic void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	spin_lock(&vol->ubi->volumes_lock);
768c2ecf20Sopenharmony_ci	ubi_assert(vol->readers == 0 && vol->writers == 0 && vol->metaonly == 0);
778c2ecf20Sopenharmony_ci	ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
788c2ecf20Sopenharmony_ci	vol->exclusive = 0;
798c2ecf20Sopenharmony_ci	if (mode == UBI_READONLY)
808c2ecf20Sopenharmony_ci		vol->readers = 1;
818c2ecf20Sopenharmony_ci	else if (mode == UBI_READWRITE)
828c2ecf20Sopenharmony_ci		vol->writers = 1;
838c2ecf20Sopenharmony_ci	else if (mode == UBI_METAONLY)
848c2ecf20Sopenharmony_ci		vol->metaonly = 1;
858c2ecf20Sopenharmony_ci	else
868c2ecf20Sopenharmony_ci		vol->exclusive = 1;
878c2ecf20Sopenharmony_ci	spin_unlock(&vol->ubi->volumes_lock);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	desc->mode = mode;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int vol_cdev_open(struct inode *inode, struct file *file)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc;
958c2ecf20Sopenharmony_ci	int vol_id = iminor(inode) - 1, mode, ubi_num;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	ubi_num = ubi_major2num(imajor(inode));
988c2ecf20Sopenharmony_ci	if (ubi_num < 0)
998c2ecf20Sopenharmony_ci		return ubi_num;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (file->f_mode & FMODE_WRITE)
1028c2ecf20Sopenharmony_ci		mode = UBI_READWRITE;
1038c2ecf20Sopenharmony_ci	else
1048c2ecf20Sopenharmony_ci		mode = UBI_READONLY;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	dbg_gen("open device %d, volume %d, mode %d",
1078c2ecf20Sopenharmony_ci		ubi_num, vol_id, mode);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	desc = ubi_open_volume(ubi_num, vol_id, mode);
1108c2ecf20Sopenharmony_ci	if (IS_ERR(desc))
1118c2ecf20Sopenharmony_ci		return PTR_ERR(desc);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	file->private_data = desc;
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int vol_cdev_release(struct inode *inode, struct file *file)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
1208c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	dbg_gen("release device %d, volume %d, mode %d",
1238c2ecf20Sopenharmony_ci		vol->ubi->ubi_num, vol->vol_id, desc->mode);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (vol->updating) {
1268c2ecf20Sopenharmony_ci		ubi_warn(vol->ubi, "update of volume %d not finished, volume is damaged",
1278c2ecf20Sopenharmony_ci			 vol->vol_id);
1288c2ecf20Sopenharmony_ci		ubi_assert(!vol->changing_leb);
1298c2ecf20Sopenharmony_ci		vol->updating = 0;
1308c2ecf20Sopenharmony_ci		vfree(vol->upd_buf);
1318c2ecf20Sopenharmony_ci	} else if (vol->changing_leb) {
1328c2ecf20Sopenharmony_ci		dbg_gen("only %lld of %lld bytes received for atomic LEB change for volume %d:%d, cancel",
1338c2ecf20Sopenharmony_ci			vol->upd_received, vol->upd_bytes, vol->ubi->ubi_num,
1348c2ecf20Sopenharmony_ci			vol->vol_id);
1358c2ecf20Sopenharmony_ci		vol->changing_leb = 0;
1368c2ecf20Sopenharmony_ci		vfree(vol->upd_buf);
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ubi_close_volume(desc);
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
1468c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (vol->updating) {
1498c2ecf20Sopenharmony_ci		/* Update is in progress, seeking is prohibited */
1508c2ecf20Sopenharmony_ci		ubi_err(vol->ubi, "updating");
1518c2ecf20Sopenharmony_ci		return -EBUSY;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return fixed_size_llseek(file, offset, origin, vol->used_bytes);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int vol_cdev_fsync(struct file *file, loff_t start, loff_t end,
1588c2ecf20Sopenharmony_ci			  int datasync)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
1618c2ecf20Sopenharmony_ci	struct ubi_device *ubi = desc->vol->ubi;
1628c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
1638c2ecf20Sopenharmony_ci	int err;
1648c2ecf20Sopenharmony_ci	inode_lock(inode);
1658c2ecf20Sopenharmony_ci	err = ubi_sync(ubi->ubi_num);
1668c2ecf20Sopenharmony_ci	inode_unlock(inode);
1678c2ecf20Sopenharmony_ci	return err;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
1728c2ecf20Sopenharmony_ci			     loff_t *offp)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
1758c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
1768c2ecf20Sopenharmony_ci	struct ubi_device *ubi = vol->ubi;
1778c2ecf20Sopenharmony_ci	int err, lnum, off, len,  tbuf_size;
1788c2ecf20Sopenharmony_ci	size_t count_save = count;
1798c2ecf20Sopenharmony_ci	void *tbuf;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	dbg_gen("read %zd bytes from offset %lld of volume %d",
1828c2ecf20Sopenharmony_ci		count, *offp, vol->vol_id);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (vol->updating) {
1858c2ecf20Sopenharmony_ci		ubi_err(vol->ubi, "updating");
1868c2ecf20Sopenharmony_ci		return -EBUSY;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	if (vol->upd_marker) {
1898c2ecf20Sopenharmony_ci		ubi_err(vol->ubi, "damaged volume, update marker is set");
1908c2ecf20Sopenharmony_ci		return -EBADF;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci	if (*offp == vol->used_bytes || count == 0)
1938c2ecf20Sopenharmony_ci		return 0;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (vol->corrupted)
1968c2ecf20Sopenharmony_ci		dbg_gen("read from corrupted volume %d", vol->vol_id);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (*offp + count > vol->used_bytes)
1998c2ecf20Sopenharmony_ci		count_save = count = vol->used_bytes - *offp;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	tbuf_size = vol->usable_leb_size;
2028c2ecf20Sopenharmony_ci	if (count < tbuf_size)
2038c2ecf20Sopenharmony_ci		tbuf_size = ALIGN(count, ubi->min_io_size);
2048c2ecf20Sopenharmony_ci	tbuf = vmalloc(tbuf_size);
2058c2ecf20Sopenharmony_ci	if (!tbuf)
2068c2ecf20Sopenharmony_ci		return -ENOMEM;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	len = count > tbuf_size ? tbuf_size : count;
2098c2ecf20Sopenharmony_ci	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	do {
2128c2ecf20Sopenharmony_ci		cond_resched();
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		if (off + len >= vol->usable_leb_size)
2158c2ecf20Sopenharmony_ci			len = vol->usable_leb_size - off;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
2188c2ecf20Sopenharmony_ci		if (err)
2198c2ecf20Sopenharmony_ci			break;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		off += len;
2228c2ecf20Sopenharmony_ci		if (off == vol->usable_leb_size) {
2238c2ecf20Sopenharmony_ci			lnum += 1;
2248c2ecf20Sopenharmony_ci			off -= vol->usable_leb_size;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		count -= len;
2288c2ecf20Sopenharmony_ci		*offp += len;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		err = copy_to_user(buf, tbuf, len);
2318c2ecf20Sopenharmony_ci		if (err) {
2328c2ecf20Sopenharmony_ci			err = -EFAULT;
2338c2ecf20Sopenharmony_ci			break;
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		buf += len;
2378c2ecf20Sopenharmony_ci		len = count > tbuf_size ? tbuf_size : count;
2388c2ecf20Sopenharmony_ci	} while (count);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	vfree(tbuf);
2418c2ecf20Sopenharmony_ci	return err ? err : count_save - count;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/*
2458c2ecf20Sopenharmony_ci * This function allows to directly write to dynamic UBI volumes, without
2468c2ecf20Sopenharmony_ci * issuing the volume update operation.
2478c2ecf20Sopenharmony_ci */
2488c2ecf20Sopenharmony_cistatic ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
2498c2ecf20Sopenharmony_ci				     size_t count, loff_t *offp)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
2528c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
2538c2ecf20Sopenharmony_ci	struct ubi_device *ubi = vol->ubi;
2548c2ecf20Sopenharmony_ci	int lnum, off, len, tbuf_size, err = 0;
2558c2ecf20Sopenharmony_ci	size_t count_save = count;
2568c2ecf20Sopenharmony_ci	char *tbuf;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (!vol->direct_writes)
2598c2ecf20Sopenharmony_ci		return -EPERM;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	dbg_gen("requested: write %zd bytes to offset %lld of volume %u",
2628c2ecf20Sopenharmony_ci		count, *offp, vol->vol_id);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (vol->vol_type == UBI_STATIC_VOLUME)
2658c2ecf20Sopenharmony_ci		return -EROFS;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
2688c2ecf20Sopenharmony_ci	if (off & (ubi->min_io_size - 1)) {
2698c2ecf20Sopenharmony_ci		ubi_err(ubi, "unaligned position");
2708c2ecf20Sopenharmony_ci		return -EINVAL;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (*offp + count > vol->used_bytes)
2748c2ecf20Sopenharmony_ci		count_save = count = vol->used_bytes - *offp;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* We can write only in fractions of the minimum I/O unit */
2778c2ecf20Sopenharmony_ci	if (count & (ubi->min_io_size - 1)) {
2788c2ecf20Sopenharmony_ci		ubi_err(ubi, "unaligned write length");
2798c2ecf20Sopenharmony_ci		return -EINVAL;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	tbuf_size = vol->usable_leb_size;
2838c2ecf20Sopenharmony_ci	if (count < tbuf_size)
2848c2ecf20Sopenharmony_ci		tbuf_size = ALIGN(count, ubi->min_io_size);
2858c2ecf20Sopenharmony_ci	tbuf = vmalloc(tbuf_size);
2868c2ecf20Sopenharmony_ci	if (!tbuf)
2878c2ecf20Sopenharmony_ci		return -ENOMEM;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	len = count > tbuf_size ? tbuf_size : count;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	while (count) {
2928c2ecf20Sopenharmony_ci		cond_resched();
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		if (off + len >= vol->usable_leb_size)
2958c2ecf20Sopenharmony_ci			len = vol->usable_leb_size - off;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		err = copy_from_user(tbuf, buf, len);
2988c2ecf20Sopenharmony_ci		if (err) {
2998c2ecf20Sopenharmony_ci			err = -EFAULT;
3008c2ecf20Sopenharmony_ci			break;
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci		err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len);
3048c2ecf20Sopenharmony_ci		if (err)
3058c2ecf20Sopenharmony_ci			break;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		off += len;
3088c2ecf20Sopenharmony_ci		if (off == vol->usable_leb_size) {
3098c2ecf20Sopenharmony_ci			lnum += 1;
3108c2ecf20Sopenharmony_ci			off -= vol->usable_leb_size;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		count -= len;
3148c2ecf20Sopenharmony_ci		*offp += len;
3158c2ecf20Sopenharmony_ci		buf += len;
3168c2ecf20Sopenharmony_ci		len = count > tbuf_size ? tbuf_size : count;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	vfree(tbuf);
3208c2ecf20Sopenharmony_ci	return err ? err : count_save - count;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic ssize_t vol_cdev_write(struct file *file, const char __user *buf,
3248c2ecf20Sopenharmony_ci			      size_t count, loff_t *offp)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	int err = 0;
3278c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
3288c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
3298c2ecf20Sopenharmony_ci	struct ubi_device *ubi = vol->ubi;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (!vol->updating && !vol->changing_leb)
3328c2ecf20Sopenharmony_ci		return vol_cdev_direct_write(file, buf, count, offp);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (vol->updating)
3358c2ecf20Sopenharmony_ci		err = ubi_more_update_data(ubi, vol, buf, count);
3368c2ecf20Sopenharmony_ci	else
3378c2ecf20Sopenharmony_ci		err = ubi_more_leb_change_data(ubi, vol, buf, count);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (err < 0) {
3408c2ecf20Sopenharmony_ci		ubi_err(ubi, "cannot accept more %zd bytes of data, error %d",
3418c2ecf20Sopenharmony_ci			count, err);
3428c2ecf20Sopenharmony_ci		return err;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (err) {
3468c2ecf20Sopenharmony_ci		/*
3478c2ecf20Sopenharmony_ci		 * The operation is finished, @err contains number of actually
3488c2ecf20Sopenharmony_ci		 * written bytes.
3498c2ecf20Sopenharmony_ci		 */
3508c2ecf20Sopenharmony_ci		count = err;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		if (vol->changing_leb) {
3538c2ecf20Sopenharmony_ci			revoke_exclusive(desc, UBI_READWRITE);
3548c2ecf20Sopenharmony_ci			return count;
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		/*
3588c2ecf20Sopenharmony_ci		 * We voluntarily do not take into account the skip_check flag
3598c2ecf20Sopenharmony_ci		 * as we want to make sure what we wrote was correctly written.
3608c2ecf20Sopenharmony_ci		 */
3618c2ecf20Sopenharmony_ci		err = ubi_check_volume(ubi, vol->vol_id);
3628c2ecf20Sopenharmony_ci		if (err < 0)
3638c2ecf20Sopenharmony_ci			return err;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		if (err) {
3668c2ecf20Sopenharmony_ci			ubi_warn(ubi, "volume %d on UBI device %d is corrupted",
3678c2ecf20Sopenharmony_ci				 vol->vol_id, ubi->ubi_num);
3688c2ecf20Sopenharmony_ci			vol->corrupted = 1;
3698c2ecf20Sopenharmony_ci		}
3708c2ecf20Sopenharmony_ci		vol->checked = 1;
3718c2ecf20Sopenharmony_ci		ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
3728c2ecf20Sopenharmony_ci		revoke_exclusive(desc, UBI_READWRITE);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return count;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic long vol_cdev_ioctl(struct file *file, unsigned int cmd,
3798c2ecf20Sopenharmony_ci			   unsigned long arg)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	int err = 0;
3828c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc = file->private_data;
3838c2ecf20Sopenharmony_ci	struct ubi_volume *vol = desc->vol;
3848c2ecf20Sopenharmony_ci	struct ubi_device *ubi = vol->ubi;
3858c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	switch (cmd) {
3888c2ecf20Sopenharmony_ci	/* Volume update command */
3898c2ecf20Sopenharmony_ci	case UBI_IOCVOLUP:
3908c2ecf20Sopenharmony_ci	{
3918c2ecf20Sopenharmony_ci		int64_t bytes, rsvd_bytes;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_RESOURCE)) {
3948c2ecf20Sopenharmony_ci			err = -EPERM;
3958c2ecf20Sopenharmony_ci			break;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		err = copy_from_user(&bytes, argp, sizeof(int64_t));
3998c2ecf20Sopenharmony_ci		if (err) {
4008c2ecf20Sopenharmony_ci			err = -EFAULT;
4018c2ecf20Sopenharmony_ci			break;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		if (desc->mode == UBI_READONLY) {
4058c2ecf20Sopenharmony_ci			err = -EROFS;
4068c2ecf20Sopenharmony_ci			break;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		rsvd_bytes = (long long)vol->reserved_pebs *
4108c2ecf20Sopenharmony_ci					vol->usable_leb_size;
4118c2ecf20Sopenharmony_ci		if (bytes < 0 || bytes > rsvd_bytes) {
4128c2ecf20Sopenharmony_ci			err = -EINVAL;
4138c2ecf20Sopenharmony_ci			break;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		err = get_exclusive(desc);
4178c2ecf20Sopenharmony_ci		if (err < 0)
4188c2ecf20Sopenharmony_ci			break;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci		err = ubi_start_update(ubi, vol, bytes);
4218c2ecf20Sopenharmony_ci		if (bytes == 0) {
4228c2ecf20Sopenharmony_ci			ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
4238c2ecf20Sopenharmony_ci			revoke_exclusive(desc, UBI_READWRITE);
4248c2ecf20Sopenharmony_ci		}
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* Atomic logical eraseblock change command */
4298c2ecf20Sopenharmony_ci	case UBI_IOCEBCH:
4308c2ecf20Sopenharmony_ci	{
4318c2ecf20Sopenharmony_ci		struct ubi_leb_change_req req;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp,
4348c2ecf20Sopenharmony_ci				     sizeof(struct ubi_leb_change_req));
4358c2ecf20Sopenharmony_ci		if (err) {
4368c2ecf20Sopenharmony_ci			err = -EFAULT;
4378c2ecf20Sopenharmony_ci			break;
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		if (desc->mode == UBI_READONLY ||
4418c2ecf20Sopenharmony_ci		    vol->vol_type == UBI_STATIC_VOLUME) {
4428c2ecf20Sopenharmony_ci			err = -EROFS;
4438c2ecf20Sopenharmony_ci			break;
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		/* Validate the request */
4478c2ecf20Sopenharmony_ci		err = -EINVAL;
4488c2ecf20Sopenharmony_ci		if (!ubi_leb_valid(vol, req.lnum) ||
4498c2ecf20Sopenharmony_ci		    req.bytes < 0 || req.bytes > vol->usable_leb_size)
4508c2ecf20Sopenharmony_ci			break;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		err = get_exclusive(desc);
4538c2ecf20Sopenharmony_ci		if (err < 0)
4548c2ecf20Sopenharmony_ci			break;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		err = ubi_start_leb_change(ubi, vol, &req);
4578c2ecf20Sopenharmony_ci		if (req.bytes == 0)
4588c2ecf20Sopenharmony_ci			revoke_exclusive(desc, UBI_READWRITE);
4598c2ecf20Sopenharmony_ci		break;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* Logical eraseblock erasure command */
4638c2ecf20Sopenharmony_ci	case UBI_IOCEBER:
4648c2ecf20Sopenharmony_ci	{
4658c2ecf20Sopenharmony_ci		int32_t lnum;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		err = get_user(lnum, (__user int32_t *)argp);
4688c2ecf20Sopenharmony_ci		if (err) {
4698c2ecf20Sopenharmony_ci			err = -EFAULT;
4708c2ecf20Sopenharmony_ci			break;
4718c2ecf20Sopenharmony_ci		}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		if (desc->mode == UBI_READONLY ||
4748c2ecf20Sopenharmony_ci		    vol->vol_type == UBI_STATIC_VOLUME) {
4758c2ecf20Sopenharmony_ci			err = -EROFS;
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		if (!ubi_leb_valid(vol, lnum)) {
4808c2ecf20Sopenharmony_ci			err = -EINVAL;
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);
4858c2ecf20Sopenharmony_ci		err = ubi_eba_unmap_leb(ubi, vol, lnum);
4868c2ecf20Sopenharmony_ci		if (err)
4878c2ecf20Sopenharmony_ci			break;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
4908c2ecf20Sopenharmony_ci		break;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* Logical eraseblock map command */
4948c2ecf20Sopenharmony_ci	case UBI_IOCEBMAP:
4958c2ecf20Sopenharmony_ci	{
4968c2ecf20Sopenharmony_ci		struct ubi_map_req req;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp, sizeof(struct ubi_map_req));
4998c2ecf20Sopenharmony_ci		if (err) {
5008c2ecf20Sopenharmony_ci			err = -EFAULT;
5018c2ecf20Sopenharmony_ci			break;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci		err = ubi_leb_map(desc, req.lnum);
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/* Logical eraseblock un-map command */
5088c2ecf20Sopenharmony_ci	case UBI_IOCEBUNMAP:
5098c2ecf20Sopenharmony_ci	{
5108c2ecf20Sopenharmony_ci		int32_t lnum;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		err = get_user(lnum, (__user int32_t *)argp);
5138c2ecf20Sopenharmony_ci		if (err) {
5148c2ecf20Sopenharmony_ci			err = -EFAULT;
5158c2ecf20Sopenharmony_ci			break;
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci		err = ubi_leb_unmap(desc, lnum);
5188c2ecf20Sopenharmony_ci		break;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* Check if logical eraseblock is mapped command */
5228c2ecf20Sopenharmony_ci	case UBI_IOCEBISMAP:
5238c2ecf20Sopenharmony_ci	{
5248c2ecf20Sopenharmony_ci		int32_t lnum;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		err = get_user(lnum, (__user int32_t *)argp);
5278c2ecf20Sopenharmony_ci		if (err) {
5288c2ecf20Sopenharmony_ci			err = -EFAULT;
5298c2ecf20Sopenharmony_ci			break;
5308c2ecf20Sopenharmony_ci		}
5318c2ecf20Sopenharmony_ci		err = ubi_is_mapped(desc, lnum);
5328c2ecf20Sopenharmony_ci		break;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Set volume property command */
5368c2ecf20Sopenharmony_ci	case UBI_IOCSETVOLPROP:
5378c2ecf20Sopenharmony_ci	{
5388c2ecf20Sopenharmony_ci		struct ubi_set_vol_prop_req req;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp,
5418c2ecf20Sopenharmony_ci				     sizeof(struct ubi_set_vol_prop_req));
5428c2ecf20Sopenharmony_ci		if (err) {
5438c2ecf20Sopenharmony_ci			err = -EFAULT;
5448c2ecf20Sopenharmony_ci			break;
5458c2ecf20Sopenharmony_ci		}
5468c2ecf20Sopenharmony_ci		switch (req.property) {
5478c2ecf20Sopenharmony_ci		case UBI_VOL_PROP_DIRECT_WRITE:
5488c2ecf20Sopenharmony_ci			mutex_lock(&ubi->device_mutex);
5498c2ecf20Sopenharmony_ci			desc->vol->direct_writes = !!req.value;
5508c2ecf20Sopenharmony_ci			mutex_unlock(&ubi->device_mutex);
5518c2ecf20Sopenharmony_ci			break;
5528c2ecf20Sopenharmony_ci		default:
5538c2ecf20Sopenharmony_ci			err = -EINVAL;
5548c2ecf20Sopenharmony_ci			break;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci		break;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Create a R/O block device on top of the UBI volume */
5608c2ecf20Sopenharmony_ci	case UBI_IOCVOLCRBLK:
5618c2ecf20Sopenharmony_ci	{
5628c2ecf20Sopenharmony_ci		struct ubi_volume_info vi;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		ubi_get_volume_info(desc, &vi);
5658c2ecf20Sopenharmony_ci		err = ubiblock_create(&vi);
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* Remove the R/O block device */
5708c2ecf20Sopenharmony_ci	case UBI_IOCVOLRMBLK:
5718c2ecf20Sopenharmony_ci	{
5728c2ecf20Sopenharmony_ci		struct ubi_volume_info vi;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		ubi_get_volume_info(desc, &vi);
5758c2ecf20Sopenharmony_ci		err = ubiblock_remove(&vi);
5768c2ecf20Sopenharmony_ci		break;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	default:
5808c2ecf20Sopenharmony_ci		err = -ENOTTY;
5818c2ecf20Sopenharmony_ci		break;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci	return err;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci/**
5878c2ecf20Sopenharmony_ci * verify_mkvol_req - verify volume creation request.
5888c2ecf20Sopenharmony_ci * @ubi: UBI device description object
5898c2ecf20Sopenharmony_ci * @req: the request to check
5908c2ecf20Sopenharmony_ci *
5918c2ecf20Sopenharmony_ci * This function zero if the request is correct, and %-EINVAL if not.
5928c2ecf20Sopenharmony_ci */
5938c2ecf20Sopenharmony_cistatic int verify_mkvol_req(const struct ubi_device *ubi,
5948c2ecf20Sopenharmony_ci			    const struct ubi_mkvol_req *req)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	int n, err = -EINVAL;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
5998c2ecf20Sopenharmony_ci	    req->name_len < 0)
6008c2ecf20Sopenharmony_ci		goto bad;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
6038c2ecf20Sopenharmony_ci	    req->vol_id != UBI_VOL_NUM_AUTO)
6048c2ecf20Sopenharmony_ci		goto bad;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (req->alignment == 0)
6078c2ecf20Sopenharmony_ci		goto bad;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (req->bytes == 0)
6108c2ecf20Sopenharmony_ci		goto bad;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (req->vol_type != UBI_DYNAMIC_VOLUME &&
6138c2ecf20Sopenharmony_ci	    req->vol_type != UBI_STATIC_VOLUME)
6148c2ecf20Sopenharmony_ci		goto bad;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (req->flags & ~UBI_VOL_VALID_FLGS)
6178c2ecf20Sopenharmony_ci		goto bad;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG &&
6208c2ecf20Sopenharmony_ci	    req->vol_type != UBI_STATIC_VOLUME)
6218c2ecf20Sopenharmony_ci		goto bad;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (req->alignment > ubi->leb_size)
6248c2ecf20Sopenharmony_ci		goto bad;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	n = req->alignment & (ubi->min_io_size - 1);
6278c2ecf20Sopenharmony_ci	if (req->alignment != 1 && n)
6288c2ecf20Sopenharmony_ci		goto bad;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	if (!req->name[0] || !req->name_len)
6318c2ecf20Sopenharmony_ci		goto bad;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (req->name_len > UBI_VOL_NAME_MAX) {
6348c2ecf20Sopenharmony_ci		err = -ENAMETOOLONG;
6358c2ecf20Sopenharmony_ci		goto bad;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	n = strnlen(req->name, req->name_len + 1);
6398c2ecf20Sopenharmony_ci	if (n != req->name_len)
6408c2ecf20Sopenharmony_ci		goto bad;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	return 0;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cibad:
6458c2ecf20Sopenharmony_ci	ubi_err(ubi, "bad volume creation request");
6468c2ecf20Sopenharmony_ci	ubi_dump_mkvol_req(req);
6478c2ecf20Sopenharmony_ci	return err;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/**
6518c2ecf20Sopenharmony_ci * verify_rsvol_req - verify volume re-size request.
6528c2ecf20Sopenharmony_ci * @ubi: UBI device description object
6538c2ecf20Sopenharmony_ci * @req: the request to check
6548c2ecf20Sopenharmony_ci *
6558c2ecf20Sopenharmony_ci * This function returns zero if the request is correct, and %-EINVAL if not.
6568c2ecf20Sopenharmony_ci */
6578c2ecf20Sopenharmony_cistatic int verify_rsvol_req(const struct ubi_device *ubi,
6588c2ecf20Sopenharmony_ci			    const struct ubi_rsvol_req *req)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	if (req->bytes <= 0)
6618c2ecf20Sopenharmony_ci		return -EINVAL;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)
6648c2ecf20Sopenharmony_ci		return -EINVAL;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * rename_volumes - rename UBI volumes.
6718c2ecf20Sopenharmony_ci * @ubi: UBI device description object
6728c2ecf20Sopenharmony_ci * @req: volumes re-name request
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * This is a helper function for the volume re-name IOCTL which validates the
6758c2ecf20Sopenharmony_ci * the request, opens the volume and calls corresponding volumes management
6768c2ecf20Sopenharmony_ci * function. Returns zero in case of success and a negative error code in case
6778c2ecf20Sopenharmony_ci * of failure.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic int rename_volumes(struct ubi_device *ubi,
6808c2ecf20Sopenharmony_ci			  struct ubi_rnvol_req *req)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	int i, n, err;
6838c2ecf20Sopenharmony_ci	struct list_head rename_list;
6848c2ecf20Sopenharmony_ci	struct ubi_rename_entry *re, *re1;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (req->count < 0 || req->count > UBI_MAX_RNVOL)
6878c2ecf20Sopenharmony_ci		return -EINVAL;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (req->count == 0)
6908c2ecf20Sopenharmony_ci		return 0;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	/* Validate volume IDs and names in the request */
6938c2ecf20Sopenharmony_ci	for (i = 0; i < req->count; i++) {
6948c2ecf20Sopenharmony_ci		if (req->ents[i].vol_id < 0 ||
6958c2ecf20Sopenharmony_ci		    req->ents[i].vol_id >= ubi->vtbl_slots)
6968c2ecf20Sopenharmony_ci			return -EINVAL;
6978c2ecf20Sopenharmony_ci		if (req->ents[i].name_len < 0)
6988c2ecf20Sopenharmony_ci			return -EINVAL;
6998c2ecf20Sopenharmony_ci		if (req->ents[i].name_len > UBI_VOL_NAME_MAX)
7008c2ecf20Sopenharmony_ci			return -ENAMETOOLONG;
7018c2ecf20Sopenharmony_ci		req->ents[i].name[req->ents[i].name_len] = '\0';
7028c2ecf20Sopenharmony_ci		n = strlen(req->ents[i].name);
7038c2ecf20Sopenharmony_ci		if (n != req->ents[i].name_len)
7048c2ecf20Sopenharmony_ci			return -EINVAL;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Make sure volume IDs and names are unique */
7088c2ecf20Sopenharmony_ci	for (i = 0; i < req->count - 1; i++) {
7098c2ecf20Sopenharmony_ci		for (n = i + 1; n < req->count; n++) {
7108c2ecf20Sopenharmony_ci			if (req->ents[i].vol_id == req->ents[n].vol_id) {
7118c2ecf20Sopenharmony_ci				ubi_err(ubi, "duplicated volume id %d",
7128c2ecf20Sopenharmony_ci					req->ents[i].vol_id);
7138c2ecf20Sopenharmony_ci				return -EINVAL;
7148c2ecf20Sopenharmony_ci			}
7158c2ecf20Sopenharmony_ci			if (!strcmp(req->ents[i].name, req->ents[n].name)) {
7168c2ecf20Sopenharmony_ci				ubi_err(ubi, "duplicated volume name \"%s\"",
7178c2ecf20Sopenharmony_ci					req->ents[i].name);
7188c2ecf20Sopenharmony_ci				return -EINVAL;
7198c2ecf20Sopenharmony_ci			}
7208c2ecf20Sopenharmony_ci		}
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/* Create the re-name list */
7248c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rename_list);
7258c2ecf20Sopenharmony_ci	for (i = 0; i < req->count; i++) {
7268c2ecf20Sopenharmony_ci		int vol_id = req->ents[i].vol_id;
7278c2ecf20Sopenharmony_ci		int name_len = req->ents[i].name_len;
7288c2ecf20Sopenharmony_ci		const char *name = req->ents[i].name;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
7318c2ecf20Sopenharmony_ci		if (!re) {
7328c2ecf20Sopenharmony_ci			err = -ENOMEM;
7338c2ecf20Sopenharmony_ci			goto out_free;
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY);
7378c2ecf20Sopenharmony_ci		if (IS_ERR(re->desc)) {
7388c2ecf20Sopenharmony_ci			err = PTR_ERR(re->desc);
7398c2ecf20Sopenharmony_ci			ubi_err(ubi, "cannot open volume %d, error %d",
7408c2ecf20Sopenharmony_ci				vol_id, err);
7418c2ecf20Sopenharmony_ci			kfree(re);
7428c2ecf20Sopenharmony_ci			goto out_free;
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		/* Skip this re-naming if the name does not really change */
7468c2ecf20Sopenharmony_ci		if (re->desc->vol->name_len == name_len &&
7478c2ecf20Sopenharmony_ci		    !memcmp(re->desc->vol->name, name, name_len)) {
7488c2ecf20Sopenharmony_ci			ubi_close_volume(re->desc);
7498c2ecf20Sopenharmony_ci			kfree(re);
7508c2ecf20Sopenharmony_ci			continue;
7518c2ecf20Sopenharmony_ci		}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		re->new_name_len = name_len;
7548c2ecf20Sopenharmony_ci		memcpy(re->new_name, name, name_len);
7558c2ecf20Sopenharmony_ci		list_add_tail(&re->list, &rename_list);
7568c2ecf20Sopenharmony_ci		dbg_gen("will rename volume %d from \"%s\" to \"%s\"",
7578c2ecf20Sopenharmony_ci			vol_id, re->desc->vol->name, name);
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (list_empty(&rename_list))
7618c2ecf20Sopenharmony_ci		return 0;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Find out the volumes which have to be removed */
7648c2ecf20Sopenharmony_ci	list_for_each_entry(re, &rename_list, list) {
7658c2ecf20Sopenharmony_ci		struct ubi_volume_desc *desc;
7668c2ecf20Sopenharmony_ci		int no_remove_needed = 0;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		/*
7698c2ecf20Sopenharmony_ci		 * Volume @re->vol_id is going to be re-named to
7708c2ecf20Sopenharmony_ci		 * @re->new_name, while its current name is @name. If a volume
7718c2ecf20Sopenharmony_ci		 * with name @re->new_name currently exists, it has to be
7728c2ecf20Sopenharmony_ci		 * removed, unless it is also re-named in the request (@req).
7738c2ecf20Sopenharmony_ci		 */
7748c2ecf20Sopenharmony_ci		list_for_each_entry(re1, &rename_list, list) {
7758c2ecf20Sopenharmony_ci			if (re->new_name_len == re1->desc->vol->name_len &&
7768c2ecf20Sopenharmony_ci			    !memcmp(re->new_name, re1->desc->vol->name,
7778c2ecf20Sopenharmony_ci				    re1->desc->vol->name_len)) {
7788c2ecf20Sopenharmony_ci				no_remove_needed = 1;
7798c2ecf20Sopenharmony_ci				break;
7808c2ecf20Sopenharmony_ci			}
7818c2ecf20Sopenharmony_ci		}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		if (no_remove_needed)
7848c2ecf20Sopenharmony_ci			continue;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		/*
7878c2ecf20Sopenharmony_ci		 * It seems we need to remove volume with name @re->new_name,
7888c2ecf20Sopenharmony_ci		 * if it exists.
7898c2ecf20Sopenharmony_ci		 */
7908c2ecf20Sopenharmony_ci		desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name,
7918c2ecf20Sopenharmony_ci					  UBI_EXCLUSIVE);
7928c2ecf20Sopenharmony_ci		if (IS_ERR(desc)) {
7938c2ecf20Sopenharmony_ci			err = PTR_ERR(desc);
7948c2ecf20Sopenharmony_ci			if (err == -ENODEV)
7958c2ecf20Sopenharmony_ci				/* Re-naming into a non-existing volume name */
7968c2ecf20Sopenharmony_ci				continue;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci			/* The volume exists but busy, or an error occurred */
7998c2ecf20Sopenharmony_ci			ubi_err(ubi, "cannot open volume \"%s\", error %d",
8008c2ecf20Sopenharmony_ci				re->new_name, err);
8018c2ecf20Sopenharmony_ci			goto out_free;
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci		re1 = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
8058c2ecf20Sopenharmony_ci		if (!re1) {
8068c2ecf20Sopenharmony_ci			err = -ENOMEM;
8078c2ecf20Sopenharmony_ci			ubi_close_volume(desc);
8088c2ecf20Sopenharmony_ci			goto out_free;
8098c2ecf20Sopenharmony_ci		}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		re1->remove = 1;
8128c2ecf20Sopenharmony_ci		re1->desc = desc;
8138c2ecf20Sopenharmony_ci		list_add(&re1->list, &rename_list);
8148c2ecf20Sopenharmony_ci		dbg_gen("will remove volume %d, name \"%s\"",
8158c2ecf20Sopenharmony_ci			re1->desc->vol->vol_id, re1->desc->vol->name);
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	mutex_lock(&ubi->device_mutex);
8198c2ecf20Sopenharmony_ci	err = ubi_rename_volumes(ubi, &rename_list);
8208c2ecf20Sopenharmony_ci	mutex_unlock(&ubi->device_mutex);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ciout_free:
8238c2ecf20Sopenharmony_ci	list_for_each_entry_safe(re, re1, &rename_list, list) {
8248c2ecf20Sopenharmony_ci		ubi_close_volume(re->desc);
8258c2ecf20Sopenharmony_ci		list_del(&re->list);
8268c2ecf20Sopenharmony_ci		kfree(re);
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci	return err;
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
8328c2ecf20Sopenharmony_ci			   unsigned long arg)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	int err = 0;
8358c2ecf20Sopenharmony_ci	struct ubi_device *ubi;
8368c2ecf20Sopenharmony_ci	struct ubi_volume_desc *desc;
8378c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_RESOURCE))
8408c2ecf20Sopenharmony_ci		return -EPERM;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	ubi = ubi_get_by_major(imajor(file->f_mapping->host));
8438c2ecf20Sopenharmony_ci	if (!ubi)
8448c2ecf20Sopenharmony_ci		return -ENODEV;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	switch (cmd) {
8478c2ecf20Sopenharmony_ci	/* Create volume command */
8488c2ecf20Sopenharmony_ci	case UBI_IOCMKVOL:
8498c2ecf20Sopenharmony_ci	{
8508c2ecf20Sopenharmony_ci		struct ubi_mkvol_req req;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci		dbg_gen("create volume");
8538c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
8548c2ecf20Sopenharmony_ci		if (err) {
8558c2ecf20Sopenharmony_ci			err = -EFAULT;
8568c2ecf20Sopenharmony_ci			break;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		err = verify_mkvol_req(ubi, &req);
8608c2ecf20Sopenharmony_ci		if (err)
8618c2ecf20Sopenharmony_ci			break;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		mutex_lock(&ubi->device_mutex);
8648c2ecf20Sopenharmony_ci		err = ubi_create_volume(ubi, &req);
8658c2ecf20Sopenharmony_ci		mutex_unlock(&ubi->device_mutex);
8668c2ecf20Sopenharmony_ci		if (err)
8678c2ecf20Sopenharmony_ci			break;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		err = put_user(req.vol_id, (__user int32_t *)argp);
8708c2ecf20Sopenharmony_ci		if (err)
8718c2ecf20Sopenharmony_ci			err = -EFAULT;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci		break;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* Remove volume command */
8778c2ecf20Sopenharmony_ci	case UBI_IOCRMVOL:
8788c2ecf20Sopenharmony_ci	{
8798c2ecf20Sopenharmony_ci		int vol_id;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci		dbg_gen("remove volume");
8828c2ecf20Sopenharmony_ci		err = get_user(vol_id, (__user int32_t *)argp);
8838c2ecf20Sopenharmony_ci		if (err) {
8848c2ecf20Sopenharmony_ci			err = -EFAULT;
8858c2ecf20Sopenharmony_ci			break;
8868c2ecf20Sopenharmony_ci		}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci		desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
8898c2ecf20Sopenharmony_ci		if (IS_ERR(desc)) {
8908c2ecf20Sopenharmony_ci			err = PTR_ERR(desc);
8918c2ecf20Sopenharmony_ci			break;
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		mutex_lock(&ubi->device_mutex);
8958c2ecf20Sopenharmony_ci		err = ubi_remove_volume(desc, 0);
8968c2ecf20Sopenharmony_ci		mutex_unlock(&ubi->device_mutex);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		/*
8998c2ecf20Sopenharmony_ci		 * The volume is deleted (unless an error occurred), and the
9008c2ecf20Sopenharmony_ci		 * 'struct ubi_volume' object will be freed when
9018c2ecf20Sopenharmony_ci		 * 'ubi_close_volume()' will call 'put_device()'.
9028c2ecf20Sopenharmony_ci		 */
9038c2ecf20Sopenharmony_ci		ubi_close_volume(desc);
9048c2ecf20Sopenharmony_ci		break;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* Re-size volume command */
9088c2ecf20Sopenharmony_ci	case UBI_IOCRSVOL:
9098c2ecf20Sopenharmony_ci	{
9108c2ecf20Sopenharmony_ci		int pebs;
9118c2ecf20Sopenharmony_ci		struct ubi_rsvol_req req;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci		dbg_gen("re-size volume");
9148c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
9158c2ecf20Sopenharmony_ci		if (err) {
9168c2ecf20Sopenharmony_ci			err = -EFAULT;
9178c2ecf20Sopenharmony_ci			break;
9188c2ecf20Sopenharmony_ci		}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci		err = verify_rsvol_req(ubi, &req);
9218c2ecf20Sopenharmony_ci		if (err)
9228c2ecf20Sopenharmony_ci			break;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci		desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);
9258c2ecf20Sopenharmony_ci		if (IS_ERR(desc)) {
9268c2ecf20Sopenharmony_ci			err = PTR_ERR(desc);
9278c2ecf20Sopenharmony_ci			break;
9288c2ecf20Sopenharmony_ci		}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		pebs = div_u64(req.bytes + desc->vol->usable_leb_size - 1,
9318c2ecf20Sopenharmony_ci			       desc->vol->usable_leb_size);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci		mutex_lock(&ubi->device_mutex);
9348c2ecf20Sopenharmony_ci		err = ubi_resize_volume(desc, pebs);
9358c2ecf20Sopenharmony_ci		mutex_unlock(&ubi->device_mutex);
9368c2ecf20Sopenharmony_ci		ubi_close_volume(desc);
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	/* Re-name volumes command */
9418c2ecf20Sopenharmony_ci	case UBI_IOCRNVOL:
9428c2ecf20Sopenharmony_ci	{
9438c2ecf20Sopenharmony_ci		struct ubi_rnvol_req *req;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci		dbg_gen("re-name volumes");
9468c2ecf20Sopenharmony_ci		req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL);
9478c2ecf20Sopenharmony_ci		if (!req) {
9488c2ecf20Sopenharmony_ci			err = -ENOMEM;
9498c2ecf20Sopenharmony_ci			break;
9508c2ecf20Sopenharmony_ci		}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
9538c2ecf20Sopenharmony_ci		if (err) {
9548c2ecf20Sopenharmony_ci			err = -EFAULT;
9558c2ecf20Sopenharmony_ci			kfree(req);
9568c2ecf20Sopenharmony_ci			break;
9578c2ecf20Sopenharmony_ci		}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		err = rename_volumes(ubi, req);
9608c2ecf20Sopenharmony_ci		kfree(req);
9618c2ecf20Sopenharmony_ci		break;
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	/* Check a specific PEB for bitflips and scrub it if needed */
9658c2ecf20Sopenharmony_ci	case UBI_IOCRPEB:
9668c2ecf20Sopenharmony_ci	{
9678c2ecf20Sopenharmony_ci		int pnum;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		err = get_user(pnum, (__user int32_t *)argp);
9708c2ecf20Sopenharmony_ci		if (err) {
9718c2ecf20Sopenharmony_ci			err = -EFAULT;
9728c2ecf20Sopenharmony_ci			break;
9738c2ecf20Sopenharmony_ci		}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci		err = ubi_bitflip_check(ubi, pnum, 0);
9768c2ecf20Sopenharmony_ci		break;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	/* Force scrubbing for a specific PEB */
9808c2ecf20Sopenharmony_ci	case UBI_IOCSPEB:
9818c2ecf20Sopenharmony_ci	{
9828c2ecf20Sopenharmony_ci		int pnum;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci		err = get_user(pnum, (__user int32_t *)argp);
9858c2ecf20Sopenharmony_ci		if (err) {
9868c2ecf20Sopenharmony_ci			err = -EFAULT;
9878c2ecf20Sopenharmony_ci			break;
9888c2ecf20Sopenharmony_ci		}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		err = ubi_bitflip_check(ubi, pnum, 1);
9918c2ecf20Sopenharmony_ci		break;
9928c2ecf20Sopenharmony_ci	}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	default:
9958c2ecf20Sopenharmony_ci		err = -ENOTTY;
9968c2ecf20Sopenharmony_ci		break;
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	ubi_put_device(ubi);
10008c2ecf20Sopenharmony_ci	return err;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
10048c2ecf20Sopenharmony_ci			    unsigned long arg)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	int err = 0;
10078c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_RESOURCE))
10108c2ecf20Sopenharmony_ci		return -EPERM;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	switch (cmd) {
10138c2ecf20Sopenharmony_ci	/* Attach an MTD device command */
10148c2ecf20Sopenharmony_ci	case UBI_IOCATT:
10158c2ecf20Sopenharmony_ci	{
10168c2ecf20Sopenharmony_ci		struct ubi_attach_req req;
10178c2ecf20Sopenharmony_ci		struct mtd_info *mtd;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		dbg_gen("attach MTD device");
10208c2ecf20Sopenharmony_ci		err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
10218c2ecf20Sopenharmony_ci		if (err) {
10228c2ecf20Sopenharmony_ci			err = -EFAULT;
10238c2ecf20Sopenharmony_ci			break;
10248c2ecf20Sopenharmony_ci		}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci		if (req.mtd_num < 0 ||
10278c2ecf20Sopenharmony_ci		    (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
10288c2ecf20Sopenharmony_ci			err = -EINVAL;
10298c2ecf20Sopenharmony_ci			break;
10308c2ecf20Sopenharmony_ci		}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		mtd = get_mtd_device(NULL, req.mtd_num);
10338c2ecf20Sopenharmony_ci		if (IS_ERR(mtd)) {
10348c2ecf20Sopenharmony_ci			err = PTR_ERR(mtd);
10358c2ecf20Sopenharmony_ci			break;
10368c2ecf20Sopenharmony_ci		}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		/*
10398c2ecf20Sopenharmony_ci		 * Note, further request verification is done by
10408c2ecf20Sopenharmony_ci		 * 'ubi_attach_mtd_dev()'.
10418c2ecf20Sopenharmony_ci		 */
10428c2ecf20Sopenharmony_ci		mutex_lock(&ubi_devices_mutex);
10438c2ecf20Sopenharmony_ci		err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset,
10448c2ecf20Sopenharmony_ci					 req.max_beb_per1024);
10458c2ecf20Sopenharmony_ci		mutex_unlock(&ubi_devices_mutex);
10468c2ecf20Sopenharmony_ci		if (err < 0)
10478c2ecf20Sopenharmony_ci			put_mtd_device(mtd);
10488c2ecf20Sopenharmony_ci		else
10498c2ecf20Sopenharmony_ci			/* @err contains UBI device number */
10508c2ecf20Sopenharmony_ci			err = put_user(err, (__user int32_t *)argp);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		break;
10538c2ecf20Sopenharmony_ci	}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Detach an MTD device command */
10568c2ecf20Sopenharmony_ci	case UBI_IOCDET:
10578c2ecf20Sopenharmony_ci	{
10588c2ecf20Sopenharmony_ci		int ubi_num;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci		dbg_gen("detach MTD device");
10618c2ecf20Sopenharmony_ci		err = get_user(ubi_num, (__user int32_t *)argp);
10628c2ecf20Sopenharmony_ci		if (err) {
10638c2ecf20Sopenharmony_ci			err = -EFAULT;
10648c2ecf20Sopenharmony_ci			break;
10658c2ecf20Sopenharmony_ci		}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		mutex_lock(&ubi_devices_mutex);
10688c2ecf20Sopenharmony_ci		err = ubi_detach_mtd_dev(ubi_num, 0);
10698c2ecf20Sopenharmony_ci		mutex_unlock(&ubi_devices_mutex);
10708c2ecf20Sopenharmony_ci		break;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	default:
10748c2ecf20Sopenharmony_ci		err = -ENOTTY;
10758c2ecf20Sopenharmony_ci		break;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	return err;
10798c2ecf20Sopenharmony_ci}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci/* UBI volume character device operations */
10828c2ecf20Sopenharmony_ciconst struct file_operations ubi_vol_cdev_operations = {
10838c2ecf20Sopenharmony_ci	.owner          = THIS_MODULE,
10848c2ecf20Sopenharmony_ci	.open           = vol_cdev_open,
10858c2ecf20Sopenharmony_ci	.release        = vol_cdev_release,
10868c2ecf20Sopenharmony_ci	.llseek         = vol_cdev_llseek,
10878c2ecf20Sopenharmony_ci	.read           = vol_cdev_read,
10888c2ecf20Sopenharmony_ci	.write          = vol_cdev_write,
10898c2ecf20Sopenharmony_ci	.fsync		= vol_cdev_fsync,
10908c2ecf20Sopenharmony_ci	.unlocked_ioctl = vol_cdev_ioctl,
10918c2ecf20Sopenharmony_ci	.compat_ioctl   = compat_ptr_ioctl,
10928c2ecf20Sopenharmony_ci};
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci/* UBI character device operations */
10958c2ecf20Sopenharmony_ciconst struct file_operations ubi_cdev_operations = {
10968c2ecf20Sopenharmony_ci	.owner          = THIS_MODULE,
10978c2ecf20Sopenharmony_ci	.llseek         = no_llseek,
10988c2ecf20Sopenharmony_ci	.unlocked_ioctl = ubi_cdev_ioctl,
10998c2ecf20Sopenharmony_ci	.compat_ioctl   = compat_ptr_ioctl,
11008c2ecf20Sopenharmony_ci};
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci/* UBI control character device operations */
11038c2ecf20Sopenharmony_ciconst struct file_operations ubi_ctrl_cdev_operations = {
11048c2ecf20Sopenharmony_ci	.owner          = THIS_MODULE,
11058c2ecf20Sopenharmony_ci	.unlocked_ioctl = ctrl_cdev_ioctl,
11068c2ecf20Sopenharmony_ci	.compat_ioctl   = compat_ptr_ioctl,
11078c2ecf20Sopenharmony_ci	.llseek		= no_llseek,
11088c2ecf20Sopenharmony_ci};
1109