Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6208e77e authored by David Woodhouse's avatar David Woodhouse
Browse files
parents 5eb91034 6dc4a871
Loading
Loading
Loading
Loading
+68 −35
Original line number Diff line number Diff line
@@ -66,9 +66,6 @@ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class;

/* Slab cache for lock-tree entries */
struct kmem_cache *ubi_ltree_slab;

/* Slab cache for wear-leveling entries */
struct kmem_cache *ubi_wl_entry_slab;

@@ -369,9 +366,6 @@ static int uif_init(struct ubi_device *ubi)
	int i, err;
	dev_t dev;

	mutex_init(&ubi->volumes_mutex);
	spin_lock_init(&ubi->volumes_lock);

	sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);

	/*
@@ -568,7 +562,7 @@ static int io_init(struct ubi_device *ubi)
	}

	/* Similar for the data offset */
	ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
	ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
	ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);

	dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
@@ -626,6 +620,58 @@ static int io_init(struct ubi_device *ubi)
	return 0;
}

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

	/*
	 * Clear the auto-resize flag in the volume in-memory copy of the
	 * volume table, and 'ubi_resize_volume()' will propogate 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 avalilable PEBs to re-size the volume, clear the flag on
		 * flash and exit.
		 */
		memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
		       sizeof(struct ubi_vtbl_record));
		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;
}

/**
 * ubi_attach_mtd_dev - attach an MTD device.
 * @mtd_dev: MTD device description object
@@ -702,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
	ubi->mtd = mtd;
	ubi->ubi_num = ubi_num;
	ubi->vid_hdr_offset = vid_hdr_offset;
	ubi->autoresize_vol_id = -1;

	mutex_init(&ubi->buf_mutex);
	mutex_init(&ubi->ckvol_mutex);
	mutex_init(&ubi->volumes_mutex);
	spin_lock_init(&ubi->volumes_lock);

	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
		mtd->index, ubi_num, vid_hdr_offset);
@@ -710,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
	if (err)
		goto out_free;

	mutex_init(&ubi->buf_mutex);
	mutex_init(&ubi->ckvol_mutex);
	ubi->peb_buf1 = vmalloc(ubi->peb_size);
	if (!ubi->peb_buf1)
		goto out_free;
@@ -733,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
		goto out_free;
	}

	if (ubi->autoresize_vol_id != -1) {
		err = autoresize(ubi, ubi->autoresize_vol_id);
		if (err)
			goto out_detach;
	}

	err = uif_init(ubi);
	if (err)
		goto out_detach;
@@ -857,20 +913,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
	return 0;
}

/**
 * ltree_entry_ctor - lock tree entries slab cache constructor.
 * @obj: the lock-tree entry to construct
 * @cache: the lock tree entry slab cache
 * @flags: constructor flags
 */
static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
{
	struct ubi_ltree_entry *le = obj;

	le->users = 0;
	init_rwsem(&le->mutex);
}

/**
 * find_mtd_device - open an MTD device by its name or number.
 * @mtd_dev: name or number of the device
@@ -933,17 +975,11 @@ static int __init ubi_init(void)
		goto out_version;
	}

	ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab",
					   sizeof(struct ubi_ltree_entry), 0,
					   0, &ltree_entry_ctor);
	if (!ubi_ltree_slab)
		goto out_dev_unreg;

	ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
						sizeof(struct ubi_wl_entry),
						0, 0, NULL);
	if (!ubi_wl_entry_slab)
		goto out_ltree;
		goto out_dev_unreg;

	/* Attach MTD devices */
	for (i = 0; i < mtd_devs; i++) {
@@ -980,8 +1016,6 @@ out_detach:
			mutex_unlock(&ubi_devices_mutex);
		}
	kmem_cache_destroy(ubi_wl_entry_slab);
out_ltree:
	kmem_cache_destroy(ubi_ltree_slab);
out_dev_unreg:
	misc_deregister(&ubi_ctrl_cdev);
out_version:
@@ -1005,7 +1039,6 @@ static void __exit ubi_exit(void)
			mutex_unlock(&ubi_devices_mutex);
		}
	kmem_cache_destroy(ubi_wl_entry_slab);
	kmem_cache_destroy(ubi_ltree_slab);
	misc_deregister(&ubi_ctrl_cdev);
	class_remove_file(ubi_class, &ubi_version);
	class_destroy(ubi_class);
