/* * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'. * * Consider a situation: * A. process 1 opens a sysfs file related to volume Y, say * /<sysfs>/class/ubi/ubiX_Y/reserved_ebs; * B. process 2 removes volume Y; * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file; * * In this situation, this function will return %-ENODEV because it will find * out that the volume was removed from the @ubi->volumes array.
*/ static ssize_t vol_attribute_show(struct device *dev, struct device_attribute *attr, char *buf)
{ int ret; struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); struct ubi_device *ubi = vol->ubi;
spin_lock(&ubi->volumes_lock); if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
spin_unlock(&ubi->volumes_lock); return -ENODEV;
} /* Take a reference to prevent volume removal */
vol->ref_count += 1;
spin_unlock(&ubi->volumes_lock);
if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs); elseif (attr == &attr_vol_type) { constchar *tp;
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
tp = "dynamic"; else
tp = "static";
ret = sprintf(buf, "%s\n", tp);
} elseif (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name); elseif (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted); elseif (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment); elseif (attr == &attr_vol_usable_eb_size)
ret = sprintf(buf, "%d\n", vol->usable_leb_size); elseif (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes); elseif (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker); else /* This must be a bug */
ret = -EINVAL;
/* We've done the operation, drop volume and UBI device references */
spin_lock(&ubi->volumes_lock);
vol->ref_count -= 1;
ubi_assert(vol->ref_count >= 0);
spin_unlock(&ubi->volumes_lock); return ret;
}
/** * ubi_create_volume - create volume. * @ubi: UBI device description object * @req: volume creation request * * This function creates volume described by @req. If @req->vol_id id * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume * and saves it in @req->vol_id. Returns zero in case of success and a negative * error code in case of failure. Note, the caller has to have the * @ubi->device_mutex locked.
*/ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
{ int i, err, vol_id = req->vol_id; struct ubi_volume *vol; struct ubi_vtbl_record vtbl_rec; struct ubi_eba_table *eba_tbl = NULL;
if (ubi->ro_mode) return -EROFS;
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); if (!vol) return -ENOMEM;
if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG)
vol->skip_check = 1;
spin_lock(&ubi->volumes_lock); if (vol_id == UBI_VOL_NUM_AUTO) { /* Find unused volume ID */
dbg_gen("search for vacant volume ID"); for (i = 0; i < ubi->vtbl_slots; i++) if (!ubi->volumes[i]) {
vol_id = i; break;
}
if (vol_id == UBI_VOL_NUM_AUTO) {
ubi_err(ubi, "out of volume IDs");
err = -ENFILE; goto out_unlock;
}
req->vol_id = vol_id;
}
dbg_gen("create device %d, volume %d, %llu bytes, type %d, name %s",
ubi->ubi_num, vol_id, (unsignedlonglong)req->bytes,
(int)req->vol_type, req->name);
/* Ensure that this volume does not exist */
err = -EEXIST; if (ubi->volumes[vol_id]) {
ubi_err(ubi, "volume %d already exists", vol_id); goto out_unlock;
}
/* Ensure that the name is unique */ for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
ubi->volumes[i]->name_len == req->name_len &&
!strcmp(ubi->volumes[i]->name, req->name)) {
ubi_err(ubi, "volume \"%s\" exists (ID %d)",
req->name, i); goto out_unlock;
}
/* Calculate how many eraseblocks are requested */
vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
vol->reserved_pebs = div_u64(req->bytes + vol->usable_leb_size - 1,
vol->usable_leb_size);
/* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) {
ubi_err(ubi, "not enough PEBs, only %d available",
ubi->avail_pebs); if (ubi->corr_peb_count)
ubi_err(ubi, "%d PEBs are corrupted and not used",
ubi->corr_peb_count);
err = -ENOSPC; goto out_unlock;
}
ubi->avail_pebs -= vol->reserved_pebs;
ubi->rsvd_pebs += vol->reserved_pebs;
spin_unlock(&ubi->volumes_lock);
/* * Finish all pending erases because there may be some LEBs belonging * to the same volume ID.
*/
err = ubi_wl_flush(ubi, vol_id, UBI_ALL); if (err) goto out_acc;
/* Make volume "available" before it becomes accessible via sysfs */
spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = vol;
ubi->vol_count += 1;
spin_unlock(&ubi->volumes_lock);
/* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
vol->cdev.owner = THIS_MODULE;
out_sysfs: /* * We have registered our device, we should not free the volume * description object in this function in case of an error - it is * freed by the release function.
*/
cdev_device_del(&vol->cdev, &vol->dev);
out_mapping:
spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = NULL;
ubi->vol_count -= 1;
spin_unlock(&ubi->volumes_lock);
out_acc:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
out_unlock:
spin_unlock(&ubi->volumes_lock);
put_device(&vol->dev);
ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err); return err;
}
/** * ubi_remove_volume - remove volume. * @desc: volume descriptor * @no_vtbl: do not change volume table if not zero * * This function removes volume described by @desc. The volume has to be opened * in "exclusive" mode. Returns zero in case of success and a negative error * code in case of failure. The caller has to have the @ubi->device_mutex * locked.
*/ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
{ struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
spin_lock(&ubi->volumes_lock); if (vol->ref_count > 1) { /* * The volume is busy, probably someone is reading one of its * sysfs files.
*/
err = -EBUSY; goto out_unlock;
}
/* * Mark volume as dead at this point to prevent that anyone * can take a reference to the volume from now on. * This is necessary as we have to release the spinlock before * calling ubi_volume_notify.
*/
vol->is_dead = true;
spin_unlock(&ubi->volumes_lock);
/** * ubi_resize_volume - re-size volume. * @desc: volume descriptor * @reserved_pebs: new size in physical eraseblocks * * This function re-sizes the volume and returns zero in case of success, and a * negative error code in case of failure. The caller has to have the * @ubi->device_mutex locked.
*/ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
{ int i, err, pebs; struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; struct ubi_vtbl_record vtbl_rec; struct ubi_eba_table *new_eba_tbl = NULL; struct ubi_eba_table *old_eba_tbl = NULL; int vol_id = vol->vol_id;
if (ubi->ro_mode) return -EROFS;
dbg_gen("re-size device %d, volume %d to from %d to %d PEBs",
ubi->ubi_num, vol_id, vol->reserved_pebs, reserved_pebs);
if (pebs < 0) { for (i = 0; i < -pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); if (err) goto out_free;
}
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs += pebs;
ubi->avail_pebs -= pebs;
ubi_update_reserved(ubi);
ubi_eba_copy_table(vol, new_eba_tbl, reserved_pebs);
old_eba_tbl = vol->eba_tbl;
vol->eba_tbl = new_eba_tbl;
vol->reserved_pebs = reserved_pebs;
spin_unlock(&ubi->volumes_lock);
}
/* * When we shrink a volume we have to flush all pending (erase) work. * Otherwise it can happen that upon next attach UBI finds a LEB with * lnum > highest_lnum and refuses to attach.
*/ if (pebs < 0) {
err = ubi_wl_flush(ubi, vol_id, UBI_ALL); if (err) goto out_acc;
}
/** * ubi_rename_volumes - re-name UBI volumes. * @ubi: UBI device description object * @rename_list: list of &struct ubi_rename_entry objects * * This function re-names or removes volumes specified in the re-name list. * Returns zero in case of success and a negative error code in case of * failure.
*/ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
{ int err; struct ubi_rename_entry *re;
err = ubi_vtbl_rename_volumes(ubi, rename_list); if (err) return err;
/** * ubi_add_volume - add volume. * @ubi: UBI device description object * @vol: volume description object * * This function adds an existing volume and initializes all its data * structures. Returns zero in case of success and a negative error code in * case of failure.
*/ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
{ int err, vol_id = vol->vol_id;
dev_t dev;
dbg_gen("add volume %d", vol_id);
/* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
vol->cdev.owner = THIS_MODULE;
dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
err = cdev_add(&vol->cdev, dev, 1); if (err) {
ubi_err(ubi, "cannot add character device for volume %d, error %d",
vol_id, err);
vol_release(&vol->dev); return err;
}
/** * ubi_free_volume - free volume. * @ubi: UBI device description object * @vol: volume description object * * This function frees all resources for volume @vol but does not remove it. * Used only when the UBI device is detached.
*/ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
{
dbg_gen("free volume %d", vol->vol_id);
/** * self_check_volume - check volume information. * @ubi: UBI device description object * @vol_id: volume ID * * Returns zero if volume is all right and a negative error code if not.
*/ staticint self_check_volume(struct ubi_device *ubi, int vol_id)
{ int idx = vol_id2idx(ubi, vol_id); int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; conststruct ubi_volume *vol; longlong n; constchar *name;
if (vol->upd_marker && vol->corrupted) {
ubi_err(ubi, "update marker and corrupted simultaneously"); goto fail;
}
if (vol->reserved_pebs > ubi->good_peb_count) {
ubi_err(ubi, "too large reserved_pebs"); goto fail;
}
n = ubi->leb_size - vol->data_pad; if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
ubi_err(ubi, "bad usable_leb_size, has to be %lld", n); goto fail;
}
if (vol->name_len > UBI_VOL_NAME_MAX) {
ubi_err(ubi, "too long volume name, max is %d",
UBI_VOL_NAME_MAX); goto fail;
}
n = strnlen(vol->name, vol->name_len + 1); if (n != vol->name_len) {
ubi_err(ubi, "bad name_len %lld", n); goto fail;
}
n = (longlong)vol->used_ebs * vol->usable_leb_size; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->corrupted) {
ubi_err(ubi, "corrupted dynamic volume"); goto fail;
} if (vol->used_ebs != vol->reserved_pebs) {
ubi_err(ubi, "bad used_ebs"); goto fail;
} if (vol->last_eb_bytes != vol->usable_leb_size) {
ubi_err(ubi, "bad last_eb_bytes"); goto fail;
} if (vol->used_bytes != n) {
ubi_err(ubi, "bad used_bytes"); goto fail;
}
fail:
ubi_err(ubi, "self-check failed for volume %d", vol_id); if (vol)
ubi_dump_vol_info(vol);
ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
dump_stack();
spin_unlock(&ubi->volumes_lock); return -EINVAL;
}
/** * self_check_volumes - check information about all volumes. * @ubi: UBI device description object * * Returns zero if volumes are all right and a negative error code if not.
*/ staticint self_check_volumes(struct ubi_device *ubi)
{ int i, err = 0;
if (!ubi_dbg_chk_gen(ubi)) return 0;
for (i = 0; i < ubi->vtbl_slots; i++) {
err = self_check_volume(ubi, i); if (err) break;
}
return err;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.