int ubi_create_volume()

in ubi/vmt.c [144:328]


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;

	device_initialize(&vol->dev);
	vol->dev.release = vol_release;
	vol->dev.parent = &ubi->dev;
	vol->dev.class = &ubi_class;
	vol->dev.groups = volume_dev_groups;

	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, (unsigned long long)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]->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);

	vol->vol_id    = vol_id;
	vol->alignment = req->alignment;
	vol->data_pad  = ubi->leb_size % vol->alignment;
	vol->vol_type  = req->vol_type;
	vol->name_len  = req->name_len;
	memcpy(vol->name, req->name, vol->name_len);
	vol->ubi = ubi;

	/*
	 * 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;

	eba_tbl = ubi_eba_create_table(vol, vol->reserved_pebs);
	if (IS_ERR(eba_tbl)) {
		err = PTR_ERR(eba_tbl);
		goto out_acc;
	}

	ubi_eba_replace_table(vol, eba_tbl);

	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
		vol->used_ebs = vol->reserved_pebs;
		vol->last_eb_bytes = vol->usable_leb_size;
		vol->used_bytes =
			(long long)vol->used_ebs * vol->usable_leb_size;
	} else {
		vol->used_ebs = div_u64_rem(vol->used_bytes,
					    vol->usable_leb_size,
					    &vol->last_eb_bytes);
		if (vol->last_eb_bytes != 0)
			vol->used_ebs += 1;
		else
			vol->last_eb_bytes = vol->usable_leb_size;
	}

	/* 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;

	vol->dev.devt = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
	err = cdev_device_add(&vol->cdev, &vol->dev);
	if (err) {
		ubi_err(ubi, "cannot add device");
		goto out_mapping;
	}

	/* Fill volume table record */
	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
	vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
	vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
	vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
	vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
		vtbl_rec.vol_type = UBI_VID_DYNAMIC;
	else
		vtbl_rec.vol_type = UBI_VID_STATIC;

	if (vol->skip_check)
		vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG;

	memcpy(vtbl_rec.name, vol->name, vol->name_len);

	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
	if (err)
		goto out_sysfs;

	ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
	self_check_volumes(ubi);
	return err;

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);
	ubi_eba_destroy_table(eba_tbl);
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;
}