@@ -1066,7 +1099,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
	struct mtd_dev_param *p;
	char buf[MTD_PARAM_LEN_MAX];
	char *pbuf = &buf[0];
	char *tokens[3] = {NULL, NULL, NULL};
	char *tokens[2] = {NULL, NULL};

	if (!val)
		return -EINVAL;
@@ -1096,7 +1129,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
	if (buf[len - 1] == '\n')
		buf[len - 1] = '\0';

	for (i = 0; i < 3; i++)
	for (i = 0; i < 2; i++)
		tokens[i] = strsep(&pbuf, ",");

	if (pbuf) {
+64 −18
Original line number Diff line number Diff line
@@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
	if (vol->updating) {
		ubi_warn("update of volume %d not finished, volume is damaged",
			 vol->vol_id);
		ubi_assert(!vol->changing_leb);
		vol->updating = 0;
		vfree(vol->upd_buf);
	} else if (vol->changing_leb) {
		dbg_msg("only %lld of %lld bytes received for atomic LEB change"
			" for volume %d:%d, cancel", vol->upd_received,
			vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
		vol->changing_leb = 0;
		vfree(vol->upd_buf);
	}

	ubi_close_volume(desc);
@@ -184,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
	struct ubi_volume_desc *desc = file->private_data;
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	int err, lnum, off, len,  vol_id = desc->vol->vol_id, tbuf_size;
	int err, lnum, off, len,  tbuf_size;
	size_t count_save = count;
	void *tbuf;
	uint64_t tmp;

	dbg_msg("read %zd bytes from offset %lld of volume %d",
		count, *offp, vol_id);
		count, *offp, vol->vol_id);

	if (vol->updating) {
		dbg_err("updating");
@@ -204,7 +211,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
		return 0;

	if (vol->corrupted)
		dbg_msg("read from corrupted volume %d", vol_id);
		dbg_msg("read from corrupted volume %d", vol->vol_id);

	if (*offp + count > vol->used_bytes)
		count_save = count = vol->used_bytes - *offp;
@@ -274,7 +281,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
	uint64_t tmp;

	dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
		count, *offp, desc->vol->vol_id);
		count, *offp, vol->vol_id);

	if (vol->vol_type == UBI_STATIC_VOLUME)
		return -EROFS;
@@ -351,23 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;

	if (!vol->updating)
	if (!vol->updating && !vol->changing_leb)
		return vol_cdev_direct_write(file, buf, count, offp);

	err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
	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 write %zd bytes of update data, error %d",
		ubi_err("cannot accept more %zd bytes of data, error %d",
			count, err);
		return err;
	}

	if (err) {
		/*
		 * Update is finished, @err contains number of actually written
		 * bytes now.
		 * 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;
@@ -382,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
		revoke_exclusive(desc, UBI_READWRITE);
	}

	*offp += count;
	return count;
}

@@ -427,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
		if (err < 0)
			break;

		err = ubi_start_update(ubi, vol->vol_id, bytes);
		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;
		}

		file->f_pos = 0;
		/* 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;
	}

@@ -447,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
			break;
		}

		if (desc->mode == UBI_READONLY) {
		if (desc->mode == UBI_READONLY ||
		    vol->vol_type == UBI_STATIC_VOLUME) {
			err = -EROFS;
			break;
		}
@@ -457,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
			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, lnum);
		if (err)
+19 −21
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ static unsigned long long next_sqnum(struct ubi_device *ubi)
 */
static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
{
	if (vol_id == UBI_LAYOUT_VOL_ID)
	if (vol_id == UBI_LAYOUT_VOLUME_ID)
		return UBI_LAYOUT_VOLUME_COMPAT;
	return 0;
}
@@ -137,10 +137,12 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
{
	struct ubi_ltree_entry *le, *le1, *le_free;

	le = kmem_cache_alloc(ubi_ltree_slab, GFP_NOFS);
	le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS);
	if (!le)
		return ERR_PTR(-ENOMEM);

	le->users = 0;
	init_rwsem(&le->mutex);
	le->vol_id = vol_id;
	le->lnum = lnum;

@@ -188,7 +190,7 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
	spin_unlock(&ubi->ltree_lock);

	if (le_free)
		kmem_cache_free(ubi_ltree_slab, le_free);
		kfree(le_free);

	return le;
}
@@ -236,7 +238,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)

	up_read(&le->mutex);
	if (free)
		kmem_cache_free(ubi_ltree_slab, le);
		kfree(le);
}

