/** * autoresize - re-size the volume which has the "auto-resize" flag set. * @ubi: UBI device description object * @vol_id: ID of the volume to re-size * * This function re-sizes the volume marked by the %UBI_VTBL_AUTORESIZE_FLG in * the volume table to the largest possible size. See comments in ubi-header.h * for more description of the flag. Returns zero in case of success and a * negative error code in case of failure. */ static int autoresize(struct ubi_device *ubi, int vol_id) { struct ubi_volume_desc desc; struct ubi_volume *vol = ubi->volumes[vol_id]; int err, old_reserved_pebs = vol->reserved_pebs; if (ubi->ro_mode) { ubi_warn("skip auto-resize because of R/O mode"); return 0; } /* * Clear the auto-resize flag in the volume in-memory copy of the * volume table, and 'ubi_resize_volume()' will propagate this change * to the flash. */ ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; if (ubi->avail_pebs == 0) { struct ubi_vtbl_record vtbl_rec; /* * No available PEBs to re-size the volume, clear the flag on * flash and exit. */ vtbl_rec = ubi->vtbl[vol_id]; err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) ubi_err("cannot clean auto-resize flag for volume %d", vol_id); } else { desc.vol = vol; err = ubi_resize_volume(&desc, old_reserved_pebs + ubi->avail_pebs); if (err) ubi_err("cannot auto-resize volume %d", vol_id); } if (err) return err; ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, vol->name, old_reserved_pebs, vol->reserved_pebs); return 0; }
static int ubi_cdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ubi_device *ubi; struct ubi_volume_desc *desc; void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_RESOURCE)) return -EPERM; ubi = ubi_get_by_major(imajor(inode)); if (!ubi) return -ENODEV; switch (cmd) { /* Create volume command */ case UBI_IOCMKVOL: { struct ubi_mkvol_req req; dbg_msg("create volume"); err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); if (err) { err = -EFAULT; break; } err = verify_mkvol_req(ubi, &req); if (err) break; req.name[req.name_len] = '\0'; mutex_lock(&ubi->volumes_mutex); err = ubi_create_volume(ubi, &req); mutex_unlock(&ubi->volumes_mutex); if (err) break; err = put_user(req.vol_id, (__user int32_t *)argp); if (err) err = -EFAULT; break; } /* Remove volume command */ case UBI_IOCRMVOL: { int vol_id; dbg_msg("remove volume"); err = get_user(vol_id, (__user int32_t *)argp); if (err) { err = -EFAULT; break; } desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE); if (IS_ERR(desc)) { err = PTR_ERR(desc); break; } mutex_lock(&ubi->volumes_mutex); err = ubi_remove_volume(desc); mutex_unlock(&ubi->volumes_mutex); /* * The volume is deleted (unless an error occurred), and the * 'struct ubi_volume' object will be freed when * 'ubi_close_volume()' will call 'put_device()'. */ ubi_close_volume(desc); break; } /* Re-size volume command */ case UBI_IOCRSVOL: { int pebs; uint64_t tmp; struct ubi_rsvol_req req; dbg_msg("re-size volume"); err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); if (err) { err = -EFAULT; break; } err = verify_rsvol_req(ubi, &req); if (err) break; desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE); if (IS_ERR(desc)) { err = PTR_ERR(desc); break; } tmp = req.bytes; pebs = !!do_div(tmp, desc->vol->usable_leb_size); pebs += tmp; mutex_lock(&ubi->volumes_mutex); err = ubi_resize_volume(desc, pebs); mutex_unlock(&ubi->volumes_mutex); ubi_close_volume(desc); break; } default: err = -ENOTTY; break; } ubi_put_device(ubi); return err; }
static int ubi_cdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ubi_device *ubi; struct ubi_volume_desc *desc; void __user *argp = (void __user *)arg; if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ || _IOC_TYPE(cmd) != UBI_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; if (!capable(CAP_SYS_RESOURCE)) return -EPERM; ubi = major_to_device(imajor(inode)); if (IS_ERR(ubi)) return PTR_ERR(ubi); switch (cmd) { /* Create volume command */ case UBI_IOCMKVOL: { struct ubi_mkvol_req req; dbg_msg("create volume"); err = __copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); if (err) { err = -EFAULT; break; } err = verify_mkvol_req(ubi, &req); if (err) break; req.name[req.name_len] = '\0'; err = ubi_create_volume(ubi, &req); if (err) break; err = __put_user(req.vol_id, (__user int32_t *)argp); if (err) err = -EFAULT; break; } /* Remove volume command */ case UBI_IOCRMVOL: { int vol_id; dbg_msg("remove volume"); err = __get_user(vol_id, (__user int32_t *)argp); if (err) { err = -EFAULT; break; } desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE); if (IS_ERR(desc)) { err = PTR_ERR(desc); break; } err = ubi_remove_volume(desc); if (err) ubi_close_volume(desc); break; } /* Re-size volume command */ case UBI_IOCRSVOL: { int pebs; uint64_t tmp; struct ubi_rsvol_req req; dbg_msg("re-size volume"); err = __copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); if (err) { err = -EFAULT; break; } err = verify_rsvol_req(ubi, &req); if (err) break; desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE); if (IS_ERR(desc)) { err = PTR_ERR(desc); break; } tmp = req.bytes; pebs = !!do_div(tmp, desc->vol->usable_leb_size); pebs += tmp; err = ubi_resize_volume(desc, pebs); ubi_close_volume(desc); break; } default: err = -ENOTTY; break; } return err; }