xref: /rk3399_rockchip-uboot/drivers/mtd/ubi/vmt.c (revision c91a719daa331b5856109313371e4ece5ec06d96)
1*c91a719dSKyungmin Park /*
2*c91a719dSKyungmin Park  * Copyright (c) International Business Machines Corp., 2006
3*c91a719dSKyungmin Park  *
4*c91a719dSKyungmin Park  * This program is free software; you can redistribute it and/or modify
5*c91a719dSKyungmin Park  * it under the terms of the GNU General Public License as published by
6*c91a719dSKyungmin Park  * the Free Software Foundation;  either version 2 of the License, or
7*c91a719dSKyungmin Park  * (at your option) any later version.
8*c91a719dSKyungmin Park  *
9*c91a719dSKyungmin Park  * This program is distributed in the hope that it will be useful,
10*c91a719dSKyungmin Park  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*c91a719dSKyungmin Park  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12*c91a719dSKyungmin Park  * the GNU General Public License for more details.
13*c91a719dSKyungmin Park  *
14*c91a719dSKyungmin Park  * You should have received a copy of the GNU General Public License
15*c91a719dSKyungmin Park  * along with this program; if not, write to the Free Software
16*c91a719dSKyungmin Park  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*c91a719dSKyungmin Park  *
18*c91a719dSKyungmin Park  * Author: Artem Bityutskiy (Битюцкий Артём)
19*c91a719dSKyungmin Park  */
20*c91a719dSKyungmin Park 
21*c91a719dSKyungmin Park /*
22*c91a719dSKyungmin Park  * This file contains implementation of volume creation, deletion, updating and
23*c91a719dSKyungmin Park  * resizing.
24*c91a719dSKyungmin Park  */
25*c91a719dSKyungmin Park 
26*c91a719dSKyungmin Park #ifdef UBI_LINUX
27*c91a719dSKyungmin Park #include <linux/err.h>
28*c91a719dSKyungmin Park #include <asm/div64.h>
29*c91a719dSKyungmin Park #endif
30*c91a719dSKyungmin Park 
31*c91a719dSKyungmin Park #include <ubi_uboot.h>
32*c91a719dSKyungmin Park #include "ubi.h"
33*c91a719dSKyungmin Park 
34*c91a719dSKyungmin Park #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
35*c91a719dSKyungmin Park static void paranoid_check_volumes(struct ubi_device *ubi);
36*c91a719dSKyungmin Park #else
37*c91a719dSKyungmin Park #define paranoid_check_volumes(ubi)
38*c91a719dSKyungmin Park #endif
39*c91a719dSKyungmin Park 
40*c91a719dSKyungmin Park #ifdef UBI_LINUX
41*c91a719dSKyungmin Park static ssize_t vol_attribute_show(struct device *dev,
42*c91a719dSKyungmin Park 				  struct device_attribute *attr, char *buf);
43*c91a719dSKyungmin Park 
44*c91a719dSKyungmin Park /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
45*c91a719dSKyungmin Park static struct device_attribute attr_vol_reserved_ebs =
46*c91a719dSKyungmin Park 	__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
47*c91a719dSKyungmin Park static struct device_attribute attr_vol_type =
48*c91a719dSKyungmin Park 	__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
49*c91a719dSKyungmin Park static struct device_attribute attr_vol_name =
50*c91a719dSKyungmin Park 	__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
51*c91a719dSKyungmin Park static struct device_attribute attr_vol_corrupted =
52*c91a719dSKyungmin Park 	__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
53*c91a719dSKyungmin Park static struct device_attribute attr_vol_alignment =
54*c91a719dSKyungmin Park 	__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
55*c91a719dSKyungmin Park static struct device_attribute attr_vol_usable_eb_size =
56*c91a719dSKyungmin Park 	__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
57*c91a719dSKyungmin Park static struct device_attribute attr_vol_data_bytes =
58*c91a719dSKyungmin Park 	__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
59*c91a719dSKyungmin Park static struct device_attribute attr_vol_upd_marker =
60*c91a719dSKyungmin Park 	__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
61*c91a719dSKyungmin Park 
62*c91a719dSKyungmin Park /*
63*c91a719dSKyungmin Park  * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'.
64*c91a719dSKyungmin Park  *
65*c91a719dSKyungmin Park  * Consider a situation:
66*c91a719dSKyungmin Park  * A. process 1 opens a sysfs file related to volume Y, say
67*c91a719dSKyungmin Park  *    /<sysfs>/class/ubi/ubiX_Y/reserved_ebs;
68*c91a719dSKyungmin Park  * B. process 2 removes volume Y;
69*c91a719dSKyungmin Park  * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
70*c91a719dSKyungmin Park  *
71*c91a719dSKyungmin Park  * In this situation, this function will return %-ENODEV because it will find
72*c91a719dSKyungmin Park  * out that the volume was removed from the @ubi->volumes array.
73*c91a719dSKyungmin Park  */
74*c91a719dSKyungmin Park static ssize_t vol_attribute_show(struct device *dev,
75*c91a719dSKyungmin Park 				  struct device_attribute *attr, char *buf)
76*c91a719dSKyungmin Park {
77*c91a719dSKyungmin Park 	int ret;
78*c91a719dSKyungmin Park 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
79*c91a719dSKyungmin Park 	struct ubi_device *ubi;
80*c91a719dSKyungmin Park 
81*c91a719dSKyungmin Park 	ubi = ubi_get_device(vol->ubi->ubi_num);
82*c91a719dSKyungmin Park 	if (!ubi)
83*c91a719dSKyungmin Park 		return -ENODEV;
84*c91a719dSKyungmin Park 
85*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
86*c91a719dSKyungmin Park 	if (!ubi->volumes[vol->vol_id]) {
87*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
88*c91a719dSKyungmin Park 		ubi_put_device(ubi);
89*c91a719dSKyungmin Park 		return -ENODEV;
90*c91a719dSKyungmin Park 	}
91*c91a719dSKyungmin Park 	/* Take a reference to prevent volume removal */
92*c91a719dSKyungmin Park 	vol->ref_count += 1;
93*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
94*c91a719dSKyungmin Park 
95*c91a719dSKyungmin Park 	if (attr == &attr_vol_reserved_ebs)
96*c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->reserved_pebs);
97*c91a719dSKyungmin Park 	else if (attr == &attr_vol_type) {
98*c91a719dSKyungmin Park 		const char *tp;
99*c91a719dSKyungmin Park 
100*c91a719dSKyungmin Park 		if (vol->vol_type == UBI_DYNAMIC_VOLUME)
101*c91a719dSKyungmin Park 			tp = "dynamic";
102*c91a719dSKyungmin Park 		else
103*c91a719dSKyungmin Park 			tp = "static";
104*c91a719dSKyungmin Park 		ret = sprintf(buf, "%s\n", tp);
105*c91a719dSKyungmin Park 	} else if (attr == &attr_vol_name)
106*c91a719dSKyungmin Park 		ret = sprintf(buf, "%s\n", vol->name);
107*c91a719dSKyungmin Park 	else if (attr == &attr_vol_corrupted)
108*c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->corrupted);
109*c91a719dSKyungmin Park 	else if (attr == &attr_vol_alignment)
110*c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->alignment);
111*c91a719dSKyungmin Park 	else if (attr == &attr_vol_usable_eb_size)
112*c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->usable_leb_size);
113*c91a719dSKyungmin Park 	else if (attr == &attr_vol_data_bytes)
114*c91a719dSKyungmin Park 		ret = sprintf(buf, "%lld\n", vol->used_bytes);
115*c91a719dSKyungmin Park 	else if (attr == &attr_vol_upd_marker)
116*c91a719dSKyungmin Park 		ret = sprintf(buf, "%d\n", vol->upd_marker);
117*c91a719dSKyungmin Park 	else
118*c91a719dSKyungmin Park 		/* This must be a bug */
119*c91a719dSKyungmin Park 		ret = -EINVAL;
120*c91a719dSKyungmin Park 
121*c91a719dSKyungmin Park 	/* We've done the operation, drop volume and UBI device references */
122*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
123*c91a719dSKyungmin Park 	vol->ref_count -= 1;
124*c91a719dSKyungmin Park 	ubi_assert(vol->ref_count >= 0);
125*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
126*c91a719dSKyungmin Park 	ubi_put_device(ubi);
127*c91a719dSKyungmin Park 	return ret;
128*c91a719dSKyungmin Park }
129*c91a719dSKyungmin Park #endif
130*c91a719dSKyungmin Park 
131*c91a719dSKyungmin Park /* Release method for volume devices */
132*c91a719dSKyungmin Park static void vol_release(struct device *dev)
133*c91a719dSKyungmin Park {
134*c91a719dSKyungmin Park 	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
135*c91a719dSKyungmin Park 
136*c91a719dSKyungmin Park 	kfree(vol);
137*c91a719dSKyungmin Park }
138*c91a719dSKyungmin Park 
139*c91a719dSKyungmin Park #ifdef UBI_LINUX
140*c91a719dSKyungmin Park /**
141*c91a719dSKyungmin Park  * volume_sysfs_init - initialize sysfs for new volume.
142*c91a719dSKyungmin Park  * @ubi: UBI device description object
143*c91a719dSKyungmin Park  * @vol: volume description object
144*c91a719dSKyungmin Park  *
145*c91a719dSKyungmin Park  * This function returns zero in case of success and a negative error code in
146*c91a719dSKyungmin Park  * case of failure.
147*c91a719dSKyungmin Park  *
148*c91a719dSKyungmin Park  * Note, this function does not free allocated resources in case of failure -
149*c91a719dSKyungmin Park  * the caller does it. This is because this would cause release() here and the
150*c91a719dSKyungmin Park  * caller would oops.
151*c91a719dSKyungmin Park  */
152*c91a719dSKyungmin Park static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
153*c91a719dSKyungmin Park {
154*c91a719dSKyungmin Park 	int err;
155*c91a719dSKyungmin Park 
156*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
157*c91a719dSKyungmin Park 	if (err)
158*c91a719dSKyungmin Park 		return err;
159*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_type);
160*c91a719dSKyungmin Park 	if (err)
161*c91a719dSKyungmin Park 		return err;
162*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_name);
163*c91a719dSKyungmin Park 	if (err)
164*c91a719dSKyungmin Park 		return err;
165*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_corrupted);
166*c91a719dSKyungmin Park 	if (err)
167*c91a719dSKyungmin Park 		return err;
168*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_alignment);
169*c91a719dSKyungmin Park 	if (err)
170*c91a719dSKyungmin Park 		return err;
171*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
172*c91a719dSKyungmin Park 	if (err)
173*c91a719dSKyungmin Park 		return err;
174*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_data_bytes);
175*c91a719dSKyungmin Park 	if (err)
176*c91a719dSKyungmin Park 		return err;
177*c91a719dSKyungmin Park 	err = device_create_file(&vol->dev, &attr_vol_upd_marker);
178*c91a719dSKyungmin Park 	return err;
179*c91a719dSKyungmin Park }
180*c91a719dSKyungmin Park 
181*c91a719dSKyungmin Park /**
182*c91a719dSKyungmin Park  * volume_sysfs_close - close sysfs for a volume.
183*c91a719dSKyungmin Park  * @vol: volume description object
184*c91a719dSKyungmin Park  */
185*c91a719dSKyungmin Park static void volume_sysfs_close(struct ubi_volume *vol)
186*c91a719dSKyungmin Park {
187*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_upd_marker);
188*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_data_bytes);
189*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
190*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_alignment);
191*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_corrupted);
192*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_name);
193*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_type);
194*c91a719dSKyungmin Park 	device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
195*c91a719dSKyungmin Park 	device_unregister(&vol->dev);
196*c91a719dSKyungmin Park }
197*c91a719dSKyungmin Park #endif
198*c91a719dSKyungmin Park 
199*c91a719dSKyungmin Park /**
200*c91a719dSKyungmin Park  * ubi_create_volume - create volume.
201*c91a719dSKyungmin Park  * @ubi: UBI device description object
202*c91a719dSKyungmin Park  * @req: volume creation request
203*c91a719dSKyungmin Park  *
204*c91a719dSKyungmin Park  * This function creates volume described by @req. If @req->vol_id id
205*c91a719dSKyungmin Park  * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume
206*c91a719dSKyungmin Park  * and saves it in @req->vol_id. Returns zero in case of success and a negative
207*c91a719dSKyungmin Park  * error code in case of failure. Note, the caller has to have the
208*c91a719dSKyungmin Park  * @ubi->volumes_mutex locked.
209*c91a719dSKyungmin Park  */
210*c91a719dSKyungmin Park int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
211*c91a719dSKyungmin Park {
212*c91a719dSKyungmin Park 	int i, err, vol_id = req->vol_id, dont_free = 0;
213*c91a719dSKyungmin Park 	struct ubi_volume *vol;
214*c91a719dSKyungmin Park 	struct ubi_vtbl_record vtbl_rec;
215*c91a719dSKyungmin Park 	uint64_t bytes;
216*c91a719dSKyungmin Park 	dev_t dev;
217*c91a719dSKyungmin Park 
218*c91a719dSKyungmin Park 	if (ubi->ro_mode)
219*c91a719dSKyungmin Park 		return -EROFS;
220*c91a719dSKyungmin Park 
221*c91a719dSKyungmin Park 	vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
222*c91a719dSKyungmin Park 	if (!vol)
223*c91a719dSKyungmin Park 		return -ENOMEM;
224*c91a719dSKyungmin Park 
225*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
226*c91a719dSKyungmin Park 	if (vol_id == UBI_VOL_NUM_AUTO) {
227*c91a719dSKyungmin Park 		/* Find unused volume ID */
228*c91a719dSKyungmin Park 		dbg_msg("search for vacant volume ID");
229*c91a719dSKyungmin Park 		for (i = 0; i < ubi->vtbl_slots; i++)
230*c91a719dSKyungmin Park 			if (!ubi->volumes[i]) {
231*c91a719dSKyungmin Park 				vol_id = i;
232*c91a719dSKyungmin Park 				break;
233*c91a719dSKyungmin Park 			}
234*c91a719dSKyungmin Park 
235*c91a719dSKyungmin Park 		if (vol_id == UBI_VOL_NUM_AUTO) {
236*c91a719dSKyungmin Park 			dbg_err("out of volume IDs");
237*c91a719dSKyungmin Park 			err = -ENFILE;
238*c91a719dSKyungmin Park 			goto out_unlock;
239*c91a719dSKyungmin Park 		}
240*c91a719dSKyungmin Park 		req->vol_id = vol_id;
241*c91a719dSKyungmin Park 	}
242*c91a719dSKyungmin Park 
243*c91a719dSKyungmin Park 	dbg_msg("volume ID %d, %llu bytes, type %d, name %s",
244*c91a719dSKyungmin Park 		vol_id, (unsigned long long)req->bytes,
245*c91a719dSKyungmin Park 		(int)req->vol_type, req->name);
246*c91a719dSKyungmin Park 
247*c91a719dSKyungmin Park 	/* Ensure that this volume does not exist */
248*c91a719dSKyungmin Park 	err = -EEXIST;
249*c91a719dSKyungmin Park 	if (ubi->volumes[vol_id]) {
250*c91a719dSKyungmin Park 		dbg_err("volume %d already exists", vol_id);
251*c91a719dSKyungmin Park 		goto out_unlock;
252*c91a719dSKyungmin Park 	}
253*c91a719dSKyungmin Park 
254*c91a719dSKyungmin Park 	/* Ensure that the name is unique */
255*c91a719dSKyungmin Park 	for (i = 0; i < ubi->vtbl_slots; i++)
256*c91a719dSKyungmin Park 		if (ubi->volumes[i] &&
257*c91a719dSKyungmin Park 		    ubi->volumes[i]->name_len == req->name_len &&
258*c91a719dSKyungmin Park 		    !strcmp(ubi->volumes[i]->name, req->name)) {
259*c91a719dSKyungmin Park 			dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
260*c91a719dSKyungmin Park 			goto out_unlock;
261*c91a719dSKyungmin Park 		}
262*c91a719dSKyungmin Park 
263*c91a719dSKyungmin Park         /* Calculate how many eraseblocks are requested */
264*c91a719dSKyungmin Park 	vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
265*c91a719dSKyungmin Park 	bytes = req->bytes;
266*c91a719dSKyungmin Park 	if (do_div(bytes, vol->usable_leb_size))
267*c91a719dSKyungmin Park 		vol->reserved_pebs = 1;
268*c91a719dSKyungmin Park 	vol->reserved_pebs += bytes;
269*c91a719dSKyungmin Park 
270*c91a719dSKyungmin Park 	/* Reserve physical eraseblocks */
271*c91a719dSKyungmin Park 	if (vol->reserved_pebs > ubi->avail_pebs) {
272*c91a719dSKyungmin Park 		dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
273*c91a719dSKyungmin Park 		err = -ENOSPC;
274*c91a719dSKyungmin Park 		goto out_unlock;
275*c91a719dSKyungmin Park 	}
276*c91a719dSKyungmin Park 	ubi->avail_pebs -= vol->reserved_pebs;
277*c91a719dSKyungmin Park 	ubi->rsvd_pebs += vol->reserved_pebs;
278*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
279*c91a719dSKyungmin Park 
280*c91a719dSKyungmin Park 	vol->vol_id    = vol_id;
281*c91a719dSKyungmin Park 	vol->alignment = req->alignment;
282*c91a719dSKyungmin Park 	vol->data_pad  = ubi->leb_size % vol->alignment;
283*c91a719dSKyungmin Park 	vol->vol_type  = req->vol_type;
284*c91a719dSKyungmin Park 	vol->name_len  = req->name_len;
285*c91a719dSKyungmin Park 	memcpy(vol->name, req->name, vol->name_len + 1);
286*c91a719dSKyungmin Park 	vol->ubi = ubi;
287*c91a719dSKyungmin Park 
288*c91a719dSKyungmin Park 	/*
289*c91a719dSKyungmin Park 	 * Finish all pending erases because there may be some LEBs belonging
290*c91a719dSKyungmin Park 	 * to the same volume ID.
291*c91a719dSKyungmin Park 	 */
292*c91a719dSKyungmin Park 	err = ubi_wl_flush(ubi);
293*c91a719dSKyungmin Park 	if (err)
294*c91a719dSKyungmin Park 		goto out_acc;
295*c91a719dSKyungmin Park 
296*c91a719dSKyungmin Park 	vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
297*c91a719dSKyungmin Park 	if (!vol->eba_tbl) {
298*c91a719dSKyungmin Park 		err = -ENOMEM;
299*c91a719dSKyungmin Park 		goto out_acc;
300*c91a719dSKyungmin Park 	}
301*c91a719dSKyungmin Park 
302*c91a719dSKyungmin Park 	for (i = 0; i < vol->reserved_pebs; i++)
303*c91a719dSKyungmin Park 		vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
304*c91a719dSKyungmin Park 
305*c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
306*c91a719dSKyungmin Park 		vol->used_ebs = vol->reserved_pebs;
307*c91a719dSKyungmin Park 		vol->last_eb_bytes = vol->usable_leb_size;
308*c91a719dSKyungmin Park 		vol->used_bytes =
309*c91a719dSKyungmin Park 			(long long)vol->used_ebs * vol->usable_leb_size;
310*c91a719dSKyungmin Park 	} else {
311*c91a719dSKyungmin Park 		bytes = vol->used_bytes;
312*c91a719dSKyungmin Park 		vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
313*c91a719dSKyungmin Park 		vol->used_ebs = bytes;
314*c91a719dSKyungmin Park 		if (vol->last_eb_bytes)
315*c91a719dSKyungmin Park 			vol->used_ebs += 1;
316*c91a719dSKyungmin Park 		else
317*c91a719dSKyungmin Park 			vol->last_eb_bytes = vol->usable_leb_size;
318*c91a719dSKyungmin Park 	}
319*c91a719dSKyungmin Park 
320*c91a719dSKyungmin Park 	/* Register character device for the volume */
321*c91a719dSKyungmin Park 	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
322*c91a719dSKyungmin Park 	vol->cdev.owner = THIS_MODULE;
323*c91a719dSKyungmin Park 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
324*c91a719dSKyungmin Park 	err = cdev_add(&vol->cdev, dev, 1);
325*c91a719dSKyungmin Park 	if (err) {
326*c91a719dSKyungmin Park 		ubi_err("cannot add character device");
327*c91a719dSKyungmin Park 		goto out_mapping;
328*c91a719dSKyungmin Park 	}
329*c91a719dSKyungmin Park 
330*c91a719dSKyungmin Park 	err = ubi_create_gluebi(ubi, vol);
331*c91a719dSKyungmin Park 	if (err)
332*c91a719dSKyungmin Park 		goto out_cdev;
333*c91a719dSKyungmin Park 
334*c91a719dSKyungmin Park 	vol->dev.release = vol_release;
335*c91a719dSKyungmin Park 	vol->dev.parent = &ubi->dev;
336*c91a719dSKyungmin Park 	vol->dev.devt = dev;
337*c91a719dSKyungmin Park 	vol->dev.class = ubi_class;
338*c91a719dSKyungmin Park 
339*c91a719dSKyungmin Park 	sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
340*c91a719dSKyungmin Park 	err = device_register(&vol->dev);
341*c91a719dSKyungmin Park 	if (err) {
342*c91a719dSKyungmin Park 		ubi_err("cannot register device");
343*c91a719dSKyungmin Park 		goto out_gluebi;
344*c91a719dSKyungmin Park 	}
345*c91a719dSKyungmin Park 
346*c91a719dSKyungmin Park 	err = volume_sysfs_init(ubi, vol);
347*c91a719dSKyungmin Park 	if (err)
348*c91a719dSKyungmin Park 		goto out_sysfs;
349*c91a719dSKyungmin Park 
350*c91a719dSKyungmin Park 	/* Fill volume table record */
351*c91a719dSKyungmin Park 	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
352*c91a719dSKyungmin Park 	vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
353*c91a719dSKyungmin Park 	vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
354*c91a719dSKyungmin Park 	vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
355*c91a719dSKyungmin Park 	vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
356*c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
357*c91a719dSKyungmin Park 		vtbl_rec.vol_type = UBI_VID_DYNAMIC;
358*c91a719dSKyungmin Park 	else
359*c91a719dSKyungmin Park 		vtbl_rec.vol_type = UBI_VID_STATIC;
360*c91a719dSKyungmin Park 	memcpy(vtbl_rec.name, vol->name, vol->name_len + 1);
361*c91a719dSKyungmin Park 
362*c91a719dSKyungmin Park 	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
363*c91a719dSKyungmin Park 	if (err)
364*c91a719dSKyungmin Park 		goto out_sysfs;
365*c91a719dSKyungmin Park 
366*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
367*c91a719dSKyungmin Park 	ubi->volumes[vol_id] = vol;
368*c91a719dSKyungmin Park 	ubi->vol_count += 1;
369*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
370*c91a719dSKyungmin Park 
371*c91a719dSKyungmin Park 	paranoid_check_volumes(ubi);
372*c91a719dSKyungmin Park 	return 0;
373*c91a719dSKyungmin Park 
374*c91a719dSKyungmin Park out_sysfs:
375*c91a719dSKyungmin Park 	/*
376*c91a719dSKyungmin Park 	 * We have registered our device, we should not free the volume*
377*c91a719dSKyungmin Park 	 * description object in this function in case of an error - it is
378*c91a719dSKyungmin Park 	 * freed by the release function.
379*c91a719dSKyungmin Park 	 *
380*c91a719dSKyungmin Park 	 * Get device reference to prevent the release function from being
381*c91a719dSKyungmin Park 	 * called just after sysfs has been closed.
382*c91a719dSKyungmin Park 	 */
383*c91a719dSKyungmin Park 	dont_free = 1;
384*c91a719dSKyungmin Park 	get_device(&vol->dev);
385*c91a719dSKyungmin Park 	volume_sysfs_close(vol);
386*c91a719dSKyungmin Park out_gluebi:
387*c91a719dSKyungmin Park 	if (ubi_destroy_gluebi(vol))
388*c91a719dSKyungmin Park 		dbg_err("cannot destroy gluebi for volume %d:%d",
389*c91a719dSKyungmin Park 			ubi->ubi_num, vol_id);
390*c91a719dSKyungmin Park out_cdev:
391*c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
392*c91a719dSKyungmin Park out_mapping:
393*c91a719dSKyungmin Park 	kfree(vol->eba_tbl);
394*c91a719dSKyungmin Park out_acc:
395*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
396*c91a719dSKyungmin Park 	ubi->rsvd_pebs -= vol->reserved_pebs;
397*c91a719dSKyungmin Park 	ubi->avail_pebs += vol->reserved_pebs;
398*c91a719dSKyungmin Park out_unlock:
399*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
400*c91a719dSKyungmin Park 	if (dont_free)
401*c91a719dSKyungmin Park 		put_device(&vol->dev);
402*c91a719dSKyungmin Park 	else
403*c91a719dSKyungmin Park 		kfree(vol);
404*c91a719dSKyungmin Park 	ubi_err("cannot create volume %d, error %d", vol_id, err);
405*c91a719dSKyungmin Park 	return err;
406*c91a719dSKyungmin Park }
407*c91a719dSKyungmin Park 
408*c91a719dSKyungmin Park /**
409*c91a719dSKyungmin Park  * ubi_remove_volume - remove volume.
410*c91a719dSKyungmin Park  * @desc: volume descriptor
411*c91a719dSKyungmin Park  *
412*c91a719dSKyungmin Park  * This function removes volume described by @desc. The volume has to be opened
413*c91a719dSKyungmin Park  * in "exclusive" mode. Returns zero in case of success and a negative error
414*c91a719dSKyungmin Park  * code in case of failure. The caller has to have the @ubi->volumes_mutex
415*c91a719dSKyungmin Park  * locked.
416*c91a719dSKyungmin Park  */
417*c91a719dSKyungmin Park int ubi_remove_volume(struct ubi_volume_desc *desc)
418*c91a719dSKyungmin Park {
419*c91a719dSKyungmin Park 	struct ubi_volume *vol = desc->vol;
420*c91a719dSKyungmin Park 	struct ubi_device *ubi = vol->ubi;
421*c91a719dSKyungmin Park 	int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
422*c91a719dSKyungmin Park 
423*c91a719dSKyungmin Park 	dbg_msg("remove UBI volume %d", vol_id);
424*c91a719dSKyungmin Park 	ubi_assert(desc->mode == UBI_EXCLUSIVE);
425*c91a719dSKyungmin Park 	ubi_assert(vol == ubi->volumes[vol_id]);
426*c91a719dSKyungmin Park 
427*c91a719dSKyungmin Park 	if (ubi->ro_mode)
428*c91a719dSKyungmin Park 		return -EROFS;
429*c91a719dSKyungmin Park 
430*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
431*c91a719dSKyungmin Park 	if (vol->ref_count > 1) {
432*c91a719dSKyungmin Park 		/*
433*c91a719dSKyungmin Park 		 * The volume is busy, probably someone is reading one of its
434*c91a719dSKyungmin Park 		 * sysfs files.
435*c91a719dSKyungmin Park 		 */
436*c91a719dSKyungmin Park 		err = -EBUSY;
437*c91a719dSKyungmin Park 		goto out_unlock;
438*c91a719dSKyungmin Park 	}
439*c91a719dSKyungmin Park 	ubi->volumes[vol_id] = NULL;
440*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
441*c91a719dSKyungmin Park 
442*c91a719dSKyungmin Park 	err = ubi_destroy_gluebi(vol);
443*c91a719dSKyungmin Park 	if (err)
444*c91a719dSKyungmin Park 		goto out_err;
445*c91a719dSKyungmin Park 
446*c91a719dSKyungmin Park 	err = ubi_change_vtbl_record(ubi, vol_id, NULL);
447*c91a719dSKyungmin Park 	if (err)
448*c91a719dSKyungmin Park 		goto out_err;
449*c91a719dSKyungmin Park 
450*c91a719dSKyungmin Park 	for (i = 0; i < vol->reserved_pebs; i++) {
451*c91a719dSKyungmin Park 		err = ubi_eba_unmap_leb(ubi, vol, i);
452*c91a719dSKyungmin Park 		if (err)
453*c91a719dSKyungmin Park 			goto out_err;
454*c91a719dSKyungmin Park 	}
455*c91a719dSKyungmin Park 
456*c91a719dSKyungmin Park 	kfree(vol->eba_tbl);
457*c91a719dSKyungmin Park 	vol->eba_tbl = NULL;
458*c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
459*c91a719dSKyungmin Park 	volume_sysfs_close(vol);
460*c91a719dSKyungmin Park 
461*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
462*c91a719dSKyungmin Park 	ubi->rsvd_pebs -= reserved_pebs;
463*c91a719dSKyungmin Park 	ubi->avail_pebs += reserved_pebs;
464*c91a719dSKyungmin Park 	i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
465*c91a719dSKyungmin Park 	if (i > 0) {
466*c91a719dSKyungmin Park 		i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
467*c91a719dSKyungmin Park 		ubi->avail_pebs -= i;
468*c91a719dSKyungmin Park 		ubi->rsvd_pebs += i;
469*c91a719dSKyungmin Park 		ubi->beb_rsvd_pebs += i;
470*c91a719dSKyungmin Park 		if (i > 0)
471*c91a719dSKyungmin Park 			ubi_msg("reserve more %d PEBs", i);
472*c91a719dSKyungmin Park 	}
473*c91a719dSKyungmin Park 	ubi->vol_count -= 1;
474*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
475*c91a719dSKyungmin Park 
476*c91a719dSKyungmin Park 	paranoid_check_volumes(ubi);
477*c91a719dSKyungmin Park 	return 0;
478*c91a719dSKyungmin Park 
479*c91a719dSKyungmin Park out_err:
480*c91a719dSKyungmin Park 	ubi_err("cannot remove volume %d, error %d", vol_id, err);
481*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
482*c91a719dSKyungmin Park 	ubi->volumes[vol_id] = vol;
483*c91a719dSKyungmin Park out_unlock:
484*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
485*c91a719dSKyungmin Park 	return err;
486*c91a719dSKyungmin Park }
487*c91a719dSKyungmin Park 
488*c91a719dSKyungmin Park /**
489*c91a719dSKyungmin Park  * ubi_resize_volume - re-size volume.
490*c91a719dSKyungmin Park  * @desc: volume descriptor
491*c91a719dSKyungmin Park  * @reserved_pebs: new size in physical eraseblocks
492*c91a719dSKyungmin Park  *
493*c91a719dSKyungmin Park  * This function re-sizes the volume and returns zero in case of success, and a
494*c91a719dSKyungmin Park  * negative error code in case of failure. The caller has to have the
495*c91a719dSKyungmin Park  * @ubi->volumes_mutex locked.
496*c91a719dSKyungmin Park  */
497*c91a719dSKyungmin Park int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
498*c91a719dSKyungmin Park {
499*c91a719dSKyungmin Park 	int i, err, pebs, *new_mapping;
500*c91a719dSKyungmin Park 	struct ubi_volume *vol = desc->vol;
501*c91a719dSKyungmin Park 	struct ubi_device *ubi = vol->ubi;
502*c91a719dSKyungmin Park 	struct ubi_vtbl_record vtbl_rec;
503*c91a719dSKyungmin Park 	int vol_id = vol->vol_id;
504*c91a719dSKyungmin Park 
505*c91a719dSKyungmin Park 	if (ubi->ro_mode)
506*c91a719dSKyungmin Park 		return -EROFS;
507*c91a719dSKyungmin Park 
508*c91a719dSKyungmin Park 	dbg_msg("re-size volume %d to from %d to %d PEBs",
509*c91a719dSKyungmin Park 		vol_id, vol->reserved_pebs, reserved_pebs);
510*c91a719dSKyungmin Park 
511*c91a719dSKyungmin Park 	if (vol->vol_type == UBI_STATIC_VOLUME &&
512*c91a719dSKyungmin Park 	    reserved_pebs < vol->used_ebs) {
513*c91a719dSKyungmin Park 		dbg_err("too small size %d, %d LEBs contain data",
514*c91a719dSKyungmin Park 			reserved_pebs, vol->used_ebs);
515*c91a719dSKyungmin Park 		return -EINVAL;
516*c91a719dSKyungmin Park 	}
517*c91a719dSKyungmin Park 
518*c91a719dSKyungmin Park 	/* If the size is the same, we have nothing to do */
519*c91a719dSKyungmin Park 	if (reserved_pebs == vol->reserved_pebs)
520*c91a719dSKyungmin Park 		return 0;
521*c91a719dSKyungmin Park 
522*c91a719dSKyungmin Park 	new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
523*c91a719dSKyungmin Park 	if (!new_mapping)
524*c91a719dSKyungmin Park 		return -ENOMEM;
525*c91a719dSKyungmin Park 
526*c91a719dSKyungmin Park 	for (i = 0; i < reserved_pebs; i++)
527*c91a719dSKyungmin Park 		new_mapping[i] = UBI_LEB_UNMAPPED;
528*c91a719dSKyungmin Park 
529*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
530*c91a719dSKyungmin Park 	if (vol->ref_count > 1) {
531*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
532*c91a719dSKyungmin Park 		err = -EBUSY;
533*c91a719dSKyungmin Park 		goto out_free;
534*c91a719dSKyungmin Park 	}
535*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
536*c91a719dSKyungmin Park 
537*c91a719dSKyungmin Park 	/* Reserve physical eraseblocks */
538*c91a719dSKyungmin Park 	pebs = reserved_pebs - vol->reserved_pebs;
539*c91a719dSKyungmin Park 	if (pebs > 0) {
540*c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
541*c91a719dSKyungmin Park 		if (pebs > ubi->avail_pebs) {
542*c91a719dSKyungmin Park 			dbg_err("not enough PEBs: requested %d, available %d",
543*c91a719dSKyungmin Park 				pebs, ubi->avail_pebs);
544*c91a719dSKyungmin Park 			spin_unlock(&ubi->volumes_lock);
545*c91a719dSKyungmin Park 			err = -ENOSPC;
546*c91a719dSKyungmin Park 			goto out_free;
547*c91a719dSKyungmin Park 		}
548*c91a719dSKyungmin Park 		ubi->avail_pebs -= pebs;
549*c91a719dSKyungmin Park 		ubi->rsvd_pebs += pebs;
550*c91a719dSKyungmin Park 		for (i = 0; i < vol->reserved_pebs; i++)
551*c91a719dSKyungmin Park 			new_mapping[i] = vol->eba_tbl[i];
552*c91a719dSKyungmin Park 		kfree(vol->eba_tbl);
553*c91a719dSKyungmin Park 		vol->eba_tbl = new_mapping;
554*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
555*c91a719dSKyungmin Park 	}
556*c91a719dSKyungmin Park 
557*c91a719dSKyungmin Park 	/* Change volume table record */
558*c91a719dSKyungmin Park 	memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
559*c91a719dSKyungmin Park 	vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
560*c91a719dSKyungmin Park 	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
561*c91a719dSKyungmin Park 	if (err)
562*c91a719dSKyungmin Park 		goto out_acc;
563*c91a719dSKyungmin Park 
564*c91a719dSKyungmin Park 	if (pebs < 0) {
565*c91a719dSKyungmin Park 		for (i = 0; i < -pebs; i++) {
566*c91a719dSKyungmin Park 			err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
567*c91a719dSKyungmin Park 			if (err)
568*c91a719dSKyungmin Park 				goto out_acc;
569*c91a719dSKyungmin Park 		}
570*c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
571*c91a719dSKyungmin Park 		ubi->rsvd_pebs += pebs;
572*c91a719dSKyungmin Park 		ubi->avail_pebs -= pebs;
573*c91a719dSKyungmin Park 		pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
574*c91a719dSKyungmin Park 		if (pebs > 0) {
575*c91a719dSKyungmin Park 			pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs;
576*c91a719dSKyungmin Park 			ubi->avail_pebs -= pebs;
577*c91a719dSKyungmin Park 			ubi->rsvd_pebs += pebs;
578*c91a719dSKyungmin Park 			ubi->beb_rsvd_pebs += pebs;
579*c91a719dSKyungmin Park 			if (pebs > 0)
580*c91a719dSKyungmin Park 				ubi_msg("reserve more %d PEBs", pebs);
581*c91a719dSKyungmin Park 		}
582*c91a719dSKyungmin Park 		for (i = 0; i < reserved_pebs; i++)
583*c91a719dSKyungmin Park 			new_mapping[i] = vol->eba_tbl[i];
584*c91a719dSKyungmin Park 		kfree(vol->eba_tbl);
585*c91a719dSKyungmin Park 		vol->eba_tbl = new_mapping;
586*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
587*c91a719dSKyungmin Park 	}
588*c91a719dSKyungmin Park 
589*c91a719dSKyungmin Park 	vol->reserved_pebs = reserved_pebs;
590*c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
591*c91a719dSKyungmin Park 		vol->used_ebs = reserved_pebs;
592*c91a719dSKyungmin Park 		vol->last_eb_bytes = vol->usable_leb_size;
593*c91a719dSKyungmin Park 		vol->used_bytes =
594*c91a719dSKyungmin Park 			(long long)vol->used_ebs * vol->usable_leb_size;
595*c91a719dSKyungmin Park 	}
596*c91a719dSKyungmin Park 
597*c91a719dSKyungmin Park 	paranoid_check_volumes(ubi);
598*c91a719dSKyungmin Park 	return 0;
599*c91a719dSKyungmin Park 
600*c91a719dSKyungmin Park out_acc:
601*c91a719dSKyungmin Park 	if (pebs > 0) {
602*c91a719dSKyungmin Park 		spin_lock(&ubi->volumes_lock);
603*c91a719dSKyungmin Park 		ubi->rsvd_pebs -= pebs;
604*c91a719dSKyungmin Park 		ubi->avail_pebs += pebs;
605*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
606*c91a719dSKyungmin Park 	}
607*c91a719dSKyungmin Park out_free:
608*c91a719dSKyungmin Park 	kfree(new_mapping);
609*c91a719dSKyungmin Park 	return err;
610*c91a719dSKyungmin Park }
611*c91a719dSKyungmin Park 
612*c91a719dSKyungmin Park /**
613*c91a719dSKyungmin Park  * ubi_add_volume - add volume.
614*c91a719dSKyungmin Park  * @ubi: UBI device description object
615*c91a719dSKyungmin Park  * @vol: volume description object
616*c91a719dSKyungmin Park  *
617*c91a719dSKyungmin Park  * This function adds an existing volume and initializes all its data
618*c91a719dSKyungmin Park  * structures. Returns zero in case of success and a negative error code in
619*c91a719dSKyungmin Park  * case of failure.
620*c91a719dSKyungmin Park  */
621*c91a719dSKyungmin Park int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
622*c91a719dSKyungmin Park {
623*c91a719dSKyungmin Park 	int err, vol_id = vol->vol_id;
624*c91a719dSKyungmin Park 	dev_t dev;
625*c91a719dSKyungmin Park 
626*c91a719dSKyungmin Park 	dbg_msg("add volume %d", vol_id);
627*c91a719dSKyungmin Park 	ubi_dbg_dump_vol_info(vol);
628*c91a719dSKyungmin Park 
629*c91a719dSKyungmin Park 	/* Register character device for the volume */
630*c91a719dSKyungmin Park 	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
631*c91a719dSKyungmin Park 	vol->cdev.owner = THIS_MODULE;
632*c91a719dSKyungmin Park 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
633*c91a719dSKyungmin Park 	err = cdev_add(&vol->cdev, dev, 1);
634*c91a719dSKyungmin Park 	if (err) {
635*c91a719dSKyungmin Park 		ubi_err("cannot add character device for volume %d, error %d",
636*c91a719dSKyungmin Park 			vol_id, err);
637*c91a719dSKyungmin Park 		return err;
638*c91a719dSKyungmin Park 	}
639*c91a719dSKyungmin Park 
640*c91a719dSKyungmin Park 	err = ubi_create_gluebi(ubi, vol);
641*c91a719dSKyungmin Park 	if (err)
642*c91a719dSKyungmin Park 		goto out_cdev;
643*c91a719dSKyungmin Park 
644*c91a719dSKyungmin Park 	vol->dev.release = vol_release;
645*c91a719dSKyungmin Park 	vol->dev.parent = &ubi->dev;
646*c91a719dSKyungmin Park 	vol->dev.devt = dev;
647*c91a719dSKyungmin Park 	vol->dev.class = ubi_class;
648*c91a719dSKyungmin Park 	sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
649*c91a719dSKyungmin Park 	err = device_register(&vol->dev);
650*c91a719dSKyungmin Park 	if (err)
651*c91a719dSKyungmin Park 		goto out_gluebi;
652*c91a719dSKyungmin Park 
653*c91a719dSKyungmin Park 	err = volume_sysfs_init(ubi, vol);
654*c91a719dSKyungmin Park 	if (err) {
655*c91a719dSKyungmin Park 		cdev_del(&vol->cdev);
656*c91a719dSKyungmin Park 		err = ubi_destroy_gluebi(vol);
657*c91a719dSKyungmin Park 		volume_sysfs_close(vol);
658*c91a719dSKyungmin Park 		return err;
659*c91a719dSKyungmin Park 	}
660*c91a719dSKyungmin Park 
661*c91a719dSKyungmin Park 	paranoid_check_volumes(ubi);
662*c91a719dSKyungmin Park 	return 0;
663*c91a719dSKyungmin Park 
664*c91a719dSKyungmin Park out_gluebi:
665*c91a719dSKyungmin Park 	err = ubi_destroy_gluebi(vol);
666*c91a719dSKyungmin Park out_cdev:
667*c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
668*c91a719dSKyungmin Park 	return err;
669*c91a719dSKyungmin Park }
670*c91a719dSKyungmin Park 
671*c91a719dSKyungmin Park /**
672*c91a719dSKyungmin Park  * ubi_free_volume - free volume.
673*c91a719dSKyungmin Park  * @ubi: UBI device description object
674*c91a719dSKyungmin Park  * @vol: volume description object
675*c91a719dSKyungmin Park  *
676*c91a719dSKyungmin Park  * This function frees all resources for volume @vol but does not remove it.
677*c91a719dSKyungmin Park  * Used only when the UBI device is detached.
678*c91a719dSKyungmin Park  */
679*c91a719dSKyungmin Park void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
680*c91a719dSKyungmin Park {
681*c91a719dSKyungmin Park 	int err;
682*c91a719dSKyungmin Park 
683*c91a719dSKyungmin Park 	dbg_msg("free volume %d", vol->vol_id);
684*c91a719dSKyungmin Park 
685*c91a719dSKyungmin Park 	ubi->volumes[vol->vol_id] = NULL;
686*c91a719dSKyungmin Park 	err = ubi_destroy_gluebi(vol);
687*c91a719dSKyungmin Park 	cdev_del(&vol->cdev);
688*c91a719dSKyungmin Park 	volume_sysfs_close(vol);
689*c91a719dSKyungmin Park }
690*c91a719dSKyungmin Park 
691*c91a719dSKyungmin Park #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
692*c91a719dSKyungmin Park 
693*c91a719dSKyungmin Park /**
694*c91a719dSKyungmin Park  * paranoid_check_volume - check volume information.
695*c91a719dSKyungmin Park  * @ubi: UBI device description object
696*c91a719dSKyungmin Park  * @vol_id: volume ID
697*c91a719dSKyungmin Park  */
698*c91a719dSKyungmin Park static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
699*c91a719dSKyungmin Park {
700*c91a719dSKyungmin Park 	int idx = vol_id2idx(ubi, vol_id);
701*c91a719dSKyungmin Park 	int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
702*c91a719dSKyungmin Park 	const struct ubi_volume *vol;
703*c91a719dSKyungmin Park 	long long n;
704*c91a719dSKyungmin Park 	const char *name;
705*c91a719dSKyungmin Park 
706*c91a719dSKyungmin Park 	spin_lock(&ubi->volumes_lock);
707*c91a719dSKyungmin Park 	reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
708*c91a719dSKyungmin Park 	vol = ubi->volumes[idx];
709*c91a719dSKyungmin Park 
710*c91a719dSKyungmin Park 	if (!vol) {
711*c91a719dSKyungmin Park 		if (reserved_pebs) {
712*c91a719dSKyungmin Park 			ubi_err("no volume info, but volume exists");
713*c91a719dSKyungmin Park 			goto fail;
714*c91a719dSKyungmin Park 		}
715*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
716*c91a719dSKyungmin Park 		return;
717*c91a719dSKyungmin Park 	}
718*c91a719dSKyungmin Park 
719*c91a719dSKyungmin Park 	if (vol->exclusive) {
720*c91a719dSKyungmin Park 		/*
721*c91a719dSKyungmin Park 		 * The volume may be being created at the moment, do not check
722*c91a719dSKyungmin Park 		 * it (e.g., it may be in the middle of ubi_create_volume().
723*c91a719dSKyungmin Park 		 */
724*c91a719dSKyungmin Park 		spin_unlock(&ubi->volumes_lock);
725*c91a719dSKyungmin Park 		return;
726*c91a719dSKyungmin Park 	}
727*c91a719dSKyungmin Park 
728*c91a719dSKyungmin Park 	if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
729*c91a719dSKyungmin Park 	    vol->name_len < 0) {
730*c91a719dSKyungmin Park 		ubi_err("negative values");
731*c91a719dSKyungmin Park 		goto fail;
732*c91a719dSKyungmin Park 	}
733*c91a719dSKyungmin Park 	if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
734*c91a719dSKyungmin Park 		ubi_err("bad alignment");
735*c91a719dSKyungmin Park 		goto fail;
736*c91a719dSKyungmin Park 	}
737*c91a719dSKyungmin Park 
738*c91a719dSKyungmin Park 	n = vol->alignment & (ubi->min_io_size - 1);
739*c91a719dSKyungmin Park 	if (vol->alignment != 1 && n) {
740*c91a719dSKyungmin Park 		ubi_err("alignment is not multiple of min I/O unit");
741*c91a719dSKyungmin Park 		goto fail;
742*c91a719dSKyungmin Park 	}
743*c91a719dSKyungmin Park 
744*c91a719dSKyungmin Park 	n = ubi->leb_size % vol->alignment;
745*c91a719dSKyungmin Park 	if (vol->data_pad != n) {
746*c91a719dSKyungmin Park 		ubi_err("bad data_pad, has to be %lld", n);
747*c91a719dSKyungmin Park 		goto fail;
748*c91a719dSKyungmin Park 	}
749*c91a719dSKyungmin Park 
750*c91a719dSKyungmin Park 	if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
751*c91a719dSKyungmin Park 	    vol->vol_type != UBI_STATIC_VOLUME) {
752*c91a719dSKyungmin Park 		ubi_err("bad vol_type");
753*c91a719dSKyungmin Park 		goto fail;
754*c91a719dSKyungmin Park 	}
755*c91a719dSKyungmin Park 
756*c91a719dSKyungmin Park 	if (vol->upd_marker && vol->corrupted) {
757*c91a719dSKyungmin Park 		dbg_err("update marker and corrupted simultaneously");
758*c91a719dSKyungmin Park 		goto fail;
759*c91a719dSKyungmin Park 	}
760*c91a719dSKyungmin Park 
761*c91a719dSKyungmin Park 	if (vol->reserved_pebs > ubi->good_peb_count) {
762*c91a719dSKyungmin Park 		ubi_err("too large reserved_pebs");
763*c91a719dSKyungmin Park 		goto fail;
764*c91a719dSKyungmin Park 	}
765*c91a719dSKyungmin Park 
766*c91a719dSKyungmin Park 	n = ubi->leb_size - vol->data_pad;
767*c91a719dSKyungmin Park 	if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
768*c91a719dSKyungmin Park 		ubi_err("bad usable_leb_size, has to be %lld", n);
769*c91a719dSKyungmin Park 		goto fail;
770*c91a719dSKyungmin Park 	}
771*c91a719dSKyungmin Park 
772*c91a719dSKyungmin Park 	if (vol->name_len > UBI_VOL_NAME_MAX) {
773*c91a719dSKyungmin Park 		ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
774*c91a719dSKyungmin Park 		goto fail;
775*c91a719dSKyungmin Park 	}
776*c91a719dSKyungmin Park 
777*c91a719dSKyungmin Park 	if (!vol->name) {
778*c91a719dSKyungmin Park 		ubi_err("NULL volume name");
779*c91a719dSKyungmin Park 		goto fail;
780*c91a719dSKyungmin Park 	}
781*c91a719dSKyungmin Park 
782*c91a719dSKyungmin Park 	n = strnlen(vol->name, vol->name_len + 1);
783*c91a719dSKyungmin Park 	if (n != vol->name_len) {
784*c91a719dSKyungmin Park 		ubi_err("bad name_len %lld", n);
785*c91a719dSKyungmin Park 		goto fail;
786*c91a719dSKyungmin Park 	}
787*c91a719dSKyungmin Park 
788*c91a719dSKyungmin Park 	n = (long long)vol->used_ebs * vol->usable_leb_size;
789*c91a719dSKyungmin Park 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
790*c91a719dSKyungmin Park 		if (vol->corrupted) {
791*c91a719dSKyungmin Park 			ubi_err("corrupted dynamic volume");
792*c91a719dSKyungmin Park 			goto fail;
793*c91a719dSKyungmin Park 		}
794*c91a719dSKyungmin Park 		if (vol->used_ebs != vol->reserved_pebs) {
795*c91a719dSKyungmin Park 			ubi_err("bad used_ebs");
796*c91a719dSKyungmin Park 			goto fail;
797*c91a719dSKyungmin Park 		}
798*c91a719dSKyungmin Park 		if (vol->last_eb_bytes != vol->usable_leb_size) {
799*c91a719dSKyungmin Park 			ubi_err("bad last_eb_bytes");
800*c91a719dSKyungmin Park 			goto fail;
801*c91a719dSKyungmin Park 		}
802*c91a719dSKyungmin Park 		if (vol->used_bytes != n) {
803*c91a719dSKyungmin Park 			ubi_err("bad used_bytes");
804*c91a719dSKyungmin Park 			goto fail;
805*c91a719dSKyungmin Park 		}
806*c91a719dSKyungmin Park 	} else {
807*c91a719dSKyungmin Park 		if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
808*c91a719dSKyungmin Park 			ubi_err("bad used_ebs");
809*c91a719dSKyungmin Park 			goto fail;
810*c91a719dSKyungmin Park 		}
811*c91a719dSKyungmin Park 		if (vol->last_eb_bytes < 0 ||
812*c91a719dSKyungmin Park 		    vol->last_eb_bytes > vol->usable_leb_size) {
813*c91a719dSKyungmin Park 			ubi_err("bad last_eb_bytes");
814*c91a719dSKyungmin Park 			goto fail;
815*c91a719dSKyungmin Park 		}
816*c91a719dSKyungmin Park 		if (vol->used_bytes < 0 || vol->used_bytes > n ||
817*c91a719dSKyungmin Park 		    vol->used_bytes < n - vol->usable_leb_size) {
818*c91a719dSKyungmin Park 			ubi_err("bad used_bytes");
819*c91a719dSKyungmin Park 			goto fail;
820*c91a719dSKyungmin Park 		}
821*c91a719dSKyungmin Park 	}
822*c91a719dSKyungmin Park 
823*c91a719dSKyungmin Park 	alignment  = be32_to_cpu(ubi->vtbl[vol_id].alignment);
824*c91a719dSKyungmin Park 	data_pad   = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
825*c91a719dSKyungmin Park 	name_len   = be16_to_cpu(ubi->vtbl[vol_id].name_len);
826*c91a719dSKyungmin Park 	upd_marker = ubi->vtbl[vol_id].upd_marker;
827*c91a719dSKyungmin Park 	name       = &ubi->vtbl[vol_id].name[0];
828*c91a719dSKyungmin Park 	if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
829*c91a719dSKyungmin Park 		vol_type = UBI_DYNAMIC_VOLUME;
830*c91a719dSKyungmin Park 	else
831*c91a719dSKyungmin Park 		vol_type = UBI_STATIC_VOLUME;
832*c91a719dSKyungmin Park 
833*c91a719dSKyungmin Park 	if (alignment != vol->alignment || data_pad != vol->data_pad ||
834*c91a719dSKyungmin Park 	    upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
835*c91a719dSKyungmin Park 	    name_len!= vol->name_len || strncmp(name, vol->name, name_len)) {
836*c91a719dSKyungmin Park 		ubi_err("volume info is different");
837*c91a719dSKyungmin Park 		goto fail;
838*c91a719dSKyungmin Park 	}
839*c91a719dSKyungmin Park 
840*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
841*c91a719dSKyungmin Park 	return;
842*c91a719dSKyungmin Park 
843*c91a719dSKyungmin Park fail:
844*c91a719dSKyungmin Park 	ubi_err("paranoid check failed for volume %d", vol_id);
845*c91a719dSKyungmin Park 	ubi_dbg_dump_vol_info(vol);
846*c91a719dSKyungmin Park 	ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
847*c91a719dSKyungmin Park 	spin_unlock(&ubi->volumes_lock);
848*c91a719dSKyungmin Park 	BUG();
849*c91a719dSKyungmin Park }
850*c91a719dSKyungmin Park 
851*c91a719dSKyungmin Park /**
852*c91a719dSKyungmin Park  * paranoid_check_volumes - check information about all volumes.
853*c91a719dSKyungmin Park  * @ubi: UBI device description object
854*c91a719dSKyungmin Park  */
855*c91a719dSKyungmin Park static void paranoid_check_volumes(struct ubi_device *ubi)
856*c91a719dSKyungmin Park {
857*c91a719dSKyungmin Park 	int i;
858*c91a719dSKyungmin Park 
859*c91a719dSKyungmin Park 	for (i = 0; i < ubi->vtbl_slots; i++)
860*c91a719dSKyungmin Park 		paranoid_check_volume(ubi, i);
861*c91a719dSKyungmin Park }
862*c91a719dSKyungmin Park #endif
863