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