/**
@@ -292,7 +294,7 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
		free = 0;
	spin_unlock(&ubi->ltree_lock);
	if (free)
		kmem_cache_free(ubi_ltree_slab, le);
		kfree(le);

	return 1;
}
@@ -321,7 +323,7 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)

	up_write(&le->mutex);
	if (free)
		kmem_cache_free(ubi_ltree_slab, le);
		kfree(le);
}

/**
@@ -339,9 +341,6 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
{
	int err, pnum, vol_id = vol->vol_id;

	ubi_assert(ubi->ref_count > 0);
	ubi_assert(vol->ref_count > 0);

	if (ubi->ro_mode)
		return -EROFS;

@@ -390,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
	struct ubi_vid_hdr *vid_hdr;
	uint32_t uninitialized_var(crc);

	ubi_assert(ubi->ref_count > 0);
	ubi_assert(vol->ref_count > 0);

	err = leb_read_lock(ubi, vol_id, lnum);
	if (err)
		return err;
@@ -616,9 +612,6 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
	int err, pnum, tries = 0, vol_id = vol->vol_id;
	struct ubi_vid_hdr *vid_hdr;

	ubi_assert(ubi->ref_count > 0);
	ubi_assert(vol->ref_count > 0);

	if (ubi->ro_mode)
		return -EROFS;

@@ -752,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
	struct ubi_vid_hdr *vid_hdr;
	uint32_t crc;

	ubi_assert(ubi->ref_count > 0);
	ubi_assert(vol->ref_count > 0);

	if (ubi->ro_mode)
		return -EROFS;

@@ -869,12 +859,20 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
	struct ubi_vid_hdr *vid_hdr;
	uint32_t crc;

	ubi_assert(ubi->ref_count > 0);
	ubi_assert(vol->ref_count > 0);

	if (ubi->ro_mode)
		return -EROFS;

	if (len == 0) {
		/*
		 * Special case when data length is zero. In this case the LEB
		 * has to be unmapped and mapped somewhere else.
		 */
		err = ubi_eba_unmap_leb(ubi, vol, lnum);
		if (err)
			return err;
		return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
	}

	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
	if (!vid_hdr)
		return -ENOMEM;
+4 −6
Original line number Diff line number Diff line
@@ -480,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
{
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	int err, vol_id = vol->vol_id;
	int err;

	dbg_msg("erase LEB %d:%d", vol_id, lnum);
	dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);

	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
		return -EROFS;
@@ -541,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
{
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	int vol_id = vol->vol_id;

	dbg_msg("unmap LEB %d:%d", vol_id, lnum);
	dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);

	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
		return -EROFS;
@@ -579,9 +578,8 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
{
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	int vol_id = vol->vol_id;

	dbg_msg("unmap LEB %d:%d", vol_id, lnum);
	dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);

	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
		return -EROFS;
+7 −3
Original line number Diff line number Diff line
@@ -286,9 +286,14 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
		 * FIXME: but this is anyway obsolete and will be removed at
		 * some point.
		 */

		dbg_bld("using old crappy leb_ver stuff");

		if (v1 == v2) {
			ubi_err("PEB %d and PEB %d have the same version %lld",
				seb->pnum, pnum, v1);
			return -EINVAL;
		}

		abs = v1 - v2;
		if (abs < 0)
			abs = -abs;
@@ -390,7 +395,6 @@ out_free_buf:
	vfree(buf);
out_free_vidh:
	ubi_free_vid_hdr(ubi, vh);
	ubi_assert(err < 0);
	return err;
}

@@ -854,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
	}

	vol_id = be32_to_cpu(vidh->vol_id);
	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
		int lnum = be32_to_cpu(vidh->lnum);

		/* Unsupported internal volume */
Loading