1801c135cSArtem B. Bityutskiy /* 2801c135cSArtem B. Bityutskiy * Copyright (c) International Business Machines Corp., 2006 3801c135cSArtem B. Bityutskiy * 4801c135cSArtem B. Bityutskiy * This program is free software; you can redistribute it and/or modify 5801c135cSArtem B. Bityutskiy * it under the terms of the GNU General Public License as published by 6801c135cSArtem B. Bityutskiy * the Free Software Foundation; either version 2 of the License, or 7801c135cSArtem B. Bityutskiy * (at your option) any later version. 8801c135cSArtem B. Bityutskiy * 9801c135cSArtem B. Bityutskiy * This program is distributed in the hope that it will be useful, 10801c135cSArtem B. Bityutskiy * but WITHOUT ANY WARRANTY; without even the implied warranty of 11801c135cSArtem B. Bityutskiy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12801c135cSArtem B. Bityutskiy * the GNU General Public License for more details. 13801c135cSArtem B. Bityutskiy * 14801c135cSArtem B. Bityutskiy * You should have received a copy of the GNU General Public License 15801c135cSArtem B. Bityutskiy * along with this program; if not, write to the Free Software 16801c135cSArtem B. Bityutskiy * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17801c135cSArtem B. Bityutskiy * 18801c135cSArtem B. Bityutskiy * Author: Artem Bityutskiy (Битюцкий Артём) 19801c135cSArtem B. Bityutskiy */ 20801c135cSArtem B. Bityutskiy 21801c135cSArtem B. Bityutskiy /* 22801c135cSArtem B. Bityutskiy * This file contains implementation of volume creation, deletion, updating and 23801c135cSArtem B. Bityutskiy * resizing. 24801c135cSArtem B. Bityutskiy */ 25801c135cSArtem B. Bityutskiy 26801c135cSArtem B. Bityutskiy #include <linux/err.h> 273013ee31SArtem Bityutskiy #include <linux/math64.h> 28801c135cSArtem B. Bityutskiy #include "ubi.h" 29801c135cSArtem B. Bityutskiy 30801c135cSArtem B. Bityutskiy #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID 31c8566350SArtem Bityutskiy static int paranoid_check_volumes(struct ubi_device *ubi); 32801c135cSArtem B. Bityutskiy #else 33c8566350SArtem Bityutskiy #define paranoid_check_volumes(ubi) 0 34801c135cSArtem B. Bityutskiy #endif 35801c135cSArtem B. Bityutskiy 36801c135cSArtem B. Bityutskiy static ssize_t vol_attribute_show(struct device *dev, 37801c135cSArtem B. Bityutskiy struct device_attribute *attr, char *buf); 38801c135cSArtem B. Bityutskiy 39801c135cSArtem B. Bityutskiy /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */ 408bc22961SArtem Bityutskiy static struct device_attribute attr_vol_reserved_ebs = 41801c135cSArtem B. Bityutskiy __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); 428bc22961SArtem Bityutskiy static struct device_attribute attr_vol_type = 43801c135cSArtem B. Bityutskiy __ATTR(type, S_IRUGO, vol_attribute_show, NULL); 448bc22961SArtem Bityutskiy static struct device_attribute attr_vol_name = 45801c135cSArtem B. Bityutskiy __ATTR(name, S_IRUGO, vol_attribute_show, NULL); 468bc22961SArtem Bityutskiy static struct device_attribute attr_vol_corrupted = 47801c135cSArtem B. Bityutskiy __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); 488bc22961SArtem Bityutskiy static struct device_attribute attr_vol_alignment = 49801c135cSArtem B. Bityutskiy __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); 508bc22961SArtem Bityutskiy static struct device_attribute attr_vol_usable_eb_size = 51801c135cSArtem B. Bityutskiy __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); 528bc22961SArtem Bityutskiy static struct device_attribute attr_vol_data_bytes = 53801c135cSArtem B. Bityutskiy __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); 548bc22961SArtem Bityutskiy static struct device_attribute attr_vol_upd_marker = 55801c135cSArtem B. Bityutskiy __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); 56801c135cSArtem B. Bityutskiy 57801c135cSArtem B. Bityutskiy /* 58801c135cSArtem B. Bityutskiy * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'. 59801c135cSArtem B. Bityutskiy * 60801c135cSArtem B. Bityutskiy * Consider a situation: 61801c135cSArtem B. Bityutskiy * A. process 1 opens a sysfs file related to volume Y, say 62801c135cSArtem B. Bityutskiy * /<sysfs>/class/ubi/ubiX_Y/reserved_ebs; 63801c135cSArtem B. Bityutskiy * B. process 2 removes volume Y; 64801c135cSArtem B. Bityutskiy * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file; 65801c135cSArtem B. Bityutskiy * 66d05c77a8SArtem Bityutskiy * In this situation, this function will return %-ENODEV because it will find 67d05c77a8SArtem Bityutskiy * out that the volume was removed from the @ubi->volumes array. 68801c135cSArtem B. Bityutskiy */ 69801c135cSArtem B. Bityutskiy static ssize_t vol_attribute_show(struct device *dev, 70801c135cSArtem B. Bityutskiy struct device_attribute *attr, char *buf) 71801c135cSArtem B. Bityutskiy { 72d05c77a8SArtem Bityutskiy int ret; 73801c135cSArtem B. Bityutskiy struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); 74e73f4459SArtem Bityutskiy struct ubi_device *ubi; 75e73f4459SArtem Bityutskiy 76e73f4459SArtem Bityutskiy ubi = ubi_get_device(vol->ubi->ubi_num); 77e73f4459SArtem Bityutskiy if (!ubi) 78e73f4459SArtem Bityutskiy return -ENODEV; 79801c135cSArtem B. Bityutskiy 80d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 81d05c77a8SArtem Bityutskiy if (!ubi->volumes[vol->vol_id]) { 82d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 83e73f4459SArtem Bityutskiy ubi_put_device(ubi); 84d05c77a8SArtem Bityutskiy return -ENODEV; 85801c135cSArtem B. Bityutskiy } 86d05c77a8SArtem Bityutskiy /* Take a reference to prevent volume removal */ 87d05c77a8SArtem Bityutskiy vol->ref_count += 1; 88d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 89732aeacfSArtem Bityutskiy 908bc22961SArtem Bityutskiy if (attr == &attr_vol_reserved_ebs) 91801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%d\n", vol->reserved_pebs); 928bc22961SArtem Bityutskiy else if (attr == &attr_vol_type) { 93801c135cSArtem B. Bityutskiy const char *tp; 948bc22961SArtem Bityutskiy 958bc22961SArtem Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) 968bc22961SArtem Bityutskiy tp = "dynamic"; 978bc22961SArtem Bityutskiy else 988bc22961SArtem Bityutskiy tp = "static"; 99801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%s\n", tp); 1008bc22961SArtem Bityutskiy } else if (attr == &attr_vol_name) 101801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%s\n", vol->name); 1028bc22961SArtem Bityutskiy else if (attr == &attr_vol_corrupted) 103801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%d\n", vol->corrupted); 1048bc22961SArtem Bityutskiy else if (attr == &attr_vol_alignment) 105801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%d\n", vol->alignment); 106732aeacfSArtem Bityutskiy else if (attr == &attr_vol_usable_eb_size) 107801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%d\n", vol->usable_leb_size); 108732aeacfSArtem Bityutskiy else if (attr == &attr_vol_data_bytes) 109801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%lld\n", vol->used_bytes); 1108bc22961SArtem Bityutskiy else if (attr == &attr_vol_upd_marker) 111801c135cSArtem B. Bityutskiy ret = sprintf(buf, "%d\n", vol->upd_marker); 112801c135cSArtem B. Bityutskiy else 113d05c77a8SArtem Bityutskiy /* This must be a bug */ 114d05c77a8SArtem Bityutskiy ret = -EINVAL; 115d05c77a8SArtem Bityutskiy 116e73f4459SArtem Bityutskiy /* We've done the operation, drop volume and UBI device references */ 117d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 118d05c77a8SArtem Bityutskiy vol->ref_count -= 1; 119d05c77a8SArtem Bityutskiy ubi_assert(vol->ref_count >= 0); 120d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 121e73f4459SArtem Bityutskiy ubi_put_device(ubi); 122801c135cSArtem B. Bityutskiy return ret; 123801c135cSArtem B. Bityutskiy } 124801c135cSArtem B. Bityutskiy 125801c135cSArtem B. Bityutskiy /* Release method for volume devices */ 126801c135cSArtem B. Bityutskiy static void vol_release(struct device *dev) 127801c135cSArtem B. Bityutskiy { 128801c135cSArtem B. Bityutskiy struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); 129732aeacfSArtem Bityutskiy 130abc5e922SArtem Bityutskiy kfree(vol->eba_tbl); 131801c135cSArtem B. Bityutskiy kfree(vol); 132801c135cSArtem B. Bityutskiy } 133801c135cSArtem B. Bityutskiy 134801c135cSArtem B. Bityutskiy /** 135801c135cSArtem B. Bityutskiy * volume_sysfs_init - initialize sysfs for new volume. 136801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 137801c135cSArtem B. Bityutskiy * @vol: volume description object 138801c135cSArtem B. Bityutskiy * 139801c135cSArtem B. Bityutskiy * This function returns zero in case of success and a negative error code in 140801c135cSArtem B. Bityutskiy * case of failure. 141801c135cSArtem B. Bityutskiy * 142801c135cSArtem B. Bityutskiy * Note, this function does not free allocated resources in case of failure - 143801c135cSArtem B. Bityutskiy * the caller does it. This is because this would cause release() here and the 144801c135cSArtem B. Bityutskiy * caller would oops. 145801c135cSArtem B. Bityutskiy */ 146801c135cSArtem B. Bityutskiy static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) 147801c135cSArtem B. Bityutskiy { 148801c135cSArtem B. Bityutskiy int err; 149801c135cSArtem B. Bityutskiy 1508bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_reserved_ebs); 151801c135cSArtem B. Bityutskiy if (err) 152801c135cSArtem B. Bityutskiy return err; 1538bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_type); 154801c135cSArtem B. Bityutskiy if (err) 155801c135cSArtem B. Bityutskiy return err; 1568bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_name); 157801c135cSArtem B. Bityutskiy if (err) 158801c135cSArtem B. Bityutskiy return err; 1598bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_corrupted); 160801c135cSArtem B. Bityutskiy if (err) 161801c135cSArtem B. Bityutskiy return err; 1628bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_alignment); 163801c135cSArtem B. Bityutskiy if (err) 164801c135cSArtem B. Bityutskiy return err; 1658bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_usable_eb_size); 166801c135cSArtem B. Bityutskiy if (err) 167801c135cSArtem B. Bityutskiy return err; 1688bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_data_bytes); 169801c135cSArtem B. Bityutskiy if (err) 170801c135cSArtem B. Bityutskiy return err; 1718bc22961SArtem Bityutskiy err = device_create_file(&vol->dev, &attr_vol_upd_marker); 172801c135cSArtem B. Bityutskiy return err; 173801c135cSArtem B. Bityutskiy } 174801c135cSArtem B. Bityutskiy 175801c135cSArtem B. Bityutskiy /** 176801c135cSArtem B. Bityutskiy * volume_sysfs_close - close sysfs for a volume. 177801c135cSArtem B. Bityutskiy * @vol: volume description object 178801c135cSArtem B. Bityutskiy */ 179801c135cSArtem B. Bityutskiy static void volume_sysfs_close(struct ubi_volume *vol) 180801c135cSArtem B. Bityutskiy { 1818bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_upd_marker); 1828bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_data_bytes); 1838bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_usable_eb_size); 1848bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_alignment); 1858bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_corrupted); 1868bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_name); 1878bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_type); 1888bc22961SArtem Bityutskiy device_remove_file(&vol->dev, &attr_vol_reserved_ebs); 189801c135cSArtem B. Bityutskiy device_unregister(&vol->dev); 190801c135cSArtem B. Bityutskiy } 191801c135cSArtem B. Bityutskiy 192801c135cSArtem B. Bityutskiy /** 193801c135cSArtem B. Bityutskiy * ubi_create_volume - create volume. 194801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 195801c135cSArtem B. Bityutskiy * @req: volume creation request 196801c135cSArtem B. Bityutskiy * 197801c135cSArtem B. Bityutskiy * This function creates volume described by @req. If @req->vol_id id 198d05c77a8SArtem Bityutskiy * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume 199801c135cSArtem B. Bityutskiy * and saves it in @req->vol_id. Returns zero in case of success and a negative 20040e4d0c1SArtem Bityutskiy * error code in case of failure. Note, the caller has to have the 201f089c0b2SArtem Bityutskiy * @ubi->device_mutex locked. 202801c135cSArtem B. Bityutskiy */ 203801c135cSArtem B. Bityutskiy int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) 204801c135cSArtem B. Bityutskiy { 205abc5e922SArtem Bityutskiy int i, err, vol_id = req->vol_id, do_free = 1; 206801c135cSArtem B. Bityutskiy struct ubi_volume *vol; 207801c135cSArtem B. Bityutskiy struct ubi_vtbl_record vtbl_rec; 20849dfc299SArtem Bityutskiy dev_t dev; 209801c135cSArtem B. Bityutskiy 210801c135cSArtem B. Bityutskiy if (ubi->ro_mode) 211801c135cSArtem B. Bityutskiy return -EROFS; 212801c135cSArtem B. Bityutskiy 213801c135cSArtem B. Bityutskiy vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); 214801c135cSArtem B. Bityutskiy if (!vol) 215801c135cSArtem B. Bityutskiy return -ENOMEM; 216801c135cSArtem B. Bityutskiy 217801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 218801c135cSArtem B. Bityutskiy if (vol_id == UBI_VOL_NUM_AUTO) { 219801c135cSArtem B. Bityutskiy /* Find unused volume ID */ 220c8566350SArtem Bityutskiy dbg_gen("search for vacant volume ID"); 221801c135cSArtem B. Bityutskiy for (i = 0; i < ubi->vtbl_slots; i++) 222801c135cSArtem B. Bityutskiy if (!ubi->volumes[i]) { 223801c135cSArtem B. Bityutskiy vol_id = i; 224801c135cSArtem B. Bityutskiy break; 225801c135cSArtem B. Bityutskiy } 226801c135cSArtem B. Bityutskiy 227801c135cSArtem B. Bityutskiy if (vol_id == UBI_VOL_NUM_AUTO) { 228801c135cSArtem B. Bityutskiy dbg_err("out of volume IDs"); 229801c135cSArtem B. Bityutskiy err = -ENFILE; 230801c135cSArtem B. Bityutskiy goto out_unlock; 231801c135cSArtem B. Bityutskiy } 232801c135cSArtem B. Bityutskiy req->vol_id = vol_id; 233801c135cSArtem B. Bityutskiy } 234801c135cSArtem B. Bityutskiy 235e1cf7e6dSArtem Bityutskiy dbg_gen("create device %d, volume %d, %llu bytes, type %d, name %s", 236e1cf7e6dSArtem Bityutskiy ubi->ubi_num, vol_id, (unsigned long long)req->bytes, 237801c135cSArtem B. Bityutskiy (int)req->vol_type, req->name); 238801c135cSArtem B. Bityutskiy 239801c135cSArtem B. Bityutskiy /* Ensure that this volume does not exist */ 240801c135cSArtem B. Bityutskiy err = -EEXIST; 241801c135cSArtem B. Bityutskiy if (ubi->volumes[vol_id]) { 242801c135cSArtem B. Bityutskiy dbg_err("volume %d already exists", vol_id); 243801c135cSArtem B. Bityutskiy goto out_unlock; 244801c135cSArtem B. Bityutskiy } 245801c135cSArtem B. Bityutskiy 246801c135cSArtem B. Bityutskiy /* Ensure that the name is unique */ 247801c135cSArtem B. Bityutskiy for (i = 0; i < ubi->vtbl_slots; i++) 248801c135cSArtem B. Bityutskiy if (ubi->volumes[i] && 249801c135cSArtem B. Bityutskiy ubi->volumes[i]->name_len == req->name_len && 25094784d91SArtem Bityutskiy !strcmp(ubi->volumes[i]->name, req->name)) { 251801c135cSArtem B. Bityutskiy dbg_err("volume \"%s\" exists (ID %d)", req->name, i); 252801c135cSArtem B. Bityutskiy goto out_unlock; 253801c135cSArtem B. Bityutskiy } 254801c135cSArtem B. Bityutskiy 255801c135cSArtem B. Bityutskiy /* Calculate how many eraseblocks are requested */ 256801c135cSArtem B. Bityutskiy vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; 2573013ee31SArtem Bityutskiy vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1, 2583013ee31SArtem Bityutskiy vol->usable_leb_size); 259801c135cSArtem B. Bityutskiy 260801c135cSArtem B. Bityutskiy /* Reserve physical eraseblocks */ 261801c135cSArtem B. Bityutskiy if (vol->reserved_pebs > ubi->avail_pebs) { 262801c135cSArtem B. Bityutskiy dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); 263801c135cSArtem B. Bityutskiy err = -ENOSPC; 264801c135cSArtem B. Bityutskiy goto out_unlock; 265801c135cSArtem B. Bityutskiy } 266801c135cSArtem B. Bityutskiy ubi->avail_pebs -= vol->reserved_pebs; 267801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += vol->reserved_pebs; 268e73f4459SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 269801c135cSArtem B. Bityutskiy 270801c135cSArtem B. Bityutskiy vol->vol_id = vol_id; 271801c135cSArtem B. Bityutskiy vol->alignment = req->alignment; 272801c135cSArtem B. Bityutskiy vol->data_pad = ubi->leb_size % vol->alignment; 273801c135cSArtem B. Bityutskiy vol->vol_type = req->vol_type; 274801c135cSArtem B. Bityutskiy vol->name_len = req->name_len; 275a6ea4407SArtem Bityutskiy memcpy(vol->name, req->name, vol->name_len); 276801c135cSArtem B. Bityutskiy vol->ubi = ubi; 277801c135cSArtem B. Bityutskiy 278801c135cSArtem B. Bityutskiy /* 279801c135cSArtem B. Bityutskiy * Finish all pending erases because there may be some LEBs belonging 280801c135cSArtem B. Bityutskiy * to the same volume ID. 281801c135cSArtem B. Bityutskiy */ 282801c135cSArtem B. Bityutskiy err = ubi_wl_flush(ubi); 283801c135cSArtem B. Bityutskiy if (err) 284801c135cSArtem B. Bityutskiy goto out_acc; 285801c135cSArtem B. Bityutskiy 286801c135cSArtem B. Bityutskiy vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL); 287801c135cSArtem B. Bityutskiy if (!vol->eba_tbl) { 288801c135cSArtem B. Bityutskiy err = -ENOMEM; 289801c135cSArtem B. Bityutskiy goto out_acc; 290801c135cSArtem B. Bityutskiy } 291801c135cSArtem B. Bityutskiy 292801c135cSArtem B. Bityutskiy for (i = 0; i < vol->reserved_pebs; i++) 293801c135cSArtem B. Bityutskiy vol->eba_tbl[i] = UBI_LEB_UNMAPPED; 294801c135cSArtem B. Bityutskiy 295801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 296801c135cSArtem B. Bityutskiy vol->used_ebs = vol->reserved_pebs; 297801c135cSArtem B. Bityutskiy vol->last_eb_bytes = vol->usable_leb_size; 298d08c3b78SVinit Agnihotri vol->used_bytes = 299d08c3b78SVinit Agnihotri (long long)vol->used_ebs * vol->usable_leb_size; 300801c135cSArtem B. Bityutskiy } else { 3013013ee31SArtem Bityutskiy vol->used_ebs = div_u64_rem(vol->used_bytes, 3023013ee31SArtem Bityutskiy vol->usable_leb_size, 3033013ee31SArtem Bityutskiy &vol->last_eb_bytes); 3043013ee31SArtem Bityutskiy if (vol->last_eb_bytes != 0) 305801c135cSArtem B. Bityutskiy vol->used_ebs += 1; 306801c135cSArtem B. Bityutskiy else 307801c135cSArtem B. Bityutskiy vol->last_eb_bytes = vol->usable_leb_size; 308801c135cSArtem B. Bityutskiy } 309801c135cSArtem B. Bityutskiy 310801c135cSArtem B. Bityutskiy /* Register character device for the volume */ 311801c135cSArtem B. Bityutskiy cdev_init(&vol->cdev, &ubi_vol_cdev_operations); 312801c135cSArtem B. Bityutskiy vol->cdev.owner = THIS_MODULE; 31349dfc299SArtem Bityutskiy dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); 31449dfc299SArtem Bityutskiy err = cdev_add(&vol->cdev, dev, 1); 315801c135cSArtem B. Bityutskiy if (err) { 31601f7b309SArtem Bityutskiy ubi_err("cannot add character device"); 317801c135cSArtem B. Bityutskiy goto out_mapping; 318801c135cSArtem B. Bityutskiy } 319801c135cSArtem B. Bityutskiy 320801c135cSArtem B. Bityutskiy vol->dev.release = vol_release; 321801c135cSArtem B. Bityutskiy vol->dev.parent = &ubi->dev; 32249dfc299SArtem Bityutskiy vol->dev.devt = dev; 323801c135cSArtem B. Bityutskiy vol->dev.class = ubi_class; 324fc75a1e1SArtem Bityutskiy 325475b44c1SKay Sievers dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); 326801c135cSArtem B. Bityutskiy err = device_register(&vol->dev); 32701f7b309SArtem Bityutskiy if (err) { 32801f7b309SArtem Bityutskiy ubi_err("cannot register device"); 329518ceef0SDmitry Pervushin goto out_cdev; 33001f7b309SArtem Bityutskiy } 331801c135cSArtem B. Bityutskiy 332801c135cSArtem B. Bityutskiy err = volume_sysfs_init(ubi, vol); 333801c135cSArtem B. Bityutskiy if (err) 334801c135cSArtem B. Bityutskiy goto out_sysfs; 335801c135cSArtem B. Bityutskiy 336801c135cSArtem B. Bityutskiy /* Fill volume table record */ 337801c135cSArtem B. Bityutskiy memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); 3383261ebd7SChristoph Hellwig vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs); 3393261ebd7SChristoph Hellwig vtbl_rec.alignment = cpu_to_be32(vol->alignment); 3403261ebd7SChristoph Hellwig vtbl_rec.data_pad = cpu_to_be32(vol->data_pad); 3413261ebd7SChristoph Hellwig vtbl_rec.name_len = cpu_to_be16(vol->name_len); 342801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) 343801c135cSArtem B. Bityutskiy vtbl_rec.vol_type = UBI_VID_DYNAMIC; 344801c135cSArtem B. Bityutskiy else 345801c135cSArtem B. Bityutskiy vtbl_rec.vol_type = UBI_VID_STATIC; 346a6ea4407SArtem Bityutskiy memcpy(vtbl_rec.name, vol->name, vol->name_len); 347801c135cSArtem B. Bityutskiy 348801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); 349801c135cSArtem B. Bityutskiy if (err) 350801c135cSArtem B. Bityutskiy goto out_sysfs; 351801c135cSArtem B. Bityutskiy 352801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 353d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = vol; 3544b3cc340SArtem Bityutskiy ubi->vol_count += 1; 355801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 356801c135cSArtem B. Bityutskiy 3570e0ee1ccSDmitry Pervushin ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED); 358d38dce5bSArtem Bityutskiy if (paranoid_check_volumes(ubi)) 359d38dce5bSArtem Bityutskiy dbg_err("check failed while creating volume %d", vol_id); 360c8566350SArtem Bityutskiy return err; 361801c135cSArtem B. Bityutskiy 362fc75a1e1SArtem Bityutskiy out_sysfs: 363fc75a1e1SArtem Bityutskiy /* 364abc5e922SArtem Bityutskiy * We have registered our device, we should not free the volume 365fc75a1e1SArtem Bityutskiy * description object in this function in case of an error - it is 366fc75a1e1SArtem Bityutskiy * freed by the release function. 367fc75a1e1SArtem Bityutskiy * 368fc75a1e1SArtem Bityutskiy * Get device reference to prevent the release function from being 369fc75a1e1SArtem Bityutskiy * called just after sysfs has been closed. 370fc75a1e1SArtem Bityutskiy */ 371abc5e922SArtem Bityutskiy do_free = 0; 372fc75a1e1SArtem Bityutskiy get_device(&vol->dev); 373fc75a1e1SArtem Bityutskiy volume_sysfs_close(vol); 374801c135cSArtem B. Bityutskiy out_cdev: 375801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 376801c135cSArtem B. Bityutskiy out_mapping: 377abc5e922SArtem Bityutskiy if (do_free) 378801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 379801c135cSArtem B. Bityutskiy out_acc: 380801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 381801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= vol->reserved_pebs; 382801c135cSArtem B. Bityutskiy ubi->avail_pebs += vol->reserved_pebs; 383801c135cSArtem B. Bityutskiy out_unlock: 384801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 385abc5e922SArtem Bityutskiy if (do_free) 386801c135cSArtem B. Bityutskiy kfree(vol); 387abc5e922SArtem Bityutskiy else 388abc5e922SArtem Bityutskiy put_device(&vol->dev); 38901f7b309SArtem Bityutskiy ubi_err("cannot create volume %d, error %d", vol_id, err); 390801c135cSArtem B. Bityutskiy return err; 391801c135cSArtem B. Bityutskiy } 392801c135cSArtem B. Bityutskiy 393801c135cSArtem B. Bityutskiy /** 394801c135cSArtem B. Bityutskiy * ubi_remove_volume - remove volume. 395801c135cSArtem B. Bityutskiy * @desc: volume descriptor 396f40ac9cdSArtem Bityutskiy * @no_vtbl: do not change volume table if not zero 397801c135cSArtem B. Bityutskiy * 398801c135cSArtem B. Bityutskiy * This function removes volume described by @desc. The volume has to be opened 399801c135cSArtem B. Bityutskiy * in "exclusive" mode. Returns zero in case of success and a negative error 400f089c0b2SArtem Bityutskiy * code in case of failure. The caller has to have the @ubi->device_mutex 40140e4d0c1SArtem Bityutskiy * locked. 402801c135cSArtem B. Bityutskiy */ 403f40ac9cdSArtem Bityutskiy int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) 404801c135cSArtem B. Bityutskiy { 405801c135cSArtem B. Bityutskiy struct ubi_volume *vol = desc->vol; 406801c135cSArtem B. Bityutskiy struct ubi_device *ubi = vol->ubi; 407801c135cSArtem B. Bityutskiy int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; 408801c135cSArtem B. Bityutskiy 409e1cf7e6dSArtem Bityutskiy dbg_gen("remove device %d, volume %d", ubi->ubi_num, vol_id); 410801c135cSArtem B. Bityutskiy ubi_assert(desc->mode == UBI_EXCLUSIVE); 411801c135cSArtem B. Bityutskiy ubi_assert(vol == ubi->volumes[vol_id]); 412801c135cSArtem B. Bityutskiy 413801c135cSArtem B. Bityutskiy if (ubi->ro_mode) 414801c135cSArtem B. Bityutskiy return -EROFS; 415801c135cSArtem B. Bityutskiy 416d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 417d05c77a8SArtem Bityutskiy if (vol->ref_count > 1) { 418d05c77a8SArtem Bityutskiy /* 419d05c77a8SArtem Bityutskiy * The volume is busy, probably someone is reading one of its 420d05c77a8SArtem Bityutskiy * sysfs files. 421d05c77a8SArtem Bityutskiy */ 422d05c77a8SArtem Bityutskiy err = -EBUSY; 423d05c77a8SArtem Bityutskiy goto out_unlock; 424d05c77a8SArtem Bityutskiy } 425d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = NULL; 426d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 427d05c77a8SArtem Bityutskiy 428f40ac9cdSArtem Bityutskiy if (!no_vtbl) { 429801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, NULL); 430801c135cSArtem B. Bityutskiy if (err) 431d05c77a8SArtem Bityutskiy goto out_err; 432f40ac9cdSArtem Bityutskiy } 433801c135cSArtem B. Bityutskiy 434801c135cSArtem B. Bityutskiy for (i = 0; i < vol->reserved_pebs; i++) { 43589b96b69SArtem Bityutskiy err = ubi_eba_unmap_leb(ubi, vol, i); 436801c135cSArtem B. Bityutskiy if (err) 437d05c77a8SArtem Bityutskiy goto out_err; 438801c135cSArtem B. Bityutskiy } 439801c135cSArtem B. Bityutskiy 440801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 441801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 442801c135cSArtem B. Bityutskiy 443801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 444801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= reserved_pebs; 445801c135cSArtem B. Bityutskiy ubi->avail_pebs += reserved_pebs; 446801c135cSArtem B. Bityutskiy i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; 447801c135cSArtem B. Bityutskiy if (i > 0) { 448801c135cSArtem B. Bityutskiy i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; 449801c135cSArtem B. Bityutskiy ubi->avail_pebs -= i; 450801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += i; 451801c135cSArtem B. Bityutskiy ubi->beb_rsvd_pebs += i; 452801c135cSArtem B. Bityutskiy if (i > 0) 453801c135cSArtem B. Bityutskiy ubi_msg("reserve more %d PEBs", i); 454801c135cSArtem B. Bityutskiy } 455801c135cSArtem B. Bityutskiy ubi->vol_count -= 1; 456801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 457801c135cSArtem B. Bityutskiy 4580e0ee1ccSDmitry Pervushin ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED); 459d38dce5bSArtem Bityutskiy if (!no_vtbl && paranoid_check_volumes(ubi)) 460d38dce5bSArtem Bityutskiy dbg_err("check failed while removing volume %d", vol_id); 461d38dce5bSArtem Bityutskiy 462c8566350SArtem Bityutskiy return err; 463d05c77a8SArtem Bityutskiy 464d05c77a8SArtem Bityutskiy out_err: 465d05c77a8SArtem Bityutskiy ubi_err("cannot remove volume %d, error %d", vol_id, err); 466d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 467d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = vol; 468d05c77a8SArtem Bityutskiy out_unlock: 469d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 470cae0a771SArtem Bityutskiy return err; 471801c135cSArtem B. Bityutskiy } 472801c135cSArtem B. Bityutskiy 473801c135cSArtem B. Bityutskiy /** 474801c135cSArtem B. Bityutskiy * ubi_resize_volume - re-size volume. 475801c135cSArtem B. Bityutskiy * @desc: volume descriptor 476801c135cSArtem B. Bityutskiy * @reserved_pebs: new size in physical eraseblocks 477801c135cSArtem B. Bityutskiy * 47840e4d0c1SArtem Bityutskiy * This function re-sizes the volume and returns zero in case of success, and a 47940e4d0c1SArtem Bityutskiy * negative error code in case of failure. The caller has to have the 480f089c0b2SArtem Bityutskiy * @ubi->device_mutex locked. 481801c135cSArtem B. Bityutskiy */ 482801c135cSArtem B. Bityutskiy int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) 483801c135cSArtem B. Bityutskiy { 484801c135cSArtem B. Bityutskiy int i, err, pebs, *new_mapping; 485801c135cSArtem B. Bityutskiy struct ubi_volume *vol = desc->vol; 486801c135cSArtem B. Bityutskiy struct ubi_device *ubi = vol->ubi; 487801c135cSArtem B. Bityutskiy struct ubi_vtbl_record vtbl_rec; 488801c135cSArtem B. Bityutskiy int vol_id = vol->vol_id; 489801c135cSArtem B. Bityutskiy 490801c135cSArtem B. Bityutskiy if (ubi->ro_mode) 491801c135cSArtem B. Bityutskiy return -EROFS; 492801c135cSArtem B. Bityutskiy 493e1cf7e6dSArtem Bityutskiy dbg_gen("re-size device %d, volume %d to from %d to %d PEBs", 494e1cf7e6dSArtem Bityutskiy ubi->ubi_num, vol_id, vol->reserved_pebs, reserved_pebs); 495801c135cSArtem B. Bityutskiy 496801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_STATIC_VOLUME && 497801c135cSArtem B. Bityutskiy reserved_pebs < vol->used_ebs) { 498801c135cSArtem B. Bityutskiy dbg_err("too small size %d, %d LEBs contain data", 499801c135cSArtem B. Bityutskiy reserved_pebs, vol->used_ebs); 500801c135cSArtem B. Bityutskiy return -EINVAL; 501801c135cSArtem B. Bityutskiy } 502801c135cSArtem B. Bityutskiy 503801c135cSArtem B. Bityutskiy /* If the size is the same, we have nothing to do */ 504801c135cSArtem B. Bityutskiy if (reserved_pebs == vol->reserved_pebs) 505801c135cSArtem B. Bityutskiy return 0; 506801c135cSArtem B. Bityutskiy 507801c135cSArtem B. Bityutskiy new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL); 508801c135cSArtem B. Bityutskiy if (!new_mapping) 509801c135cSArtem B. Bityutskiy return -ENOMEM; 510801c135cSArtem B. Bityutskiy 511801c135cSArtem B. Bityutskiy for (i = 0; i < reserved_pebs; i++) 512801c135cSArtem B. Bityutskiy new_mapping[i] = UBI_LEB_UNMAPPED; 513801c135cSArtem B. Bityutskiy 514d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 515d05c77a8SArtem Bityutskiy if (vol->ref_count > 1) { 516d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 517d05c77a8SArtem Bityutskiy err = -EBUSY; 518d05c77a8SArtem Bityutskiy goto out_free; 519d05c77a8SArtem Bityutskiy } 520d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 521d05c77a8SArtem Bityutskiy 522d05c77a8SArtem Bityutskiy /* Reserve physical eraseblocks */ 523801c135cSArtem B. Bityutskiy pebs = reserved_pebs - vol->reserved_pebs; 524801c135cSArtem B. Bityutskiy if (pebs > 0) { 525801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 526801c135cSArtem B. Bityutskiy if (pebs > ubi->avail_pebs) { 527801c135cSArtem B. Bityutskiy dbg_err("not enough PEBs: requested %d, available %d", 528801c135cSArtem B. Bityutskiy pebs, ubi->avail_pebs); 529801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 530801c135cSArtem B. Bityutskiy err = -ENOSPC; 531801c135cSArtem B. Bityutskiy goto out_free; 532801c135cSArtem B. Bityutskiy } 533801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 534801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 535801c135cSArtem B. Bityutskiy for (i = 0; i < vol->reserved_pebs; i++) 536801c135cSArtem B. Bityutskiy new_mapping[i] = vol->eba_tbl[i]; 537801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 538801c135cSArtem B. Bityutskiy vol->eba_tbl = new_mapping; 539801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 540801c135cSArtem B. Bityutskiy } 541801c135cSArtem B. Bityutskiy 542801c135cSArtem B. Bityutskiy /* Change volume table record */ 543801c135cSArtem B. Bityutskiy memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); 5443261ebd7SChristoph Hellwig vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); 545801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); 546801c135cSArtem B. Bityutskiy if (err) 547801c135cSArtem B. Bityutskiy goto out_acc; 548801c135cSArtem B. Bityutskiy 549801c135cSArtem B. Bityutskiy if (pebs < 0) { 550801c135cSArtem B. Bityutskiy for (i = 0; i < -pebs; i++) { 55189b96b69SArtem Bityutskiy err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); 552801c135cSArtem B. Bityutskiy if (err) 553801c135cSArtem B. Bityutskiy goto out_acc; 554801c135cSArtem B. Bityutskiy } 555801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 556801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 557801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 558801c135cSArtem B. Bityutskiy pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; 559801c135cSArtem B. Bityutskiy if (pebs > 0) { 560801c135cSArtem B. Bityutskiy pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs; 561801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 562801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 563801c135cSArtem B. Bityutskiy ubi->beb_rsvd_pebs += pebs; 564801c135cSArtem B. Bityutskiy if (pebs > 0) 565801c135cSArtem B. Bityutskiy ubi_msg("reserve more %d PEBs", pebs); 566801c135cSArtem B. Bityutskiy } 567801c135cSArtem B. Bityutskiy for (i = 0; i < reserved_pebs; i++) 568801c135cSArtem B. Bityutskiy new_mapping[i] = vol->eba_tbl[i]; 569801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 570801c135cSArtem B. Bityutskiy vol->eba_tbl = new_mapping; 571801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 572801c135cSArtem B. Bityutskiy } 573801c135cSArtem B. Bityutskiy 574801c135cSArtem B. Bityutskiy vol->reserved_pebs = reserved_pebs; 575801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 576801c135cSArtem B. Bityutskiy vol->used_ebs = reserved_pebs; 577801c135cSArtem B. Bityutskiy vol->last_eb_bytes = vol->usable_leb_size; 578d08c3b78SVinit Agnihotri vol->used_bytes = 579d08c3b78SVinit Agnihotri (long long)vol->used_ebs * vol->usable_leb_size; 580801c135cSArtem B. Bityutskiy } 581801c135cSArtem B. Bityutskiy 5820e0ee1ccSDmitry Pervushin ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED); 583d38dce5bSArtem Bityutskiy if (paranoid_check_volumes(ubi)) 584d38dce5bSArtem Bityutskiy dbg_err("check failed while re-sizing volume %d", vol_id); 585c8566350SArtem Bityutskiy return err; 586801c135cSArtem B. Bityutskiy 587801c135cSArtem B. Bityutskiy out_acc: 588801c135cSArtem B. Bityutskiy if (pebs > 0) { 589801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 590801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= pebs; 591801c135cSArtem B. Bityutskiy ubi->avail_pebs += pebs; 592801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 593801c135cSArtem B. Bityutskiy } 594801c135cSArtem B. Bityutskiy out_free: 595801c135cSArtem B. Bityutskiy kfree(new_mapping); 596801c135cSArtem B. Bityutskiy return err; 597801c135cSArtem B. Bityutskiy } 598801c135cSArtem B. Bityutskiy 599801c135cSArtem B. Bityutskiy /** 600f40ac9cdSArtem Bityutskiy * ubi_rename_volumes - re-name UBI volumes. 601f40ac9cdSArtem Bityutskiy * @ubi: UBI device description object 602ebaaf1afSArtem Bityutskiy * @rename_list: list of &struct ubi_rename_entry objects 603f40ac9cdSArtem Bityutskiy * 604f40ac9cdSArtem Bityutskiy * This function re-names or removes volumes specified in the re-name list. 605f40ac9cdSArtem Bityutskiy * Returns zero in case of success and a negative error code in case of 606f40ac9cdSArtem Bityutskiy * failure. 607f40ac9cdSArtem Bityutskiy */ 608f40ac9cdSArtem Bityutskiy int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) 609f40ac9cdSArtem Bityutskiy { 610f40ac9cdSArtem Bityutskiy int err; 611f40ac9cdSArtem Bityutskiy struct ubi_rename_entry *re; 612f40ac9cdSArtem Bityutskiy 613f40ac9cdSArtem Bityutskiy err = ubi_vtbl_rename_volumes(ubi, rename_list); 614f40ac9cdSArtem Bityutskiy if (err) 615f40ac9cdSArtem Bityutskiy return err; 616f40ac9cdSArtem Bityutskiy 617f40ac9cdSArtem Bityutskiy list_for_each_entry(re, rename_list, list) { 618f40ac9cdSArtem Bityutskiy if (re->remove) { 619f40ac9cdSArtem Bityutskiy err = ubi_remove_volume(re->desc, 1); 620f40ac9cdSArtem Bityutskiy if (err) 621f40ac9cdSArtem Bityutskiy break; 622f40ac9cdSArtem Bityutskiy } else { 623f40ac9cdSArtem Bityutskiy struct ubi_volume *vol = re->desc->vol; 624f40ac9cdSArtem Bityutskiy 625f40ac9cdSArtem Bityutskiy spin_lock(&ubi->volumes_lock); 626f40ac9cdSArtem Bityutskiy vol->name_len = re->new_name_len; 627f40ac9cdSArtem Bityutskiy memcpy(vol->name, re->new_name, re->new_name_len + 1); 628f40ac9cdSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 6290e0ee1ccSDmitry Pervushin ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED); 630f40ac9cdSArtem Bityutskiy } 631f40ac9cdSArtem Bityutskiy } 632f40ac9cdSArtem Bityutskiy 633d38dce5bSArtem Bityutskiy if (!err && paranoid_check_volumes(ubi)) 634d38dce5bSArtem Bityutskiy ; 635f40ac9cdSArtem Bityutskiy return err; 636f40ac9cdSArtem Bityutskiy } 637f40ac9cdSArtem Bityutskiy 638f40ac9cdSArtem Bityutskiy /** 639801c135cSArtem B. Bityutskiy * ubi_add_volume - add volume. 640801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 64189b96b69SArtem Bityutskiy * @vol: volume description object 642801c135cSArtem B. Bityutskiy * 643d05c77a8SArtem Bityutskiy * This function adds an existing volume and initializes all its data 644d05c77a8SArtem Bityutskiy * structures. Returns zero in case of success and a negative error code in 645801c135cSArtem B. Bityutskiy * case of failure. 646801c135cSArtem B. Bityutskiy */ 64789b96b69SArtem Bityutskiy int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) 648801c135cSArtem B. Bityutskiy { 64989b96b69SArtem Bityutskiy int err, vol_id = vol->vol_id; 65049dfc299SArtem Bityutskiy dev_t dev; 651801c135cSArtem B. Bityutskiy 652c8566350SArtem Bityutskiy dbg_gen("add volume %d", vol_id); 653801c135cSArtem B. Bityutskiy 654801c135cSArtem B. Bityutskiy /* Register character device for the volume */ 655801c135cSArtem B. Bityutskiy cdev_init(&vol->cdev, &ubi_vol_cdev_operations); 656801c135cSArtem B. Bityutskiy vol->cdev.owner = THIS_MODULE; 65749dfc299SArtem Bityutskiy dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); 65849dfc299SArtem Bityutskiy err = cdev_add(&vol->cdev, dev, 1); 659801c135cSArtem B. Bityutskiy if (err) { 66001f7b309SArtem Bityutskiy ubi_err("cannot add character device for volume %d, error %d", 66101f7b309SArtem Bityutskiy vol_id, err); 662801c135cSArtem B. Bityutskiy return err; 663801c135cSArtem B. Bityutskiy } 664801c135cSArtem B. Bityutskiy 665801c135cSArtem B. Bityutskiy vol->dev.release = vol_release; 666801c135cSArtem B. Bityutskiy vol->dev.parent = &ubi->dev; 66749dfc299SArtem Bityutskiy vol->dev.devt = dev; 668801c135cSArtem B. Bityutskiy vol->dev.class = ubi_class; 669475b44c1SKay Sievers dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); 670801c135cSArtem B. Bityutskiy err = device_register(&vol->dev); 671801c135cSArtem B. Bityutskiy if (err) 672518ceef0SDmitry Pervushin goto out_cdev; 673801c135cSArtem B. Bityutskiy 674801c135cSArtem B. Bityutskiy err = volume_sysfs_init(ubi, vol); 675801c135cSArtem B. Bityutskiy if (err) { 676801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 677801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 678801c135cSArtem B. Bityutskiy return err; 679801c135cSArtem B. Bityutskiy } 680801c135cSArtem B. Bityutskiy 681d38dce5bSArtem Bityutskiy if (paranoid_check_volumes(ubi)) 682d38dce5bSArtem Bityutskiy dbg_err("check failed while adding volume %d", vol_id); 683c8566350SArtem Bityutskiy return err; 684801c135cSArtem B. Bityutskiy 685801c135cSArtem B. Bityutskiy out_cdev: 686801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 687801c135cSArtem B. Bityutskiy return err; 688801c135cSArtem B. Bityutskiy } 689801c135cSArtem B. Bityutskiy 690801c135cSArtem B. Bityutskiy /** 691801c135cSArtem B. Bityutskiy * ubi_free_volume - free volume. 692801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 69389b96b69SArtem Bityutskiy * @vol: volume description object 694801c135cSArtem B. Bityutskiy * 69589b96b69SArtem Bityutskiy * This function frees all resources for volume @vol but does not remove it. 696801c135cSArtem B. Bityutskiy * Used only when the UBI device is detached. 697801c135cSArtem B. Bityutskiy */ 69889b96b69SArtem Bityutskiy void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) 699801c135cSArtem B. Bityutskiy { 700c8566350SArtem Bityutskiy dbg_gen("free volume %d", vol->vol_id); 701801c135cSArtem B. Bityutskiy 70289b96b69SArtem Bityutskiy ubi->volumes[vol->vol_id] = NULL; 703801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 704801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 705801c135cSArtem B. Bityutskiy } 706801c135cSArtem B. Bityutskiy 707801c135cSArtem B. Bityutskiy #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID 708801c135cSArtem B. Bityutskiy 709801c135cSArtem B. Bityutskiy /** 710801c135cSArtem B. Bityutskiy * paranoid_check_volume - check volume information. 711801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 712801c135cSArtem B. Bityutskiy * @vol_id: volume ID 713c8566350SArtem Bityutskiy * 714c8566350SArtem Bityutskiy * Returns zero if volume is all right and a a negative error code if not. 715801c135cSArtem B. Bityutskiy */ 716c8566350SArtem Bityutskiy static int paranoid_check_volume(struct ubi_device *ubi, int vol_id) 717801c135cSArtem B. Bityutskiy { 718801c135cSArtem B. Bityutskiy int idx = vol_id2idx(ubi, vol_id); 719801c135cSArtem B. Bityutskiy int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; 720b89044bfSArtem Bityutskiy const struct ubi_volume *vol; 721801c135cSArtem B. Bityutskiy long long n; 722801c135cSArtem B. Bityutskiy const char *name; 723801c135cSArtem B. Bityutskiy 724b89044bfSArtem Bityutskiy spin_lock(&ubi->volumes_lock); 7253261ebd7SChristoph Hellwig reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); 726b89044bfSArtem Bityutskiy vol = ubi->volumes[idx]; 727801c135cSArtem B. Bityutskiy 728801c135cSArtem B. Bityutskiy if (!vol) { 729801c135cSArtem B. Bityutskiy if (reserved_pebs) { 730801c135cSArtem B. Bityutskiy ubi_err("no volume info, but volume exists"); 731801c135cSArtem B. Bityutskiy goto fail; 732801c135cSArtem B. Bityutskiy } 733b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 734c8566350SArtem Bityutskiy return 0; 735801c135cSArtem B. Bityutskiy } 736801c135cSArtem B. Bityutskiy 737801c135cSArtem B. Bityutskiy if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || 738801c135cSArtem B. Bityutskiy vol->name_len < 0) { 739801c135cSArtem B. Bityutskiy ubi_err("negative values"); 740801c135cSArtem B. Bityutskiy goto fail; 741801c135cSArtem B. Bityutskiy } 742801c135cSArtem B. Bityutskiy if (vol->alignment > ubi->leb_size || vol->alignment == 0) { 743801c135cSArtem B. Bityutskiy ubi_err("bad alignment"); 744801c135cSArtem B. Bityutskiy goto fail; 745801c135cSArtem B. Bityutskiy } 746801c135cSArtem B. Bityutskiy 747cadb40ccSKyungmin Park n = vol->alignment & (ubi->min_io_size - 1); 748801c135cSArtem B. Bityutskiy if (vol->alignment != 1 && n) { 749801c135cSArtem B. Bityutskiy ubi_err("alignment is not multiple of min I/O unit"); 750801c135cSArtem B. Bityutskiy goto fail; 751801c135cSArtem B. Bityutskiy } 752801c135cSArtem B. Bityutskiy 753801c135cSArtem B. Bityutskiy n = ubi->leb_size % vol->alignment; 754801c135cSArtem B. Bityutskiy if (vol->data_pad != n) { 755801c135cSArtem B. Bityutskiy ubi_err("bad data_pad, has to be %lld", n); 756801c135cSArtem B. Bityutskiy goto fail; 757801c135cSArtem B. Bityutskiy } 758801c135cSArtem B. Bityutskiy 759801c135cSArtem B. Bityutskiy if (vol->vol_type != UBI_DYNAMIC_VOLUME && 760801c135cSArtem B. Bityutskiy vol->vol_type != UBI_STATIC_VOLUME) { 761801c135cSArtem B. Bityutskiy ubi_err("bad vol_type"); 762801c135cSArtem B. Bityutskiy goto fail; 763801c135cSArtem B. Bityutskiy } 764801c135cSArtem B. Bityutskiy 765801c135cSArtem B. Bityutskiy if (vol->upd_marker && vol->corrupted) { 766801c135cSArtem B. Bityutskiy dbg_err("update marker and corrupted simultaneously"); 767801c135cSArtem B. Bityutskiy goto fail; 768801c135cSArtem B. Bityutskiy } 769801c135cSArtem B. Bityutskiy 770801c135cSArtem B. Bityutskiy if (vol->reserved_pebs > ubi->good_peb_count) { 771801c135cSArtem B. Bityutskiy ubi_err("too large reserved_pebs"); 772801c135cSArtem B. Bityutskiy goto fail; 773801c135cSArtem B. Bityutskiy } 774801c135cSArtem B. Bityutskiy 775801c135cSArtem B. Bityutskiy n = ubi->leb_size - vol->data_pad; 776801c135cSArtem B. Bityutskiy if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { 777801c135cSArtem B. Bityutskiy ubi_err("bad usable_leb_size, has to be %lld", n); 778801c135cSArtem B. Bityutskiy goto fail; 779801c135cSArtem B. Bityutskiy } 780801c135cSArtem B. Bityutskiy 781801c135cSArtem B. Bityutskiy if (vol->name_len > UBI_VOL_NAME_MAX) { 782801c135cSArtem B. Bityutskiy ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); 783801c135cSArtem B. Bityutskiy goto fail; 784801c135cSArtem B. Bityutskiy } 785801c135cSArtem B. Bityutskiy 786801c135cSArtem B. Bityutskiy if (!vol->name) { 787801c135cSArtem B. Bityutskiy ubi_err("NULL volume name"); 788801c135cSArtem B. Bityutskiy goto fail; 789801c135cSArtem B. Bityutskiy } 790801c135cSArtem B. Bityutskiy 791801c135cSArtem B. Bityutskiy n = strnlen(vol->name, vol->name_len + 1); 792801c135cSArtem B. Bityutskiy if (n != vol->name_len) { 793801c135cSArtem B. Bityutskiy ubi_err("bad name_len %lld", n); 794801c135cSArtem B. Bityutskiy goto fail; 795801c135cSArtem B. Bityutskiy } 796801c135cSArtem B. Bityutskiy 797d08c3b78SVinit Agnihotri n = (long long)vol->used_ebs * vol->usable_leb_size; 798801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 799896c0c06SArtem Bityutskiy if (vol->corrupted) { 800801c135cSArtem B. Bityutskiy ubi_err("corrupted dynamic volume"); 801801c135cSArtem B. Bityutskiy goto fail; 802801c135cSArtem B. Bityutskiy } 803801c135cSArtem B. Bityutskiy if (vol->used_ebs != vol->reserved_pebs) { 804801c135cSArtem B. Bityutskiy ubi_err("bad used_ebs"); 805801c135cSArtem B. Bityutskiy goto fail; 806801c135cSArtem B. Bityutskiy } 807801c135cSArtem B. Bityutskiy if (vol->last_eb_bytes != vol->usable_leb_size) { 808801c135cSArtem B. Bityutskiy ubi_err("bad last_eb_bytes"); 809801c135cSArtem B. Bityutskiy goto fail; 810801c135cSArtem B. Bityutskiy } 811801c135cSArtem B. Bityutskiy if (vol->used_bytes != n) { 812801c135cSArtem B. Bityutskiy ubi_err("bad used_bytes"); 813801c135cSArtem B. Bityutskiy goto fail; 814801c135cSArtem B. Bityutskiy } 815801c135cSArtem B. Bityutskiy } else { 816801c135cSArtem B. Bityutskiy if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { 817801c135cSArtem B. Bityutskiy ubi_err("bad used_ebs"); 818801c135cSArtem B. Bityutskiy goto fail; 819801c135cSArtem B. Bityutskiy } 820801c135cSArtem B. Bityutskiy if (vol->last_eb_bytes < 0 || 821801c135cSArtem B. Bityutskiy vol->last_eb_bytes > vol->usable_leb_size) { 822801c135cSArtem B. Bityutskiy ubi_err("bad last_eb_bytes"); 823801c135cSArtem B. Bityutskiy goto fail; 824801c135cSArtem B. Bityutskiy } 825801c135cSArtem B. Bityutskiy if (vol->used_bytes < 0 || vol->used_bytes > n || 826801c135cSArtem B. Bityutskiy vol->used_bytes < n - vol->usable_leb_size) { 827801c135cSArtem B. Bityutskiy ubi_err("bad used_bytes"); 828801c135cSArtem B. Bityutskiy goto fail; 829801c135cSArtem B. Bityutskiy } 830801c135cSArtem B. Bityutskiy } 831801c135cSArtem B. Bityutskiy 8323261ebd7SChristoph Hellwig alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment); 8333261ebd7SChristoph Hellwig data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad); 8343261ebd7SChristoph Hellwig name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len); 835801c135cSArtem B. Bityutskiy upd_marker = ubi->vtbl[vol_id].upd_marker; 836801c135cSArtem B. Bityutskiy name = &ubi->vtbl[vol_id].name[0]; 837801c135cSArtem B. Bityutskiy if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) 838801c135cSArtem B. Bityutskiy vol_type = UBI_DYNAMIC_VOLUME; 839801c135cSArtem B. Bityutskiy else 840801c135cSArtem B. Bityutskiy vol_type = UBI_STATIC_VOLUME; 841801c135cSArtem B. Bityutskiy 842801c135cSArtem B. Bityutskiy if (alignment != vol->alignment || data_pad != vol->data_pad || 843801c135cSArtem B. Bityutskiy upd_marker != vol->upd_marker || vol_type != vol->vol_type || 844801c135cSArtem B. Bityutskiy name_len != vol->name_len || strncmp(name, vol->name, name_len)) { 845801c135cSArtem B. Bityutskiy ubi_err("volume info is different"); 846801c135cSArtem B. Bityutskiy goto fail; 847801c135cSArtem B. Bityutskiy } 848801c135cSArtem B. Bityutskiy 849b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 850c8566350SArtem Bityutskiy return 0; 851801c135cSArtem B. Bityutskiy 852801c135cSArtem B. Bityutskiy fail: 85394784d91SArtem Bityutskiy ubi_err("paranoid check failed for volume %d", vol_id); 854f40ac9cdSArtem Bityutskiy if (vol) 855801c135cSArtem B. Bityutskiy ubi_dbg_dump_vol_info(vol); 856801c135cSArtem B. Bityutskiy ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); 857cfcf0ec8SArtem Bityutskiy dump_stack(); 858b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 859c8566350SArtem Bityutskiy return -EINVAL; 860801c135cSArtem B. Bityutskiy } 861801c135cSArtem B. Bityutskiy 862801c135cSArtem B. Bityutskiy /** 863801c135cSArtem B. Bityutskiy * paranoid_check_volumes - check information about all volumes. 864801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 865c8566350SArtem Bityutskiy * 866c8566350SArtem Bityutskiy * Returns zero if volumes are all right and a a negative error code if not. 867801c135cSArtem B. Bityutskiy */ 868c8566350SArtem Bityutskiy static int paranoid_check_volumes(struct ubi_device *ubi) 869801c135cSArtem B. Bityutskiy { 870c8566350SArtem Bityutskiy int i, err = 0; 871801c135cSArtem B. Bityutskiy 872c8566350SArtem Bityutskiy for (i = 0; i < ubi->vtbl_slots; i++) { 873c8566350SArtem Bityutskiy err = paranoid_check_volume(ubi, i); 874c8566350SArtem Bityutskiy if (err) 875c8566350SArtem Bityutskiy break; 876c8566350SArtem Bityutskiy } 877c8566350SArtem Bityutskiy 878c8566350SArtem Bityutskiy return err; 879801c135cSArtem B. Bityutskiy } 880801c135cSArtem B. Bityutskiy #endif 881