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