static int ubi_volume_continue_write(char *volume, void *buf, size_t size) { int err = 1; struct ubi_volume *vol; vol = ubi_find_volume(volume); if (vol == NULL) return ENODEV; err = ubi_more_update_data(ubi, vol, buf, size); if (err < 0) { printf("Couldnt or partially wrote data\n"); return -err; } if (err) { size = err; err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return -err; if (err) { ubi_warn(ubi, "volume %d on UBI device %d is corrupt", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; ubi_gluebi_updated(vol); } return 0; }
static int ubi_volume_write(char *volume, void *buf, size_t size) { int i = 0, err = -1; int rsvd_bytes = 0; int found = 0; struct ubi_volume *vol; for (i = 0; i < ubi->vtbl_slots; i++) { vol = ubi->volumes[i]; if (vol && !strcmp(vol->name, volume)) { printf("Volume \"%s\" found at volume id %d\n", volume, i); found = 1; break; } } if (!found) { printf("%s volume not found\n", volume); return 1; } rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad); if (size < 0 || size > rsvd_bytes) { printf("rsvd_bytes=%d vol->reserved_pebs=%d ubi->leb_size=%d\n", rsvd_bytes, vol->reserved_pebs, ubi->leb_size); printf("vol->data_pad=%d\n", vol->data_pad); printf("Size > volume size !!\n"); return 1; } err = ubi_start_update(ubi, vol, size); if (err < 0) { printf("Cannot start volume update\n"); return err; } err = ubi_more_update_data(ubi, vol, buf, size); if (err < 0) { printf("Couldnt or partially wrote data \n"); return err; } if (err) { size = 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); } return 0; }
static int ubi_volume_cdev_close(struct cdev *cdev) { struct ubi_volume_cdev_priv *priv = cdev->priv; struct ubi_volume *vol = priv->vol; struct ubi_device *ubi = priv->ubi; int err; if (priv->written) { int remaining = vol->usable_leb_size - (priv->written % vol->usable_leb_size); if (remaining && vol->vol_type == UBI_DYNAMIC_VOLUME) { void *buf = kmalloc(remaining, GFP_KERNEL); if (!buf) return -ENOMEM; memset(buf, 0xff, remaining); err = ubi_more_update_data(ubi, vol, buf, remaining); kfree(buf); if (err < 0) { ubi_err(ubi, "Couldnt or partially wrote data"); return err; } } if (vol->vol_type == UBI_STATIC_VOLUME) cdev->size = priv->written; err = ubi_finish_update(ubi, vol); if (err) return err; err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) { ubi_err(ubi, "ubi volume check failed: %s", strerror(err)); return err; } if (err) { ubi_warn(ubi, "volume %d on UBI device %d is corrupted", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED); } return 0; }
static int ubi_volume_write(char *volume, void *buf, size_t size) { int err = 1; int rsvd_bytes = 0; struct ubi_volume *vol; vol = ubi_find_volume(volume); if (vol == NULL) return ENODEV; rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad); if (size < 0 || size > rsvd_bytes) { printf("size > volume size! Aborting!\n"); return EINVAL; } if (!strncmp(vol->name, "Factory", 7) && (!size || size != rsvd_bytes)) { printf("Partial write to volume %s is inhibited\n", vol->name); return EROFS; } err = ubi_start_update(ubi, vol, size); if (err < 0) { printf("Cannot start volume update\n"); return -err; } err = ubi_more_update_data(ubi, vol, buf, size); if (err < 0) { printf("Couldnt or partially wrote data\n"); return -err; } if (err) { size = 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); } printf("\n0x%x bytes written to volume %s\n", size, volume); return 0; }
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; }
/** * ubi_open_volume - open UBI volume. * @ubi_num: UBI device number * @vol_id: volume ID * @mode: open mode * * The @mode parameter specifies if the volume should be opened in read-only * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that * nobody else will be able to open this volume. UBI allows to have many volume * readers and one writer at a time. * * If a static volume is being opened for the first time since boot, it will be * checked by this function, which means it will be fully read and the CRC * checksum of each logical eraseblock will be checked. * * This function returns volume descriptor in case of success and a negative * error code in case of failure. */ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) { int err; struct ubi_volume_desc *desc; struct ubi_device *ubi; struct ubi_volume *vol; dbg_gen("open device %d, volume %d, mode %d", ubi_num, vol_id, mode); if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) return ERR_PTR(-EINVAL); if (mode != UBI_READONLY && mode != UBI_READWRITE && mode != UBI_EXCLUSIVE) return ERR_PTR(-EINVAL); /* * First of all, we have to get the UBI device to prevent its removal. */ ubi = ubi_get_device(ubi_num); if (!ubi) return ERR_PTR(-ENODEV); if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { err = -EINVAL; goto out_put_ubi; } desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); if (!desc) { err = -ENOMEM; goto out_put_ubi; } err = -ENODEV; if (!try_module_get(THIS_MODULE)) goto out_free; spin_lock(&ubi->volumes_lock); vol = ubi->volumes[vol_id]; if (!vol) goto out_unlock; err = -EBUSY; switch (mode) { case UBI_READONLY: if (vol->exclusive) goto out_unlock; vol->readers += 1; break; case UBI_READWRITE: if (vol->exclusive || vol->writers > 0) goto out_unlock; vol->writers += 1; break; case UBI_EXCLUSIVE: if (vol->exclusive || vol->writers || vol->readers) goto out_unlock; vol->exclusive = 1; break; } get_device(&vol->dev); vol->ref_count += 1; spin_unlock(&ubi->volumes_lock); desc->vol = vol; desc->mode = mode; mutex_lock(&ubi->ckvol_mutex); if (!vol->checked) { /* This is the first open - check the volume */ err = ubi_check_volume(ubi, vol_id); if (err < 0) { mutex_unlock(&ubi->ckvol_mutex); ubi_close_volume(desc); return ERR_PTR(err); } if (err == 1) { ubi_warn("volume %d on UBI device %d is corrupted", vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; } mutex_unlock(&ubi->ckvol_mutex); return desc; out_unlock: spin_unlock(&ubi->volumes_lock); module_put(THIS_MODULE); out_free: kfree(desc); out_put_ubi: ubi_put_device(ubi); dbg_err("cannot open device %d, volume %d, error %d", ubi_num, vol_id, err); return ERR_PTR(err); }
/** * ubi_open_volume - open UBI volume. * @ubi_num: UBI device number * @vol_id: volume ID * @mode: open mode * * The @mode parameter specifies if the volume should be opened in read-only * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that * nobody else will be able to open this volume. UBI allows to have many volume * readers and one writer at a time. * * If a static volume is being opened for the first time since boot, it will be * checked by this function, which means it will be fully read and the CRC * checksum of each logical eraseblock will be checked. * * This function returns volume descriptor in case of success and a negative * error code in case of failure. */ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) { int err; struct ubi_volume_desc *desc; struct ubi_device *ubi = ubi_devices[ubi_num]; struct ubi_volume *vol; dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); err = -ENODEV; if (!try_module_get(THIS_MODULE)) return ERR_PTR(err); if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi) goto out_put; err = -EINVAL; if (vol_id < 0 || vol_id >= ubi->vtbl_slots) goto out_put; if (mode != UBI_READONLY && mode != UBI_READWRITE && mode != UBI_EXCLUSIVE) goto out_put; desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); if (!desc) { err = -ENOMEM; goto out_put; } spin_lock(&ubi->volumes_lock); vol = ubi->volumes[vol_id]; if (!vol) { err = -ENODEV; goto out_unlock; } err = -EBUSY; switch (mode) { case UBI_READONLY: if (vol->exclusive) goto out_unlock; vol->readers += 1; break; case UBI_READWRITE: if (vol->exclusive || vol->writers > 0) goto out_unlock; vol->writers += 1; break; case UBI_EXCLUSIVE: if (vol->exclusive || vol->writers || vol->readers) goto out_unlock; vol->exclusive = 1; break; } spin_unlock(&ubi->volumes_lock); desc->vol = vol; desc->mode = mode; /* * To prevent simultaneous checks of the same volume we use @vtbl_mutex, * although it is not the purpose it was introduced for. */ mutex_lock(&ubi->vtbl_mutex); if (!vol->checked) { /* This is the first open - check the volume */ err = ubi_check_volume(ubi, vol_id); if (err < 0) { mutex_unlock(&ubi->vtbl_mutex); ubi_close_volume(desc); return ERR_PTR(err); } if (err == 1) { ubi_warn("volume %d on UBI device %d is corrupted", vol_id, ubi->ubi_num); vol->corrupted = 1; } vol->checked = 1; } mutex_unlock(&ubi->vtbl_mutex); return desc; out_unlock: spin_unlock(&ubi->volumes_lock); kfree(desc); out_put: module_put(THIS_MODULE); return ERR_PTR(err); }