static ssize_t vol_cdev_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) { int err = 0; struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; if (!vol->updating && !vol->changing_leb) return vol_cdev_direct_write(file, buf, count, offp); if (vol->updating) err = ubi_more_update_data(ubi, vol, buf, count); else err = ubi_more_leb_change_data(ubi, vol, buf, count); if (err < 0) { ubi_err("cannot accept more %zd bytes of data, error %d", count, err); return err; } if (err) { /* * The operation is finished, @err contains number of actually * written bytes. */ count = err; if (vol->changing_leb) { revoke_exclusive(desc, UBI_READWRITE); return count; } err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; if (err) { ubi_warn("volume %d on UBI device %d is corrupted", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; ubi_gluebi_updated(vol); revoke_exclusive(desc, UBI_READWRITE); } return count; }
static ssize_t vol_cdev_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) { int err = 0; struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; if (!vol->updating) return vol_cdev_direct_write(file, buf, count, offp); err = ubi_more_update_data(ubi, vol->vol_id, buf, count); if (err < 0) { ubi_err("cannot write %zd bytes of update data", count); return err; } if (err) { /* * Update is finished, @err contains number of actually written * bytes now. */ count = err; err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; if (err) { ubi_warn("volume %d on UBI device %d is corrupted", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; ubi_gluebi_updated(vol); revoke_exclusive(desc, UBI_READWRITE); } *offp += count; return count; }
static int vol_cdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; void __user *argp = (void __user *)arg; switch (cmd) { /* Volume update command */ case UBI_IOCVOLUP: { int64_t bytes, rsvd_bytes; if (!capable(CAP_SYS_RESOURCE)) { err = -EPERM; break; } err = copy_from_user(&bytes, argp, sizeof(int64_t)); if (err) { err = -EFAULT; break; } if (desc->mode == UBI_READONLY) { err = -EROFS; break; } rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad); if (bytes < 0 || bytes > rsvd_bytes) { err = -EINVAL; break; } err = get_exclusive(desc); if (err < 0) break; err = ubi_start_update(ubi, vol, bytes); if (bytes == 0) revoke_exclusive(desc, UBI_READWRITE); break; } /* Atomic logical eraseblock change command */ case UBI_IOCEBCH: { struct ubi_leb_change_req req; err = copy_from_user(&req, argp, sizeof(struct ubi_leb_change_req)); if (err) { err = -EFAULT; break; } if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) { err = -EROFS; break; } /* Validate the request */ err = -EINVAL; if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || req.bytes < 0 || req.lnum >= vol->usable_leb_size) break; if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM && req.dtype != UBI_UNKNOWN) break; err = get_exclusive(desc); if (err < 0) break; err = ubi_start_leb_change(ubi, vol, &req); if (req.bytes == 0) revoke_exclusive(desc, UBI_READWRITE); break; } #ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO /* Logical eraseblock erasure command */ case UBI_IOCEBER: { int32_t lnum; err = get_user(lnum, (__user int32_t *)argp); if (err) { err = -EFAULT; break; } if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) { err = -EROFS; break; } if (lnum < 0 || lnum >= vol->reserved_pebs) { err = -EINVAL; break; } dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); err = ubi_eba_unmap_leb(ubi, vol, lnum); if (err) break; err = ubi_wl_flush(ubi); break; } #endif default: err = -ENOTTY; break; } return err; }
static int vol_cdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; void __user *argp = (void __user *)arg; if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ || _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC) return -ENOTTY; if (_IOC_DIR(cmd) && _IOC_READ) err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) && _IOC_WRITE) err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch (cmd) { /* Volume update command */ case UBI_IOCVOLUP: { int64_t bytes, rsvd_bytes; if (!capable(CAP_SYS_RESOURCE)) { err = -EPERM; break; } err = copy_from_user(&bytes, argp, sizeof(int64_t)); if (err) { err = -EFAULT; break; } if (desc->mode == UBI_READONLY) { err = -EROFS; break; } rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad); if (bytes < 0 || bytes > rsvd_bytes) { err = -EINVAL; break; } err = get_exclusive(desc); if (err < 0) break; err = ubi_start_update(ubi, vol->vol_id, bytes); if (bytes == 0) revoke_exclusive(desc, UBI_READWRITE); file->f_pos = 0; break; } #ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO /* Logical eraseblock erasure command */ case UBI_IOCEBER: { int32_t lnum; err = __get_user(lnum, (__user int32_t *)argp); if (err) { err = -EFAULT; break; } if (desc->mode == UBI_READONLY) { err = -EROFS; break; } if (lnum < 0 || lnum >= vol->reserved_pebs) { err = -EINVAL; break; } if (vol->vol_type != UBI_DYNAMIC_VOLUME) { err = -EROFS; break; } dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum); if (err) break; err = ubi_wl_flush(ubi); break; } #endif default: err = -ENOTTY; break; } return err; }