xref: /openbmc/u-boot/drivers/mtd/ubi/vmt.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c91a719dSKyungmin Park /*
3c91a719dSKyungmin Park  * Copyright (c) International Business Machines Corp., 2006
4c91a719dSKyungmin Park  *
5c91a719dSKyungmin Park  * Author: Artem Bityutskiy (Битюцкий Артём)
6c91a719dSKyungmin Park  */
7c91a719dSKyungmin Park 
8c91a719dSKyungmin Park /*
9c91a719dSKyungmin Park  * This file contains implementation of volume creation, deletion, updating and
10c91a719dSKyungmin Park  * resizing.
11c91a719dSKyungmin Park  */
12c91a719dSKyungmin Park 
13ff94bc40SHeiko Schocher #ifndef __UBOOT__
14c91a719dSKyungmin Park #include <linux/err.h>
15ff94bc40SHeiko Schocher #include <linux/slab.h>
16ff94bc40SHeiko Schocher #include <linux/export.h>
17ff94bc40SHeiko Schocher #else
18ff94bc40SHeiko Schocher #include <div64.h>
19c91a719dSKyungmin Park #include <ubi_uboot.h>
20ff94bc40SHeiko Schocher #endif
21ff94bc40SHeiko Schocher #include <linux/math64.h>
22ff94bc40SHeiko Schocher 
23c91a719dSKyungmin Park #include "ubi.h"
24c91a719dSKyungmin Park 
25ff94bc40SHeiko Schocher static int self_check_volumes(struct ubi_device *ubi);
26c91a719dSKyungmin Park 
27ff94bc40SHeiko Schocher #ifndef __UBOOT__
28c91a719dSKyungmin Park static ssize_t vol_attribute_show(struct device *dev,
29c91a719dSKyungmin Park 				  struct device_attribute *attr, char *buf);
30c91a719dSKyungmin Park 
31c91a719dSKyungmin Park /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
32c91a719dSKyungmin Park static struct device_attribute attr_vol_reserved_ebs =
33c91a719dSKyungmin Park 	__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
34c91a719dSKyungmin Park static struct device_attribute attr_vol_type =
35c91a719dSKyungmin Park 	__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
36c91a719dSKyungmin Park static struct device_attribute attr_vol_name =
37c91a719dSKyungmin Park 	__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
38c91a719dSKyungmin Park static struct device_attribute attr_vol_corrupted =
39c91a719dSKyungmin Park 	__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
40c91a719dSKyungmin Park static struct device_attribute attr_vol_alignment =
41c91a719dSKyungmin Park 	__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
42c91a719dSKyungmin Park static struct device_attribute attr_vol_usable_eb_size =
43c91a719dSKyungmin Park 	__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
44c91a719dSKyungmin Park static struct device_attribute attr_vol_data_bytes =
45c91a719dSKyungmin Park 	__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
46c91a719dSKyungmin Park static struct device_attribute attr_vol_upd_marker =
47c91a719dSKyungmin Park 	__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
48c91a719dSKyungmin Park 
49c91a719dSKyungmin Park /*
50c91a719dSKyungmin Park  * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'.
51c91a719dSKyungmin Park  *
52c91a719dSKyungmin Park  * Consider a situation:
53c91a719dSKyungmin Park  * A. process 1 opens a sysfs file related to volume Y, say
54c91a719dSKyungmin Park  *    /<sysfs>/class/ubi/ubiX_Y/reserved_ebs;
55c91a719dSKyungmin Park  * B. process 2 removes volume Y;
56c91a719dSKyungmin Park  * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
57c91a719dSKyungmin Park  *
58c91a719dSKyungmin Park  * In this situation, this function will return %-ENODEV because it will find
59c91a719dSKyungmin Park  * out that the volume was removed from the @ubi->volumes array.
60c91a719dSKyungmin Park  */
vol_attribute_show(struct device * dev,struct device_attribute * attr,char * buf)61c91a719dSKyungmin Park static ssize_t vol_attribute_show(struct device *dev,
62c91a719dSKyungmin Park 				  struct device_attribute *attr, char *buf)
63c91a719dSKyungmin Park {
64c91a719dSKyungmin Park 	int ret;
65c91a719dSKyungmin Park 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
66c91a719dSKyungmin Park 	struct ubi_device *ubi;
67c91a719dSKyungmin Park 
68c91a719dSKyungmin Park 	ubi = ubi_get_device(vol->ubi->ubi_num);
69c91a719dSKyungmin Park 	if (!ubi)
70c91a719dSKyungmin Park 		return -ENODEV;
71c91a719dSKyungmin Park 
72c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
73c91a719dSKyungmin Park 	if (!ubi->volumes[vol->vol_id]) {
74c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
75c91a719dSKyungmin Park 		ubi_put_device(ubi);
76c91a719dSKyungmin Park 		return -ENODEV;
77c91a719dSKyungmin Park 	}
78c91a719dSKyungmin Park 	/* Take a reference to prevent volume removal */
79c91a719dSKyungmin Park 	vol->ref_count += 1;
80c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
81c91a719dSKyungmin Park 
82c91a719dSKyungmin Park 	if (attr == &attr_vol_reserved_ebs)
83c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->reserved_pebs);
84c91a719dSKyungmin Park 	else if (attr == &attr_vol_type) {
85c91a719dSKyungmin Park 		const char *tp;
86c91a719dSKyungmin Park 
87c91a719dSKyungmin Park 		if (vol->vol_type == UBI_DYNAMIC_VOLUME)
88c91a719dSKyungmin Park 			tp = "dynamic";
89c91a719dSKyungmin Park 		else
90c91a719dSKyungmin Park 			tp = "static";
91c91a719dSKyungmin Park 		ret = sprintf(buf, "%s\n", tp);
92c91a719dSKyungmin Park 	} else if (attr == &attr_vol_name)
93c91a719dSKyungmin Park 		ret = sprintf(buf, "%s\n", vol->name);
94c91a719dSKyungmin Park 	else if (attr == &attr_vol_corrupted)
95c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->corrupted);
96c91a719dSKyungmin Park 	else if (attr == &attr_vol_alignment)
97c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->alignment);
98c91a719dSKyungmin Park 	else if (attr == &attr_vol_usable_eb_size)
99c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->usable_leb_size);
100c91a719dSKyungmin Park 	else if (attr == &attr_vol_data_bytes)
101c91a719dSKyungmin Park 		ret = sprintf(buf, "%lld\n", vol->used_bytes);
102c91a719dSKyungmin Park 	else if (attr == &attr_vol_upd_marker)
103c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->upd_marker);
104c91a719dSKyungmin Park 	else
105c91a719dSKyungmin Park 		/* This must be a bug */
106c91a719dSKyungmin Park 		ret = -EINVAL;
107c91a719dSKyungmin Park 
108c91a719dSKyungmin Park 	/* We've done the operation, drop volume and UBI device references */
109c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
110c91a719dSKyungmin Park 	vol->ref_count -= 1;
111c91a719dSKyungmin Park 	ubi_assert(vol->ref_count >= 0);
112c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
113c91a719dSKyungmin Park 	ubi_put_device(ubi);
114c91a719dSKyungmin Park 	return ret;
115c91a719dSKyungmin Park }
1160195a7bbSHeiko Schocher 
1170195a7bbSHeiko Schocher static struct attribute *volume_dev_attrs[] = {
1180195a7bbSHeiko Schocher 	&attr_vol_reserved_ebs.attr,
1190195a7bbSHeiko Schocher 	&attr_vol_type.attr,
1200195a7bbSHeiko Schocher 	&attr_vol_name.attr,
1210195a7bbSHeiko Schocher 	&attr_vol_corrupted.attr,
1220195a7bbSHeiko Schocher 	&attr_vol_alignment.attr,
1230195a7bbSHeiko Schocher 	&attr_vol_usable_eb_size.attr,
1240195a7bbSHeiko Schocher 	&attr_vol_data_bytes.attr,
1250195a7bbSHeiko Schocher 	&attr_vol_upd_marker.attr,
1260195a7bbSHeiko Schocher 	NULL
1270195a7bbSHeiko Schocher };
1280195a7bbSHeiko Schocher ATTRIBUTE_GROUPS(volume_dev);
129c91a719dSKyungmin Park #endif
130c91a719dSKyungmin Park 
131c91a719dSKyungmin Park /* Release method for volume devices */
vol_release(struct device * dev)132c91a719dSKyungmin Park static void vol_release(struct device *dev)
133c91a719dSKyungmin Park {
134c91a719dSKyungmin Park 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
135c91a719dSKyungmin Park 
136ff94bc40SHeiko Schocher 	kfree(vol->eba_tbl);
137c91a719dSKyungmin Park 	kfree(vol);
138c91a719dSKyungmin Park }
139c91a719dSKyungmin Park 
140c91a719dSKyungmin Park /**
141c91a719dSKyungmin Park  * ubi_create_volume - create volume.
142c91a719dSKyungmin Park  * @ubi: UBI device description object
143c91a719dSKyungmin Park  * @req: volume creation request
144c91a719dSKyungmin Park  *
145c91a719dSKyungmin Park  * This function creates volume described by @req. If @req->vol_id id
146c91a719dSKyungmin Park  * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume
147c91a719dSKyungmin Park  * and saves it in @req->vol_id. Returns zero in case of success and a negative
148c91a719dSKyungmin Park  * error code in case of failure. Note, the caller has to have the
149ff94bc40SHeiko Schocher  * @ubi->device_mutex locked.
150c91a719dSKyungmin Park  */
ubi_create_volume(struct ubi_device * ubi,struct ubi_mkvol_req * req)151c91a719dSKyungmin Park int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
152c91a719dSKyungmin Park {
153ff94bc40SHeiko Schocher 	int i, err, vol_id = req->vol_id, do_free = 1;
154c91a719dSKyungmin Park 	struct ubi_volume *vol;
155c91a719dSKyungmin Park 	struct ubi_vtbl_record vtbl_rec;
156c91a719dSKyungmin Park 	dev_t dev;
157c91a719dSKyungmin Park 
158c91a719dSKyungmin Park 	if (ubi->ro_mode)
159c91a719dSKyungmin Park 		return -EROFS;
160c91a719dSKyungmin Park 
161c91a719dSKyungmin Park 	vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
162c91a719dSKyungmin Park 	if (!vol)
163c91a719dSKyungmin Park 		return -ENOMEM;
164c91a719dSKyungmin Park 
165c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
166c91a719dSKyungmin Park 	if (vol_id == UBI_VOL_NUM_AUTO) {
167c91a719dSKyungmin Park 		/* Find unused volume ID */
168ff94bc40SHeiko Schocher 		dbg_gen("search for vacant volume ID");
169c91a719dSKyungmin Park 		for (i = 0; i < ubi->vtbl_slots; i++)
170c91a719dSKyungmin Park 			if (!ubi->volumes[i]) {
171c91a719dSKyungmin Park 				vol_id = i;
172c91a719dSKyungmin Park 				break;
173c91a719dSKyungmin Park 			}
174c91a719dSKyungmin Park 
175c91a719dSKyungmin Park 		if (vol_id == UBI_VOL_NUM_AUTO) {
1760195a7bbSHeiko Schocher 			ubi_err(ubi, "out of volume IDs");
177c91a719dSKyungmin Park 			err = -ENFILE;
178c91a719dSKyungmin Park 			goto out_unlock;
179c91a719dSKyungmin Park 		}
180c91a719dSKyungmin Park 		req->vol_id = vol_id;
181c91a719dSKyungmin Park 	}
182c91a719dSKyungmin Park 
183ff94bc40SHeiko Schocher 	dbg_gen("create device %d, volume %d, %llu bytes, type %d, name %s",
184ff94bc40SHeiko Schocher 		ubi->ubi_num, vol_id, (unsigned long long)req->bytes,
185c91a719dSKyungmin Park 		(int)req->vol_type, req->name);
186c91a719dSKyungmin Park 
187c91a719dSKyungmin Park 	/* Ensure that this volume does not exist */
188c91a719dSKyungmin Park 	err = -EEXIST;
189c91a719dSKyungmin Park 	if (ubi->volumes[vol_id]) {
1900195a7bbSHeiko Schocher 		ubi_err(ubi, "volume %d already exists", vol_id);
191c91a719dSKyungmin Park 		goto out_unlock;
192c91a719dSKyungmin Park 	}
193c91a719dSKyungmin Park 
194c91a719dSKyungmin Park 	/* Ensure that the name is unique */
195c91a719dSKyungmin Park 	for (i = 0; i < ubi->vtbl_slots; i++)
196c91a719dSKyungmin Park 		if (ubi->volumes[i] &&
197c91a719dSKyungmin Park 		    ubi->volumes[i]->name_len == req->name_len &&
198c91a719dSKyungmin Park 		    !strcmp(ubi->volumes[i]->name, req->name)) {
1990195a7bbSHeiko Schocher 			ubi_err(ubi, "volume \"%s\" exists (ID %d)",
2000195a7bbSHeiko Schocher 				req->name, i);
201c91a719dSKyungmin Park 			goto out_unlock;
202c91a719dSKyungmin Park 		}
203c91a719dSKyungmin Park 
204c91a719dSKyungmin Park 	/* Calculate how many eraseblocks are requested */
205c91a719dSKyungmin Park 	vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
2060195a7bbSHeiko Schocher 	vol->reserved_pebs = div_u64(req->bytes + vol->usable_leb_size - 1,
207ff94bc40SHeiko Schocher 				     vol->usable_leb_size);
208c91a719dSKyungmin Park 
209c91a719dSKyungmin Park 	/* Reserve physical eraseblocks */
210c91a719dSKyungmin Park 	if (vol->reserved_pebs > ubi->avail_pebs) {
2110195a7bbSHeiko Schocher 		ubi_err(ubi, "not enough PEBs, only %d available",
2120195a7bbSHeiko Schocher 			ubi->avail_pebs);
213ff94bc40SHeiko Schocher 		if (ubi->corr_peb_count)
2140195a7bbSHeiko Schocher 			ubi_err(ubi, "%d PEBs are corrupted and not used",
215ff94bc40SHeiko Schocher 				ubi->corr_peb_count);
216c91a719dSKyungmin Park 		err = -ENOSPC;
217c91a719dSKyungmin Park 		goto out_unlock;
218c91a719dSKyungmin Park 	}
219c91a719dSKyungmin Park 	ubi->avail_pebs -= vol->reserved_pebs;
220c91a719dSKyungmin Park 	ubi->rsvd_pebs += vol->reserved_pebs;
221c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
222c91a719dSKyungmin Park 
223c91a719dSKyungmin Park 	vol->vol_id    = vol_id;
224c91a719dSKyungmin Park 	vol->alignment = req->alignment;
225c91a719dSKyungmin Park 	vol->data_pad  = ubi->leb_size % vol->alignment;
226c91a719dSKyungmin Park 	vol->vol_type  = req->vol_type;
227c91a719dSKyungmin Park 	vol->name_len  = req->name_len;
228ff94bc40SHeiko Schocher 	memcpy(vol->name, req->name, vol->name_len);
229c91a719dSKyungmin Park 	vol->ubi = ubi;
230c91a719dSKyungmin Park 
231c91a719dSKyungmin Park 	/*
232c91a719dSKyungmin Park 	 * Finish all pending erases because there may be some LEBs belonging
233c91a719dSKyungmin Park 	 * to the same volume ID.
234c91a719dSKyungmin Park 	 */
235ff94bc40SHeiko Schocher 	err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
236c91a719dSKyungmin Park 	if (err)
237c91a719dSKyungmin Park 		goto out_acc;
238c91a719dSKyungmin Park 
239c91a719dSKyungmin Park 	vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
240c91a719dSKyungmin Park 	if (!vol->eba_tbl) {
241c91a719dSKyungmin Park 		err = -ENOMEM;
242c91a719dSKyungmin Park 		goto out_acc;
243c91a719dSKyungmin Park 	}
244c91a719dSKyungmin Park 
245c91a719dSKyungmin Park 	for (i = 0; i < vol->reserved_pebs; i++)
246c91a719dSKyungmin Park 		vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
247c91a719dSKyungmin Park 
248c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
249c91a719dSKyungmin Park 		vol->used_ebs = vol->reserved_pebs;
250c91a719dSKyungmin Park 		vol->last_eb_bytes = vol->usable_leb_size;
251c91a719dSKyungmin Park 		vol->used_bytes =
252c91a719dSKyungmin Park 			(long long)vol->used_ebs * vol->usable_leb_size;
253c91a719dSKyungmin Park 	} else {
254ff94bc40SHeiko Schocher 		vol->used_ebs = div_u64_rem(vol->used_bytes,
255ff94bc40SHeiko Schocher 					    vol->usable_leb_size,
256ff94bc40SHeiko Schocher 					    &vol->last_eb_bytes);
257ff94bc40SHeiko Schocher 		if (vol->last_eb_bytes != 0)
258c91a719dSKyungmin Park 			vol->used_ebs += 1;
259c91a719dSKyungmin Park 		else
260c91a719dSKyungmin Park 			vol->last_eb_bytes = vol->usable_leb_size;
261c91a719dSKyungmin Park 	}
262c91a719dSKyungmin Park 
263c91a719dSKyungmin Park 	/* Register character device for the volume */
264c91a719dSKyungmin Park 	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
265c91a719dSKyungmin Park 	vol->cdev.owner = THIS_MODULE;
266c91a719dSKyungmin Park 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
267c91a719dSKyungmin Park 	err = cdev_add(&vol->cdev, dev, 1);
268c91a719dSKyungmin Park 	if (err) {
2690195a7bbSHeiko Schocher 		ubi_err(ubi, "cannot add character device");
270c91a719dSKyungmin Park 		goto out_mapping;
271c91a719dSKyungmin Park 	}
272c91a719dSKyungmin Park 
273c91a719dSKyungmin Park 	vol->dev.release = vol_release;
274c91a719dSKyungmin Park 	vol->dev.parent = &ubi->dev;
275c91a719dSKyungmin Park 	vol->dev.devt = dev;
2760195a7bbSHeiko Schocher #ifndef __UBOOT__
2770195a7bbSHeiko Schocher 	vol->dev.class = &ubi_class;
2780195a7bbSHeiko Schocher 	vol->dev.groups = volume_dev_groups;
2790195a7bbSHeiko Schocher #endif
280c91a719dSKyungmin Park 
281ff94bc40SHeiko Schocher 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
282c91a719dSKyungmin Park 	err = device_register(&vol->dev);
283c91a719dSKyungmin Park 	if (err) {
2840195a7bbSHeiko Schocher 		ubi_err(ubi, "cannot register device");
285ff94bc40SHeiko Schocher 		goto out_cdev;
286c91a719dSKyungmin Park 	}
287c91a719dSKyungmin Park 
288c91a719dSKyungmin Park 	/* Fill volume table record */
289c91a719dSKyungmin Park 	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
290c91a719dSKyungmin Park 	vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
291c91a719dSKyungmin Park 	vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
292c91a719dSKyungmin Park 	vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
293c91a719dSKyungmin Park 	vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
294c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
295c91a719dSKyungmin Park 		vtbl_rec.vol_type = UBI_VID_DYNAMIC;
296c91a719dSKyungmin Park 	else
297c91a719dSKyungmin Park 		vtbl_rec.vol_type = UBI_VID_STATIC;
298ff94bc40SHeiko Schocher 	memcpy(vtbl_rec.name, vol->name, vol->name_len);
299c91a719dSKyungmin Park 
300c91a719dSKyungmin Park 	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
301c91a719dSKyungmin Park 	if (err)
302c91a719dSKyungmin Park 		goto out_sysfs;
303c91a719dSKyungmin Park 
304c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
305c91a719dSKyungmin Park 	ubi->volumes[vol_id] = vol;
306c91a719dSKyungmin Park 	ubi->vol_count += 1;
307c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
308c91a719dSKyungmin Park 
309ff94bc40SHeiko Schocher 	ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
310ff94bc40SHeiko Schocher 	self_check_volumes(ubi);
311ff94bc40SHeiko Schocher 	return err;
312c91a719dSKyungmin Park 
313c91a719dSKyungmin Park out_sysfs:
314c91a719dSKyungmin Park 	/*
315ff94bc40SHeiko Schocher 	 * We have registered our device, we should not free the volume
316c91a719dSKyungmin Park 	 * description object in this function in case of an error - it is
317c91a719dSKyungmin Park 	 * freed by the release function.
318c91a719dSKyungmin Park 	 *
319c91a719dSKyungmin Park 	 * Get device reference to prevent the release function from being
320c91a719dSKyungmin Park 	 * called just after sysfs has been closed.
321c91a719dSKyungmin Park 	 */
322ff94bc40SHeiko Schocher 	do_free = 0;
323c91a719dSKyungmin Park 	get_device(&vol->dev);
3240195a7bbSHeiko Schocher 	device_unregister(&vol->dev);
325c91a719dSKyungmin Park out_cdev:
326c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
327c91a719dSKyungmin Park out_mapping:
328ff94bc40SHeiko Schocher 	if (do_free)
329c91a719dSKyungmin Park 		kfree(vol->eba_tbl);
330c91a719dSKyungmin Park out_acc:
331c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
332c91a719dSKyungmin Park 	ubi->rsvd_pebs -= vol->reserved_pebs;
333c91a719dSKyungmin Park 	ubi->avail_pebs += vol->reserved_pebs;
334c91a719dSKyungmin Park out_unlock:
335c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
336ff94bc40SHeiko Schocher 	if (do_free)
337c91a719dSKyungmin Park 		kfree(vol);
338ff94bc40SHeiko Schocher 	else
339ff94bc40SHeiko Schocher 		put_device(&vol->dev);
3400195a7bbSHeiko Schocher 	ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err);
341c91a719dSKyungmin Park 	return err;
342c91a719dSKyungmin Park }
343c91a719dSKyungmin Park 
344c91a719dSKyungmin Park /**
345c91a719dSKyungmin Park  * ubi_remove_volume - remove volume.
346c91a719dSKyungmin Park  * @desc: volume descriptor
347ff94bc40SHeiko Schocher  * @no_vtbl: do not change volume table if not zero
348c91a719dSKyungmin Park  *
349c91a719dSKyungmin Park  * This function removes volume described by @desc. The volume has to be opened
350c91a719dSKyungmin Park  * in "exclusive" mode. Returns zero in case of success and a negative error
351ff94bc40SHeiko Schocher  * code in case of failure. The caller has to have the @ubi->device_mutex
352c91a719dSKyungmin Park  * locked.
353c91a719dSKyungmin Park  */
ubi_remove_volume(struct ubi_volume_desc * desc,int no_vtbl)354ff94bc40SHeiko Schocher int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
355c91a719dSKyungmin Park {
356c91a719dSKyungmin Park 	struct ubi_volume *vol = desc->vol;
357c91a719dSKyungmin Park 	struct ubi_device *ubi = vol->ubi;
358c91a719dSKyungmin Park 	int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
359c91a719dSKyungmin Park 
360ff94bc40SHeiko Schocher 	dbg_gen("remove device %d, volume %d", ubi->ubi_num, vol_id);
361c91a719dSKyungmin Park 	ubi_assert(desc->mode == UBI_EXCLUSIVE);
362c91a719dSKyungmin Park 	ubi_assert(vol == ubi->volumes[vol_id]);
363c91a719dSKyungmin Park 
364c91a719dSKyungmin Park 	if (ubi->ro_mode)
365c91a719dSKyungmin Park 		return -EROFS;
366c91a719dSKyungmin Park 
367c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
368c91a719dSKyungmin Park 	if (vol->ref_count > 1) {
369c91a719dSKyungmin Park 		/*
370c91a719dSKyungmin Park 		 * The volume is busy, probably someone is reading one of its
371c91a719dSKyungmin Park 		 * sysfs files.
372c91a719dSKyungmin Park 		 */
373c91a719dSKyungmin Park 		err = -EBUSY;
374c91a719dSKyungmin Park 		goto out_unlock;
375c91a719dSKyungmin Park 	}
376c91a719dSKyungmin Park 	ubi->volumes[vol_id] = NULL;
377c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
378c91a719dSKyungmin Park 
379ff94bc40SHeiko Schocher 	if (!no_vtbl) {
380c91a719dSKyungmin Park 		err = ubi_change_vtbl_record(ubi, vol_id, NULL);
381c91a719dSKyungmin Park 		if (err)
382c91a719dSKyungmin Park 			goto out_err;
383ff94bc40SHeiko Schocher 	}
384c91a719dSKyungmin Park 
385c91a719dSKyungmin Park 	for (i = 0; i < vol->reserved_pebs; i++) {
386c91a719dSKyungmin Park 		err = ubi_eba_unmap_leb(ubi, vol, i);
387c91a719dSKyungmin Park 		if (err)
388c91a719dSKyungmin Park 			goto out_err;
389c91a719dSKyungmin Park 	}
390c91a719dSKyungmin Park 
391c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
3920195a7bbSHeiko Schocher 	device_unregister(&vol->dev);
393c91a719dSKyungmin Park 
394c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
395c91a719dSKyungmin Park 	ubi->rsvd_pebs -= reserved_pebs;
396c91a719dSKyungmin Park 	ubi->avail_pebs += reserved_pebs;
397ff94bc40SHeiko Schocher 	ubi_update_reserved(ubi);
398c91a719dSKyungmin Park 	ubi->vol_count -= 1;
399c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
400c91a719dSKyungmin Park 
401ff94bc40SHeiko Schocher 	ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
402ff94bc40SHeiko Schocher 	if (!no_vtbl)
403ff94bc40SHeiko Schocher 		self_check_volumes(ubi);
404ff94bc40SHeiko Schocher 
405ff94bc40SHeiko Schocher 	return err;
406c91a719dSKyungmin Park 
407c91a719dSKyungmin Park out_err:
4080195a7bbSHeiko Schocher 	ubi_err(ubi, "cannot remove volume %d, error %d", vol_id, err);
409c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
410c91a719dSKyungmin Park 	ubi->volumes[vol_id] = vol;
411c91a719dSKyungmin Park out_unlock:
412c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
413c91a719dSKyungmin Park 	return err;
414c91a719dSKyungmin Park }
415c91a719dSKyungmin Park 
416c91a719dSKyungmin Park /**
417c91a719dSKyungmin Park  * ubi_resize_volume - re-size volume.
418c91a719dSKyungmin Park  * @desc: volume descriptor
419c91a719dSKyungmin Park  * @reserved_pebs: new size in physical eraseblocks
420c91a719dSKyungmin Park  *
421c91a719dSKyungmin Park  * This function re-sizes the volume and returns zero in case of success, and a
422c91a719dSKyungmin Park  * negative error code in case of failure. The caller has to have the
423ff94bc40SHeiko Schocher  * @ubi->device_mutex locked.
424c91a719dSKyungmin Park  */
ubi_resize_volume(struct ubi_volume_desc * desc,int reserved_pebs)425c91a719dSKyungmin Park int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
426c91a719dSKyungmin Park {
427c91a719dSKyungmin Park 	int i, err, pebs, *new_mapping;
428c91a719dSKyungmin Park 	struct ubi_volume *vol = desc->vol;
429c91a719dSKyungmin Park 	struct ubi_device *ubi = vol->ubi;
430c91a719dSKyungmin Park 	struct ubi_vtbl_record vtbl_rec;
431c91a719dSKyungmin Park 	int vol_id = vol->vol_id;
432c91a719dSKyungmin Park 
433c91a719dSKyungmin Park 	if (ubi->ro_mode)
434c91a719dSKyungmin Park 		return -EROFS;
435c91a719dSKyungmin Park 
436ff94bc40SHeiko Schocher 	dbg_gen("re-size device %d, volume %d to from %d to %d PEBs",
437ff94bc40SHeiko Schocher 		ubi->ubi_num, vol_id, vol->reserved_pebs, reserved_pebs);
438c91a719dSKyungmin Park 
439c91a719dSKyungmin Park 	if (vol->vol_type == UBI_STATIC_VOLUME &&
440c91a719dSKyungmin Park 	    reserved_pebs < vol->used_ebs) {
4410195a7bbSHeiko Schocher 		ubi_err(ubi, "too small size %d, %d LEBs contain data",
442c91a719dSKyungmin Park 			reserved_pebs, vol->used_ebs);
443c91a719dSKyungmin Park 		return -EINVAL;
444c91a719dSKyungmin Park 	}
445c91a719dSKyungmin Park 
446c91a719dSKyungmin Park 	/* If the size is the same, we have nothing to do */
447c91a719dSKyungmin Park 	if (reserved_pebs == vol->reserved_pebs)
448c91a719dSKyungmin Park 		return 0;
449c91a719dSKyungmin Park 
450c91a719dSKyungmin Park 	new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
451c91a719dSKyungmin Park 	if (!new_mapping)
452c91a719dSKyungmin Park 		return -ENOMEM;
453c91a719dSKyungmin Park 
454c91a719dSKyungmin Park 	for (i = 0; i < reserved_pebs; i++)
455c91a719dSKyungmin Park 		new_mapping[i] = UBI_LEB_UNMAPPED;
456c91a719dSKyungmin Park 
457c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
458c91a719dSKyungmin Park 	if (vol->ref_count > 1) {
459c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
460c91a719dSKyungmin Park 		err = -EBUSY;
461c91a719dSKyungmin Park 		goto out_free;
462c91a719dSKyungmin Park 	}
463c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
464c91a719dSKyungmin Park 
465c91a719dSKyungmin Park 	/* Reserve physical eraseblocks */
466c91a719dSKyungmin Park 	pebs = reserved_pebs - vol->reserved_pebs;
467c91a719dSKyungmin Park 	if (pebs > 0) {
468c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
469c91a719dSKyungmin Park 		if (pebs > ubi->avail_pebs) {
4700195a7bbSHeiko Schocher 			ubi_err(ubi, "not enough PEBs: requested %d, available %d",
471c91a719dSKyungmin Park 				pebs, ubi->avail_pebs);
472ff94bc40SHeiko Schocher 			if (ubi->corr_peb_count)
4730195a7bbSHeiko Schocher 				ubi_err(ubi, "%d PEBs are corrupted and not used",
474ff94bc40SHeiko Schocher 					ubi->corr_peb_count);
475c91a719dSKyungmin Park 			spin_unlock(&ubi->volumes_lock);
476c91a719dSKyungmin Park 			err = -ENOSPC;
477c91a719dSKyungmin Park 			goto out_free;
478c91a719dSKyungmin Park 		}
479c91a719dSKyungmin Park 		ubi->avail_pebs -= pebs;
480c91a719dSKyungmin Park 		ubi->rsvd_pebs += pebs;
481c91a719dSKyungmin Park 		for (i = 0; i < vol->reserved_pebs; i++)
482c91a719dSKyungmin Park 			new_mapping[i] = vol->eba_tbl[i];
483c91a719dSKyungmin Park 		kfree(vol->eba_tbl);
484c91a719dSKyungmin Park 		vol->eba_tbl = new_mapping;
485c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
486c91a719dSKyungmin Park 	}
487c91a719dSKyungmin Park 
488c91a719dSKyungmin Park 	/* Change volume table record */
489ff94bc40SHeiko Schocher 	vtbl_rec = ubi->vtbl[vol_id];
490c91a719dSKyungmin Park 	vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
491c91a719dSKyungmin Park 	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
492c91a719dSKyungmin Park 	if (err)
493c91a719dSKyungmin Park 		goto out_acc;
494c91a719dSKyungmin Park 
495c91a719dSKyungmin Park 	if (pebs < 0) {
496c91a719dSKyungmin Park 		for (i = 0; i < -pebs; i++) {
497c91a719dSKyungmin Park 			err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
498c91a719dSKyungmin Park 			if (err)
499c91a719dSKyungmin Park 				goto out_acc;
500c91a719dSKyungmin Park 		}
501c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
502c91a719dSKyungmin Park 		ubi->rsvd_pebs += pebs;
503c91a719dSKyungmin Park 		ubi->avail_pebs -= pebs;
504ff94bc40SHeiko Schocher 		ubi_update_reserved(ubi);
505c91a719dSKyungmin Park 		for (i = 0; i < reserved_pebs; i++)
506c91a719dSKyungmin Park 			new_mapping[i] = vol->eba_tbl[i];
507c91a719dSKyungmin Park 		kfree(vol->eba_tbl);
508c91a719dSKyungmin Park 		vol->eba_tbl = new_mapping;
509c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
510c91a719dSKyungmin Park 	}
511c91a719dSKyungmin Park 
512c91a719dSKyungmin Park 	vol->reserved_pebs = reserved_pebs;
513c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
514c91a719dSKyungmin Park 		vol->used_ebs = reserved_pebs;
515c91a719dSKyungmin Park 		vol->last_eb_bytes = vol->usable_leb_size;
516c91a719dSKyungmin Park 		vol->used_bytes =
517c91a719dSKyungmin Park 			(long long)vol->used_ebs * vol->usable_leb_size;
518c91a719dSKyungmin Park 	}
519c91a719dSKyungmin Park 
520ff94bc40SHeiko Schocher 	ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
521ff94bc40SHeiko Schocher 	self_check_volumes(ubi);
522ff94bc40SHeiko Schocher 	return err;
523c91a719dSKyungmin Park 
524c91a719dSKyungmin Park out_acc:
525c91a719dSKyungmin Park 	if (pebs > 0) {
526c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
527c91a719dSKyungmin Park 		ubi->rsvd_pebs -= pebs;
528c91a719dSKyungmin Park 		ubi->avail_pebs += pebs;
529c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
530c91a719dSKyungmin Park 	}
531c91a719dSKyungmin Park out_free:
532c91a719dSKyungmin Park 	kfree(new_mapping);
533c91a719dSKyungmin Park 	return err;
534c91a719dSKyungmin Park }
535c91a719dSKyungmin Park 
536c91a719dSKyungmin Park /**
537ff94bc40SHeiko Schocher  * ubi_rename_volumes - re-name UBI volumes.
538ff94bc40SHeiko Schocher  * @ubi: UBI device description object
539ff94bc40SHeiko Schocher  * @rename_list: list of &struct ubi_rename_entry objects
540ff94bc40SHeiko Schocher  *
541ff94bc40SHeiko Schocher  * This function re-names or removes volumes specified in the re-name list.
542ff94bc40SHeiko Schocher  * Returns zero in case of success and a negative error code in case of
543ff94bc40SHeiko Schocher  * failure.
544ff94bc40SHeiko Schocher  */
ubi_rename_volumes(struct ubi_device * ubi,struct list_head * rename_list)545ff94bc40SHeiko Schocher int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
546ff94bc40SHeiko Schocher {
547ff94bc40SHeiko Schocher 	int err;
548ff94bc40SHeiko Schocher 	struct ubi_rename_entry *re;
549ff94bc40SHeiko Schocher 
550ff94bc40SHeiko Schocher 	err = ubi_vtbl_rename_volumes(ubi, rename_list);
551ff94bc40SHeiko Schocher 	if (err)
552ff94bc40SHeiko Schocher 		return err;
553ff94bc40SHeiko Schocher 
554ff94bc40SHeiko Schocher 	list_for_each_entry(re, rename_list, list) {
555ff94bc40SHeiko Schocher 		if (re->remove) {
556ff94bc40SHeiko Schocher 			err = ubi_remove_volume(re->desc, 1);
557ff94bc40SHeiko Schocher 			if (err)
558ff94bc40SHeiko Schocher 				break;
559ff94bc40SHeiko Schocher 		} else {
560ff94bc40SHeiko Schocher 			struct ubi_volume *vol = re->desc->vol;
561ff94bc40SHeiko Schocher 
562ff94bc40SHeiko Schocher 			spin_lock(&ubi->volumes_lock);
563ff94bc40SHeiko Schocher 			vol->name_len = re->new_name_len;
564ff94bc40SHeiko Schocher 			memcpy(vol->name, re->new_name, re->new_name_len + 1);
565ff94bc40SHeiko Schocher 			spin_unlock(&ubi->volumes_lock);
566ff94bc40SHeiko Schocher 			ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED);
567ff94bc40SHeiko Schocher 		}
568ff94bc40SHeiko Schocher 	}
569ff94bc40SHeiko Schocher 
570ff94bc40SHeiko Schocher 	if (!err)
571ff94bc40SHeiko Schocher 		self_check_volumes(ubi);
572ff94bc40SHeiko Schocher 	return err;
573ff94bc40SHeiko Schocher }
574ff94bc40SHeiko Schocher 
575ff94bc40SHeiko Schocher /**
576c91a719dSKyungmin Park  * ubi_add_volume - add volume.
577c91a719dSKyungmin Park  * @ubi: UBI device description object
578c91a719dSKyungmin Park  * @vol: volume description object
579c91a719dSKyungmin Park  *
580c91a719dSKyungmin Park  * This function adds an existing volume and initializes all its data
581c91a719dSKyungmin Park  * structures. Returns zero in case of success and a negative error code in
582c91a719dSKyungmin Park  * case of failure.
583c91a719dSKyungmin Park  */
ubi_add_volume(struct ubi_device * ubi,struct ubi_volume * vol)584c91a719dSKyungmin Park int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
585c91a719dSKyungmin Park {
586c91a719dSKyungmin Park 	int err, vol_id = vol->vol_id;
587c91a719dSKyungmin Park 	dev_t dev;
588c91a719dSKyungmin Park 
589ff94bc40SHeiko Schocher 	dbg_gen("add volume %d", vol_id);
590c91a719dSKyungmin Park 
591c91a719dSKyungmin Park 	/* Register character device for the volume */
592c91a719dSKyungmin Park 	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
593c91a719dSKyungmin Park 	vol->cdev.owner = THIS_MODULE;
594c91a719dSKyungmin Park 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
595c91a719dSKyungmin Park 	err = cdev_add(&vol->cdev, dev, 1);
596c91a719dSKyungmin Park 	if (err) {
5970195a7bbSHeiko Schocher 		ubi_err(ubi, "cannot add character device for volume %d, error %d",
598c91a719dSKyungmin Park 			vol_id, err);
599c91a719dSKyungmin Park 		return err;
600c91a719dSKyungmin Park 	}
601c91a719dSKyungmin Park 
602c91a719dSKyungmin Park 	vol->dev.release = vol_release;
603c91a719dSKyungmin Park 	vol->dev.parent = &ubi->dev;
604c91a719dSKyungmin Park 	vol->dev.devt = dev;
6050195a7bbSHeiko Schocher #ifndef __UBOOT__
6060195a7bbSHeiko Schocher 	vol->dev.class = &ubi_class;
6070195a7bbSHeiko Schocher 	vol->dev.groups = volume_dev_groups;
6080195a7bbSHeiko Schocher #endif
609ff94bc40SHeiko Schocher 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
610c91a719dSKyungmin Park 	err = device_register(&vol->dev);
611c91a719dSKyungmin Park 	if (err)
612ff94bc40SHeiko Schocher 		goto out_cdev;
613c91a719dSKyungmin Park 
614ff94bc40SHeiko Schocher 	self_check_volumes(ubi);
615ff94bc40SHeiko Schocher 	return err;
616c91a719dSKyungmin Park 
617c91a719dSKyungmin Park out_cdev:
618c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
619c91a719dSKyungmin Park 	return err;
620c91a719dSKyungmin Park }
621c91a719dSKyungmin Park 
622c91a719dSKyungmin Park /**
623c91a719dSKyungmin Park  * ubi_free_volume - free volume.
624c91a719dSKyungmin Park  * @ubi: UBI device description object
625c91a719dSKyungmin Park  * @vol: volume description object
626c91a719dSKyungmin Park  *
627c91a719dSKyungmin Park  * This function frees all resources for volume @vol but does not remove it.
628c91a719dSKyungmin Park  * Used only when the UBI device is detached.
629c91a719dSKyungmin Park  */
ubi_free_volume(struct ubi_device * ubi,struct ubi_volume * vol)630c91a719dSKyungmin Park void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
631c91a719dSKyungmin Park {
632ff94bc40SHeiko Schocher 	dbg_gen("free volume %d", vol->vol_id);
633c91a719dSKyungmin Park 
634c91a719dSKyungmin Park 	ubi->volumes[vol->vol_id] = NULL;
635c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
6360195a7bbSHeiko Schocher 	device_unregister(&vol->dev);
637c91a719dSKyungmin Park }
638c91a719dSKyungmin Park 
639c91a719dSKyungmin Park /**
640ff94bc40SHeiko Schocher  * self_check_volume - check volume information.
641c91a719dSKyungmin Park  * @ubi: UBI device description object
642c91a719dSKyungmin Park  * @vol_id: volume ID
643ff94bc40SHeiko Schocher  *
644ff94bc40SHeiko Schocher  * Returns zero if volume is all right and a a negative error code if not.
645c91a719dSKyungmin Park  */
self_check_volume(struct ubi_device * ubi,int vol_id)646ff94bc40SHeiko Schocher static int self_check_volume(struct ubi_device *ubi, int vol_id)
647c91a719dSKyungmin Park {
648c91a719dSKyungmin Park 	int idx = vol_id2idx(ubi, vol_id);
649c91a719dSKyungmin Park 	int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
650c91a719dSKyungmin Park 	const struct ubi_volume *vol;
651c91a719dSKyungmin Park 	long long n;
652c91a719dSKyungmin Park 	const char *name;
653c91a719dSKyungmin Park 
654c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
655c91a719dSKyungmin Park 	reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
656c91a719dSKyungmin Park 	vol = ubi->volumes[idx];
657c91a719dSKyungmin Park 
658c91a719dSKyungmin Park 	if (!vol) {
659c91a719dSKyungmin Park 		if (reserved_pebs) {
6600195a7bbSHeiko Schocher 			ubi_err(ubi, "no volume info, but volume exists");
661c91a719dSKyungmin Park 			goto fail;
662c91a719dSKyungmin Park 		}
663c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
664ff94bc40SHeiko Schocher 		return 0;
665c91a719dSKyungmin Park 	}
666c91a719dSKyungmin Park 
667c91a719dSKyungmin Park 	if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
668c91a719dSKyungmin Park 	    vol->name_len < 0) {
6690195a7bbSHeiko Schocher 		ubi_err(ubi, "negative values");
670c91a719dSKyungmin Park 		goto fail;
671c91a719dSKyungmin Park 	}
672c91a719dSKyungmin Park 	if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
6730195a7bbSHeiko Schocher 		ubi_err(ubi, "bad alignment");
674c91a719dSKyungmin Park 		goto fail;
675c91a719dSKyungmin Park 	}
676c91a719dSKyungmin Park 
677c91a719dSKyungmin Park 	n = vol->alignment & (ubi->min_io_size - 1);
678c91a719dSKyungmin Park 	if (vol->alignment != 1 && n) {
6790195a7bbSHeiko Schocher 		ubi_err(ubi, "alignment is not multiple of min I/O unit");
680c91a719dSKyungmin Park 		goto fail;
681c91a719dSKyungmin Park 	}
682c91a719dSKyungmin Park 
683c91a719dSKyungmin Park 	n = ubi->leb_size % vol->alignment;
684c91a719dSKyungmin Park 	if (vol->data_pad != n) {
6850195a7bbSHeiko Schocher 		ubi_err(ubi, "bad data_pad, has to be %lld", n);
686c91a719dSKyungmin Park 		goto fail;
687c91a719dSKyungmin Park 	}
688c91a719dSKyungmin Park 
689c91a719dSKyungmin Park 	if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
690c91a719dSKyungmin Park 	    vol->vol_type != UBI_STATIC_VOLUME) {
6910195a7bbSHeiko Schocher 		ubi_err(ubi, "bad vol_type");
692c91a719dSKyungmin Park 		goto fail;
693c91a719dSKyungmin Park 	}
694c91a719dSKyungmin Park 
695c91a719dSKyungmin Park 	if (vol->upd_marker && vol->corrupted) {
6960195a7bbSHeiko Schocher 		ubi_err(ubi, "update marker and corrupted simultaneously");
697c91a719dSKyungmin Park 		goto fail;
698c91a719dSKyungmin Park 	}
699c91a719dSKyungmin Park 
700c91a719dSKyungmin Park 	if (vol->reserved_pebs > ubi->good_peb_count) {
7010195a7bbSHeiko Schocher 		ubi_err(ubi, "too large reserved_pebs");
702c91a719dSKyungmin Park 		goto fail;
703c91a719dSKyungmin Park 	}
704c91a719dSKyungmin Park 
705c91a719dSKyungmin Park 	n = ubi->leb_size - vol->data_pad;
706c91a719dSKyungmin Park 	if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
7070195a7bbSHeiko Schocher 		ubi_err(ubi, "bad usable_leb_size, has to be %lld", n);
708c91a719dSKyungmin Park 		goto fail;
709c91a719dSKyungmin Park 	}
710c91a719dSKyungmin Park 
711c91a719dSKyungmin Park 	if (vol->name_len > UBI_VOL_NAME_MAX) {
7120195a7bbSHeiko Schocher 		ubi_err(ubi, "too long volume name, max is %d",
7130195a7bbSHeiko Schocher 			UBI_VOL_NAME_MAX);
714c91a719dSKyungmin Park 		goto fail;
715c91a719dSKyungmin Park 	}
716c91a719dSKyungmin Park 
717c91a719dSKyungmin Park 	n = strnlen(vol->name, vol->name_len + 1);
718c91a719dSKyungmin Park 	if (n != vol->name_len) {
7190195a7bbSHeiko Schocher 		ubi_err(ubi, "bad name_len %lld", n);
720c91a719dSKyungmin Park 		goto fail;
721c91a719dSKyungmin Park 	}
722c91a719dSKyungmin Park 
723c91a719dSKyungmin Park 	n = (long long)vol->used_ebs * vol->usable_leb_size;
724c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
725c91a719dSKyungmin Park 		if (vol->corrupted) {
7260195a7bbSHeiko Schocher 			ubi_err(ubi, "corrupted dynamic volume");
727c91a719dSKyungmin Park 			goto fail;
728c91a719dSKyungmin Park 		}
729c91a719dSKyungmin Park 		if (vol->used_ebs != vol->reserved_pebs) {
7300195a7bbSHeiko Schocher 			ubi_err(ubi, "bad used_ebs");
731c91a719dSKyungmin Park 			goto fail;
732c91a719dSKyungmin Park 		}
733c91a719dSKyungmin Park 		if (vol->last_eb_bytes != vol->usable_leb_size) {
7340195a7bbSHeiko Schocher 			ubi_err(ubi, "bad last_eb_bytes");
735c91a719dSKyungmin Park 			goto fail;
736c91a719dSKyungmin Park 		}
737c91a719dSKyungmin Park 		if (vol->used_bytes != n) {
7380195a7bbSHeiko Schocher 			ubi_err(ubi, "bad used_bytes");
739c91a719dSKyungmin Park 			goto fail;
740c91a719dSKyungmin Park 		}
741c91a719dSKyungmin Park 	} else {
742c91a719dSKyungmin Park 		if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
7430195a7bbSHeiko Schocher 			ubi_err(ubi, "bad used_ebs");
744c91a719dSKyungmin Park 			goto fail;
745c91a719dSKyungmin Park 		}
746c91a719dSKyungmin Park 		if (vol->last_eb_bytes < 0 ||
747c91a719dSKyungmin Park 		    vol->last_eb_bytes > vol->usable_leb_size) {
7480195a7bbSHeiko Schocher 			ubi_err(ubi, "bad last_eb_bytes");
749c91a719dSKyungmin Park 			goto fail;
750c91a719dSKyungmin Park 		}
751c91a719dSKyungmin Park 		if (vol->used_bytes < 0 || vol->used_bytes > n ||
752c91a719dSKyungmin Park 		    vol->used_bytes < n - vol->usable_leb_size) {
7530195a7bbSHeiko Schocher 			ubi_err(ubi, "bad used_bytes");
754c91a719dSKyungmin Park 			goto fail;
755c91a719dSKyungmin Park 		}
756c91a719dSKyungmin Park 	}
757c91a719dSKyungmin Park 
758c91a719dSKyungmin Park 	alignment  = be32_to_cpu(ubi->vtbl[vol_id].alignment);
759c91a719dSKyungmin Park 	data_pad   = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
760c91a719dSKyungmin Park 	name_len   = be16_to_cpu(ubi->vtbl[vol_id].name_len);
761c91a719dSKyungmin Park 	upd_marker = ubi->vtbl[vol_id].upd_marker;
762c91a719dSKyungmin Park 	name       = &ubi->vtbl[vol_id].name[0];
763c91a719dSKyungmin Park 	if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
764c91a719dSKyungmin Park 		vol_type = UBI_DYNAMIC_VOLUME;
765c91a719dSKyungmin Park 	else
766c91a719dSKyungmin Park 		vol_type = UBI_STATIC_VOLUME;
767c91a719dSKyungmin Park 
768c91a719dSKyungmin Park 	if (alignment != vol->alignment || data_pad != vol->data_pad ||
769c91a719dSKyungmin Park 	    upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
770c91a719dSKyungmin Park 	    name_len != vol->name_len || strncmp(name, vol->name, name_len)) {
7710195a7bbSHeiko Schocher 		ubi_err(ubi, "volume info is different");
772c91a719dSKyungmin Park 		goto fail;
773c91a719dSKyungmin Park 	}
774c91a719dSKyungmin Park 
775c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
776ff94bc40SHeiko Schocher 	return 0;
777c91a719dSKyungmin Park 
778c91a719dSKyungmin Park fail:
7790195a7bbSHeiko Schocher 	ubi_err(ubi, "self-check failed for volume %d", vol_id);
780ff94bc40SHeiko Schocher 	if (vol)
781ff94bc40SHeiko Schocher 		ubi_dump_vol_info(vol);
782ff94bc40SHeiko Schocher 	ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
783ff94bc40SHeiko Schocher 	dump_stack();
784c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
785ff94bc40SHeiko Schocher 	return -EINVAL;
786c91a719dSKyungmin Park }
787c91a719dSKyungmin Park 
788c91a719dSKyungmin Park /**
789ff94bc40SHeiko Schocher  * self_check_volumes - check information about all volumes.
790c91a719dSKyungmin Park  * @ubi: UBI device description object
791ff94bc40SHeiko Schocher  *
792ff94bc40SHeiko Schocher  * Returns zero if volumes are all right and a a negative error code if not.
793c91a719dSKyungmin Park  */
self_check_volumes(struct ubi_device * ubi)794ff94bc40SHeiko Schocher static int self_check_volumes(struct ubi_device *ubi)
795c91a719dSKyungmin Park {
796ff94bc40SHeiko Schocher 	int i, err = 0;
797c91a719dSKyungmin Park 
798ff94bc40SHeiko Schocher 	if (!ubi_dbg_chk_gen(ubi))
799ff94bc40SHeiko Schocher 		return 0;
800ff94bc40SHeiko Schocher 
801ff94bc40SHeiko Schocher 	for (i = 0; i < ubi->vtbl_slots; i++) {
802ff94bc40SHeiko Schocher 		err = self_check_volume(ubi, i);
803ff94bc40SHeiko Schocher 		if (err)
804ff94bc40SHeiko Schocher 			break;
805c91a719dSKyungmin Park 	}
806ff94bc40SHeiko Schocher 
807ff94bc40SHeiko Schocher 	return err;
808ff94bc40SHeiko Schocher }
809