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