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> 27*3013ee31SArtem 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 20140e4d0c1SArtem Bityutskiy * @ubi->volumes_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 235c8566350SArtem Bityutskiy dbg_gen("volume ID %d, %llu bytes, type %d, name %s", 236801c135cSArtem B. Bityutskiy 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; 257*3013ee31SArtem Bityutskiy vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1, 258*3013ee31SArtem 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 { 301*3013ee31SArtem Bityutskiy vol->used_ebs = div_u64_rem(vol->used_bytes, 302*3013ee31SArtem Bityutskiy vol->usable_leb_size, 303*3013ee31SArtem Bityutskiy &vol->last_eb_bytes); 304*3013ee31SArtem 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 err = ubi_create_gluebi(ubi, vol); 321801c135cSArtem B. Bityutskiy if (err) 322801c135cSArtem B. Bityutskiy goto out_cdev; 323801c135cSArtem B. Bityutskiy 324801c135cSArtem B. Bityutskiy vol->dev.release = vol_release; 325801c135cSArtem B. Bityutskiy vol->dev.parent = &ubi->dev; 32649dfc299SArtem Bityutskiy vol->dev.devt = dev; 327801c135cSArtem B. Bityutskiy vol->dev.class = ubi_class; 328fc75a1e1SArtem Bityutskiy 329475b44c1SKay Sievers dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); 330801c135cSArtem B. Bityutskiy err = device_register(&vol->dev); 33101f7b309SArtem Bityutskiy if (err) { 33201f7b309SArtem Bityutskiy ubi_err("cannot register device"); 333801c135cSArtem B. Bityutskiy goto out_gluebi; 33401f7b309SArtem Bityutskiy } 335801c135cSArtem B. Bityutskiy 336801c135cSArtem B. Bityutskiy err = volume_sysfs_init(ubi, vol); 337801c135cSArtem B. Bityutskiy if (err) 338801c135cSArtem B. Bityutskiy goto out_sysfs; 339801c135cSArtem B. Bityutskiy 340801c135cSArtem B. Bityutskiy /* Fill volume table record */ 341801c135cSArtem B. Bityutskiy memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); 3423261ebd7SChristoph Hellwig vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs); 3433261ebd7SChristoph Hellwig vtbl_rec.alignment = cpu_to_be32(vol->alignment); 3443261ebd7SChristoph Hellwig vtbl_rec.data_pad = cpu_to_be32(vol->data_pad); 3453261ebd7SChristoph Hellwig vtbl_rec.name_len = cpu_to_be16(vol->name_len); 346801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) 347801c135cSArtem B. Bityutskiy vtbl_rec.vol_type = UBI_VID_DYNAMIC; 348801c135cSArtem B. Bityutskiy else 349801c135cSArtem B. Bityutskiy vtbl_rec.vol_type = UBI_VID_STATIC; 350a6ea4407SArtem Bityutskiy memcpy(vtbl_rec.name, vol->name, vol->name_len); 351801c135cSArtem B. Bityutskiy 352801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); 353801c135cSArtem B. Bityutskiy if (err) 354801c135cSArtem B. Bityutskiy goto out_sysfs; 355801c135cSArtem B. Bityutskiy 356801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 357d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = vol; 3584b3cc340SArtem Bityutskiy ubi->vol_count += 1; 359801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 360801c135cSArtem B. Bityutskiy 361c8566350SArtem Bityutskiy err = paranoid_check_volumes(ubi); 362c8566350SArtem Bityutskiy return err; 363801c135cSArtem B. Bityutskiy 364fc75a1e1SArtem Bityutskiy out_sysfs: 365fc75a1e1SArtem Bityutskiy /* 366abc5e922SArtem Bityutskiy * We have registered our device, we should not free the volume 367fc75a1e1SArtem Bityutskiy * description object in this function in case of an error - it is 368fc75a1e1SArtem Bityutskiy * freed by the release function. 369fc75a1e1SArtem Bityutskiy * 370fc75a1e1SArtem Bityutskiy * Get device reference to prevent the release function from being 371fc75a1e1SArtem Bityutskiy * called just after sysfs has been closed. 372fc75a1e1SArtem Bityutskiy */ 373abc5e922SArtem Bityutskiy do_free = 0; 374fc75a1e1SArtem Bityutskiy get_device(&vol->dev); 375fc75a1e1SArtem Bityutskiy volume_sysfs_close(vol); 376801c135cSArtem B. Bityutskiy out_gluebi: 377fc398769SS.Çağlar Onur if (ubi_destroy_gluebi(vol)) 378fc398769SS.Çağlar Onur dbg_err("cannot destroy gluebi for volume %d:%d", 379fc398769SS.Çağlar Onur ubi->ubi_num, vol_id); 380801c135cSArtem B. Bityutskiy out_cdev: 381801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 382801c135cSArtem B. Bityutskiy out_mapping: 383abc5e922SArtem Bityutskiy if (do_free) 384801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 385801c135cSArtem B. Bityutskiy out_acc: 386801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 387801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= vol->reserved_pebs; 388801c135cSArtem B. Bityutskiy ubi->avail_pebs += vol->reserved_pebs; 389801c135cSArtem B. Bityutskiy out_unlock: 390801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 391abc5e922SArtem Bityutskiy if (do_free) 392801c135cSArtem B. Bityutskiy kfree(vol); 393abc5e922SArtem Bityutskiy else 394abc5e922SArtem Bityutskiy put_device(&vol->dev); 39501f7b309SArtem Bityutskiy ubi_err("cannot create volume %d, error %d", vol_id, err); 396801c135cSArtem B. Bityutskiy return err; 397801c135cSArtem B. Bityutskiy } 398801c135cSArtem B. Bityutskiy 399801c135cSArtem B. Bityutskiy /** 400801c135cSArtem B. Bityutskiy * ubi_remove_volume - remove volume. 401801c135cSArtem B. Bityutskiy * @desc: volume descriptor 402f40ac9cdSArtem Bityutskiy * @no_vtbl: do not change volume table if not zero 403801c135cSArtem B. Bityutskiy * 404801c135cSArtem B. Bityutskiy * This function removes volume described by @desc. The volume has to be opened 405801c135cSArtem B. Bityutskiy * in "exclusive" mode. Returns zero in case of success and a negative error 40640e4d0c1SArtem Bityutskiy * code in case of failure. The caller has to have the @ubi->volumes_mutex 40740e4d0c1SArtem Bityutskiy * locked. 408801c135cSArtem B. Bityutskiy */ 409f40ac9cdSArtem Bityutskiy int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) 410801c135cSArtem B. Bityutskiy { 411801c135cSArtem B. Bityutskiy struct ubi_volume *vol = desc->vol; 412801c135cSArtem B. Bityutskiy struct ubi_device *ubi = vol->ubi; 413801c135cSArtem B. Bityutskiy int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; 414801c135cSArtem B. Bityutskiy 415c8566350SArtem Bityutskiy dbg_gen("remove UBI volume %d", vol_id); 416801c135cSArtem B. Bityutskiy ubi_assert(desc->mode == UBI_EXCLUSIVE); 417801c135cSArtem B. Bityutskiy ubi_assert(vol == ubi->volumes[vol_id]); 418801c135cSArtem B. Bityutskiy 419801c135cSArtem B. Bityutskiy if (ubi->ro_mode) 420801c135cSArtem B. Bityutskiy return -EROFS; 421801c135cSArtem B. Bityutskiy 422d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 423d05c77a8SArtem Bityutskiy if (vol->ref_count > 1) { 424d05c77a8SArtem Bityutskiy /* 425d05c77a8SArtem Bityutskiy * The volume is busy, probably someone is reading one of its 426d05c77a8SArtem Bityutskiy * sysfs files. 427d05c77a8SArtem Bityutskiy */ 428d05c77a8SArtem Bityutskiy err = -EBUSY; 429d05c77a8SArtem Bityutskiy goto out_unlock; 430d05c77a8SArtem Bityutskiy } 431d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = NULL; 432d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 433d05c77a8SArtem Bityutskiy 434801c135cSArtem B. Bityutskiy err = ubi_destroy_gluebi(vol); 435801c135cSArtem B. Bityutskiy if (err) 436d05c77a8SArtem Bityutskiy goto out_err; 437801c135cSArtem B. Bityutskiy 438f40ac9cdSArtem Bityutskiy if (!no_vtbl) { 439801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, NULL); 440801c135cSArtem B. Bityutskiy if (err) 441d05c77a8SArtem Bityutskiy goto out_err; 442f40ac9cdSArtem Bityutskiy } 443801c135cSArtem B. Bityutskiy 444801c135cSArtem B. Bityutskiy for (i = 0; i < vol->reserved_pebs; i++) { 44589b96b69SArtem Bityutskiy err = ubi_eba_unmap_leb(ubi, vol, i); 446801c135cSArtem B. Bityutskiy if (err) 447d05c77a8SArtem Bityutskiy goto out_err; 448801c135cSArtem B. Bityutskiy } 449801c135cSArtem B. Bityutskiy 450801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 451801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 452801c135cSArtem B. Bityutskiy 453801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 454801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= reserved_pebs; 455801c135cSArtem B. Bityutskiy ubi->avail_pebs += reserved_pebs; 456801c135cSArtem B. Bityutskiy i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; 457801c135cSArtem B. Bityutskiy if (i > 0) { 458801c135cSArtem B. Bityutskiy i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; 459801c135cSArtem B. Bityutskiy ubi->avail_pebs -= i; 460801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += i; 461801c135cSArtem B. Bityutskiy ubi->beb_rsvd_pebs += i; 462801c135cSArtem B. Bityutskiy if (i > 0) 463801c135cSArtem B. Bityutskiy ubi_msg("reserve more %d PEBs", i); 464801c135cSArtem B. Bityutskiy } 465801c135cSArtem B. Bityutskiy ubi->vol_count -= 1; 466801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 467801c135cSArtem B. Bityutskiy 468f40ac9cdSArtem Bityutskiy if (!no_vtbl) 469c8566350SArtem Bityutskiy err = paranoid_check_volumes(ubi); 470c8566350SArtem Bityutskiy return err; 471d05c77a8SArtem Bityutskiy 472d05c77a8SArtem Bityutskiy out_err: 473d05c77a8SArtem Bityutskiy ubi_err("cannot remove volume %d, error %d", vol_id, err); 474d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 475d05c77a8SArtem Bityutskiy ubi->volumes[vol_id] = vol; 476d05c77a8SArtem Bityutskiy out_unlock: 477d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 478cae0a771SArtem Bityutskiy return err; 479801c135cSArtem B. Bityutskiy } 480801c135cSArtem B. Bityutskiy 481801c135cSArtem B. Bityutskiy /** 482801c135cSArtem B. Bityutskiy * ubi_resize_volume - re-size volume. 483801c135cSArtem B. Bityutskiy * @desc: volume descriptor 484801c135cSArtem B. Bityutskiy * @reserved_pebs: new size in physical eraseblocks 485801c135cSArtem B. Bityutskiy * 48640e4d0c1SArtem Bityutskiy * This function re-sizes the volume and returns zero in case of success, and a 48740e4d0c1SArtem Bityutskiy * negative error code in case of failure. The caller has to have the 48840e4d0c1SArtem Bityutskiy * @ubi->volumes_mutex locked. 489801c135cSArtem B. Bityutskiy */ 490801c135cSArtem B. Bityutskiy int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) 491801c135cSArtem B. Bityutskiy { 492801c135cSArtem B. Bityutskiy int i, err, pebs, *new_mapping; 493801c135cSArtem B. Bityutskiy struct ubi_volume *vol = desc->vol; 494801c135cSArtem B. Bityutskiy struct ubi_device *ubi = vol->ubi; 495801c135cSArtem B. Bityutskiy struct ubi_vtbl_record vtbl_rec; 496801c135cSArtem B. Bityutskiy int vol_id = vol->vol_id; 497801c135cSArtem B. Bityutskiy 498801c135cSArtem B. Bityutskiy if (ubi->ro_mode) 499801c135cSArtem B. Bityutskiy return -EROFS; 500801c135cSArtem B. Bityutskiy 501c8566350SArtem Bityutskiy dbg_gen("re-size volume %d to from %d to %d PEBs", 502801c135cSArtem B. Bityutskiy vol_id, vol->reserved_pebs, reserved_pebs); 503801c135cSArtem B. Bityutskiy 504801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_STATIC_VOLUME && 505801c135cSArtem B. Bityutskiy reserved_pebs < vol->used_ebs) { 506801c135cSArtem B. Bityutskiy dbg_err("too small size %d, %d LEBs contain data", 507801c135cSArtem B. Bityutskiy reserved_pebs, vol->used_ebs); 508801c135cSArtem B. Bityutskiy return -EINVAL; 509801c135cSArtem B. Bityutskiy } 510801c135cSArtem B. Bityutskiy 511801c135cSArtem B. Bityutskiy /* If the size is the same, we have nothing to do */ 512801c135cSArtem B. Bityutskiy if (reserved_pebs == vol->reserved_pebs) 513801c135cSArtem B. Bityutskiy return 0; 514801c135cSArtem B. Bityutskiy 515801c135cSArtem B. Bityutskiy new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL); 516801c135cSArtem B. Bityutskiy if (!new_mapping) 517801c135cSArtem B. Bityutskiy return -ENOMEM; 518801c135cSArtem B. Bityutskiy 519801c135cSArtem B. Bityutskiy for (i = 0; i < reserved_pebs; i++) 520801c135cSArtem B. Bityutskiy new_mapping[i] = UBI_LEB_UNMAPPED; 521801c135cSArtem B. Bityutskiy 522d05c77a8SArtem Bityutskiy spin_lock(&ubi->volumes_lock); 523d05c77a8SArtem Bityutskiy if (vol->ref_count > 1) { 524d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 525d05c77a8SArtem Bityutskiy err = -EBUSY; 526d05c77a8SArtem Bityutskiy goto out_free; 527d05c77a8SArtem Bityutskiy } 528d05c77a8SArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 529d05c77a8SArtem Bityutskiy 530d05c77a8SArtem Bityutskiy /* Reserve physical eraseblocks */ 531801c135cSArtem B. Bityutskiy pebs = reserved_pebs - vol->reserved_pebs; 532801c135cSArtem B. Bityutskiy if (pebs > 0) { 533801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 534801c135cSArtem B. Bityutskiy if (pebs > ubi->avail_pebs) { 535801c135cSArtem B. Bityutskiy dbg_err("not enough PEBs: requested %d, available %d", 536801c135cSArtem B. Bityutskiy pebs, ubi->avail_pebs); 537801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 538801c135cSArtem B. Bityutskiy err = -ENOSPC; 539801c135cSArtem B. Bityutskiy goto out_free; 540801c135cSArtem B. Bityutskiy } 541801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 542801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 543801c135cSArtem B. Bityutskiy for (i = 0; i < vol->reserved_pebs; i++) 544801c135cSArtem B. Bityutskiy new_mapping[i] = vol->eba_tbl[i]; 545801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 546801c135cSArtem B. Bityutskiy vol->eba_tbl = new_mapping; 547801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 548801c135cSArtem B. Bityutskiy } 549801c135cSArtem B. Bityutskiy 550801c135cSArtem B. Bityutskiy /* Change volume table record */ 551801c135cSArtem B. Bityutskiy memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); 5523261ebd7SChristoph Hellwig vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); 553801c135cSArtem B. Bityutskiy err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); 554801c135cSArtem B. Bityutskiy if (err) 555801c135cSArtem B. Bityutskiy goto out_acc; 556801c135cSArtem B. Bityutskiy 557801c135cSArtem B. Bityutskiy if (pebs < 0) { 558801c135cSArtem B. Bityutskiy for (i = 0; i < -pebs; i++) { 55989b96b69SArtem Bityutskiy err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); 560801c135cSArtem B. Bityutskiy if (err) 561801c135cSArtem B. Bityutskiy goto out_acc; 562801c135cSArtem B. Bityutskiy } 563801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 564801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 565801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 566801c135cSArtem B. Bityutskiy pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; 567801c135cSArtem B. Bityutskiy if (pebs > 0) { 568801c135cSArtem B. Bityutskiy pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs; 569801c135cSArtem B. Bityutskiy ubi->avail_pebs -= pebs; 570801c135cSArtem B. Bityutskiy ubi->rsvd_pebs += pebs; 571801c135cSArtem B. Bityutskiy ubi->beb_rsvd_pebs += pebs; 572801c135cSArtem B. Bityutskiy if (pebs > 0) 573801c135cSArtem B. Bityutskiy ubi_msg("reserve more %d PEBs", pebs); 574801c135cSArtem B. Bityutskiy } 575801c135cSArtem B. Bityutskiy for (i = 0; i < reserved_pebs; i++) 576801c135cSArtem B. Bityutskiy new_mapping[i] = vol->eba_tbl[i]; 577801c135cSArtem B. Bityutskiy kfree(vol->eba_tbl); 578801c135cSArtem B. Bityutskiy vol->eba_tbl = new_mapping; 579801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 580801c135cSArtem B. Bityutskiy } 581801c135cSArtem B. Bityutskiy 582801c135cSArtem B. Bityutskiy vol->reserved_pebs = reserved_pebs; 583801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 584801c135cSArtem B. Bityutskiy vol->used_ebs = reserved_pebs; 585801c135cSArtem B. Bityutskiy vol->last_eb_bytes = vol->usable_leb_size; 586d08c3b78SVinit Agnihotri vol->used_bytes = 587d08c3b78SVinit Agnihotri (long long)vol->used_ebs * vol->usable_leb_size; 588801c135cSArtem B. Bityutskiy } 589801c135cSArtem B. Bityutskiy 590c8566350SArtem Bityutskiy err = paranoid_check_volumes(ubi); 591c8566350SArtem Bityutskiy return err; 592801c135cSArtem B. Bityutskiy 593801c135cSArtem B. Bityutskiy out_acc: 594801c135cSArtem B. Bityutskiy if (pebs > 0) { 595801c135cSArtem B. Bityutskiy spin_lock(&ubi->volumes_lock); 596801c135cSArtem B. Bityutskiy ubi->rsvd_pebs -= pebs; 597801c135cSArtem B. Bityutskiy ubi->avail_pebs += pebs; 598801c135cSArtem B. Bityutskiy spin_unlock(&ubi->volumes_lock); 599801c135cSArtem B. Bityutskiy } 600801c135cSArtem B. Bityutskiy out_free: 601801c135cSArtem B. Bityutskiy kfree(new_mapping); 602801c135cSArtem B. Bityutskiy return err; 603801c135cSArtem B. Bityutskiy } 604801c135cSArtem B. Bityutskiy 605801c135cSArtem B. Bityutskiy /** 606f40ac9cdSArtem Bityutskiy * ubi_rename_volumes - re-name UBI volumes. 607f40ac9cdSArtem Bityutskiy * @ubi: UBI device description object 608ebaaf1afSArtem Bityutskiy * @rename_list: list of &struct ubi_rename_entry objects 609f40ac9cdSArtem Bityutskiy * 610f40ac9cdSArtem Bityutskiy * This function re-names or removes volumes specified in the re-name list. 611f40ac9cdSArtem Bityutskiy * Returns zero in case of success and a negative error code in case of 612f40ac9cdSArtem Bityutskiy * failure. 613f40ac9cdSArtem Bityutskiy */ 614f40ac9cdSArtem Bityutskiy int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) 615f40ac9cdSArtem Bityutskiy { 616f40ac9cdSArtem Bityutskiy int err; 617f40ac9cdSArtem Bityutskiy struct ubi_rename_entry *re; 618f40ac9cdSArtem Bityutskiy 619f40ac9cdSArtem Bityutskiy err = ubi_vtbl_rename_volumes(ubi, rename_list); 620f40ac9cdSArtem Bityutskiy if (err) 621f40ac9cdSArtem Bityutskiy return err; 622f40ac9cdSArtem Bityutskiy 623f40ac9cdSArtem Bityutskiy list_for_each_entry(re, rename_list, list) { 624f40ac9cdSArtem Bityutskiy if (re->remove) { 625f40ac9cdSArtem Bityutskiy err = ubi_remove_volume(re->desc, 1); 626f40ac9cdSArtem Bityutskiy if (err) 627f40ac9cdSArtem Bityutskiy break; 628f40ac9cdSArtem Bityutskiy } else { 629f40ac9cdSArtem Bityutskiy struct ubi_volume *vol = re->desc->vol; 630f40ac9cdSArtem Bityutskiy 631f40ac9cdSArtem Bityutskiy spin_lock(&ubi->volumes_lock); 632f40ac9cdSArtem Bityutskiy vol->name_len = re->new_name_len; 633f40ac9cdSArtem Bityutskiy memcpy(vol->name, re->new_name, re->new_name_len + 1); 634f40ac9cdSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 635f40ac9cdSArtem Bityutskiy } 636f40ac9cdSArtem Bityutskiy } 637f40ac9cdSArtem Bityutskiy 638f40ac9cdSArtem Bityutskiy if (!err) 639eeb16e87SArtem Bityutskiy err = paranoid_check_volumes(ubi); 640f40ac9cdSArtem Bityutskiy return err; 641f40ac9cdSArtem Bityutskiy } 642f40ac9cdSArtem Bityutskiy 643f40ac9cdSArtem Bityutskiy /** 644801c135cSArtem B. Bityutskiy * ubi_add_volume - add volume. 645801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 64689b96b69SArtem Bityutskiy * @vol: volume description object 647801c135cSArtem B. Bityutskiy * 648d05c77a8SArtem Bityutskiy * This function adds an existing volume and initializes all its data 649d05c77a8SArtem Bityutskiy * structures. Returns zero in case of success and a negative error code in 650801c135cSArtem B. Bityutskiy * case of failure. 651801c135cSArtem B. Bityutskiy */ 65289b96b69SArtem Bityutskiy int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) 653801c135cSArtem B. Bityutskiy { 65489b96b69SArtem Bityutskiy int err, vol_id = vol->vol_id; 65549dfc299SArtem Bityutskiy dev_t dev; 656801c135cSArtem B. Bityutskiy 657c8566350SArtem Bityutskiy dbg_gen("add volume %d", vol_id); 658801c135cSArtem B. Bityutskiy 659801c135cSArtem B. Bityutskiy /* Register character device for the volume */ 660801c135cSArtem B. Bityutskiy cdev_init(&vol->cdev, &ubi_vol_cdev_operations); 661801c135cSArtem B. Bityutskiy vol->cdev.owner = THIS_MODULE; 66249dfc299SArtem Bityutskiy dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); 66349dfc299SArtem Bityutskiy err = cdev_add(&vol->cdev, dev, 1); 664801c135cSArtem B. Bityutskiy if (err) { 66501f7b309SArtem Bityutskiy ubi_err("cannot add character device for volume %d, error %d", 66601f7b309SArtem Bityutskiy vol_id, err); 667801c135cSArtem B. Bityutskiy return err; 668801c135cSArtem B. Bityutskiy } 669801c135cSArtem B. Bityutskiy 670801c135cSArtem B. Bityutskiy err = ubi_create_gluebi(ubi, vol); 671801c135cSArtem B. Bityutskiy if (err) 672801c135cSArtem B. Bityutskiy goto out_cdev; 673801c135cSArtem B. Bityutskiy 674801c135cSArtem B. Bityutskiy vol->dev.release = vol_release; 675801c135cSArtem B. Bityutskiy vol->dev.parent = &ubi->dev; 67649dfc299SArtem Bityutskiy vol->dev.devt = dev; 677801c135cSArtem B. Bityutskiy vol->dev.class = ubi_class; 678475b44c1SKay Sievers dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); 679801c135cSArtem B. Bityutskiy err = device_register(&vol->dev); 680801c135cSArtem B. Bityutskiy if (err) 681801c135cSArtem B. Bityutskiy goto out_gluebi; 682801c135cSArtem B. Bityutskiy 683801c135cSArtem B. Bityutskiy err = volume_sysfs_init(ubi, vol); 684801c135cSArtem B. Bityutskiy if (err) { 685801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 686801c135cSArtem B. Bityutskiy err = ubi_destroy_gluebi(vol); 687801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 688801c135cSArtem B. Bityutskiy return err; 689801c135cSArtem B. Bityutskiy } 690801c135cSArtem B. Bityutskiy 691c8566350SArtem Bityutskiy err = paranoid_check_volumes(ubi); 692c8566350SArtem Bityutskiy return err; 693801c135cSArtem B. Bityutskiy 694801c135cSArtem B. Bityutskiy out_gluebi: 695801c135cSArtem B. Bityutskiy err = ubi_destroy_gluebi(vol); 696801c135cSArtem B. Bityutskiy out_cdev: 697801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 698801c135cSArtem B. Bityutskiy return err; 699801c135cSArtem B. Bityutskiy } 700801c135cSArtem B. Bityutskiy 701801c135cSArtem B. Bityutskiy /** 702801c135cSArtem B. Bityutskiy * ubi_free_volume - free volume. 703801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 70489b96b69SArtem Bityutskiy * @vol: volume description object 705801c135cSArtem B. Bityutskiy * 70689b96b69SArtem Bityutskiy * This function frees all resources for volume @vol but does not remove it. 707801c135cSArtem B. Bityutskiy * Used only when the UBI device is detached. 708801c135cSArtem B. Bityutskiy */ 70989b96b69SArtem Bityutskiy void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) 710801c135cSArtem B. Bityutskiy { 711801c135cSArtem B. Bityutskiy int err; 712801c135cSArtem B. Bityutskiy 713c8566350SArtem Bityutskiy dbg_gen("free volume %d", vol->vol_id); 714801c135cSArtem B. Bityutskiy 71589b96b69SArtem Bityutskiy ubi->volumes[vol->vol_id] = NULL; 716d05c77a8SArtem Bityutskiy err = ubi_destroy_gluebi(vol); 717801c135cSArtem B. Bityutskiy cdev_del(&vol->cdev); 718801c135cSArtem B. Bityutskiy volume_sysfs_close(vol); 719801c135cSArtem B. Bityutskiy } 720801c135cSArtem B. Bityutskiy 721801c135cSArtem B. Bityutskiy #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID 722801c135cSArtem B. Bityutskiy 723801c135cSArtem B. Bityutskiy /** 724801c135cSArtem B. Bityutskiy * paranoid_check_volume - check volume information. 725801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 726801c135cSArtem B. Bityutskiy * @vol_id: volume ID 727c8566350SArtem Bityutskiy * 728c8566350SArtem Bityutskiy * Returns zero if volume is all right and a a negative error code if not. 729801c135cSArtem B. Bityutskiy */ 730c8566350SArtem Bityutskiy static int paranoid_check_volume(struct ubi_device *ubi, int vol_id) 731801c135cSArtem B. Bityutskiy { 732801c135cSArtem B. Bityutskiy int idx = vol_id2idx(ubi, vol_id); 733801c135cSArtem B. Bityutskiy int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; 734b89044bfSArtem Bityutskiy const struct ubi_volume *vol; 735801c135cSArtem B. Bityutskiy long long n; 736801c135cSArtem B. Bityutskiy const char *name; 737801c135cSArtem B. Bityutskiy 738b89044bfSArtem Bityutskiy spin_lock(&ubi->volumes_lock); 7393261ebd7SChristoph Hellwig reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); 740b89044bfSArtem Bityutskiy vol = ubi->volumes[idx]; 741801c135cSArtem B. Bityutskiy 742801c135cSArtem B. Bityutskiy if (!vol) { 743801c135cSArtem B. Bityutskiy if (reserved_pebs) { 744801c135cSArtem B. Bityutskiy ubi_err("no volume info, but volume exists"); 745801c135cSArtem B. Bityutskiy goto fail; 746801c135cSArtem B. Bityutskiy } 747b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 748c8566350SArtem Bityutskiy return 0; 749801c135cSArtem B. Bityutskiy } 750801c135cSArtem B. Bityutskiy 751801c135cSArtem B. Bityutskiy if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || 752801c135cSArtem B. Bityutskiy vol->name_len < 0) { 753801c135cSArtem B. Bityutskiy ubi_err("negative values"); 754801c135cSArtem B. Bityutskiy goto fail; 755801c135cSArtem B. Bityutskiy } 756801c135cSArtem B. Bityutskiy if (vol->alignment > ubi->leb_size || vol->alignment == 0) { 757801c135cSArtem B. Bityutskiy ubi_err("bad alignment"); 758801c135cSArtem B. Bityutskiy goto fail; 759801c135cSArtem B. Bityutskiy } 760801c135cSArtem B. Bityutskiy 761cadb40ccSKyungmin Park n = vol->alignment & (ubi->min_io_size - 1); 762801c135cSArtem B. Bityutskiy if (vol->alignment != 1 && n) { 763801c135cSArtem B. Bityutskiy ubi_err("alignment is not multiple of min I/O unit"); 764801c135cSArtem B. Bityutskiy goto fail; 765801c135cSArtem B. Bityutskiy } 766801c135cSArtem B. Bityutskiy 767801c135cSArtem B. Bityutskiy n = ubi->leb_size % vol->alignment; 768801c135cSArtem B. Bityutskiy if (vol->data_pad != n) { 769801c135cSArtem B. Bityutskiy ubi_err("bad data_pad, has to be %lld", n); 770801c135cSArtem B. Bityutskiy goto fail; 771801c135cSArtem B. Bityutskiy } 772801c135cSArtem B. Bityutskiy 773801c135cSArtem B. Bityutskiy if (vol->vol_type != UBI_DYNAMIC_VOLUME && 774801c135cSArtem B. Bityutskiy vol->vol_type != UBI_STATIC_VOLUME) { 775801c135cSArtem B. Bityutskiy ubi_err("bad vol_type"); 776801c135cSArtem B. Bityutskiy goto fail; 777801c135cSArtem B. Bityutskiy } 778801c135cSArtem B. Bityutskiy 779801c135cSArtem B. Bityutskiy if (vol->upd_marker && vol->corrupted) { 780801c135cSArtem B. Bityutskiy dbg_err("update marker and corrupted simultaneously"); 781801c135cSArtem B. Bityutskiy goto fail; 782801c135cSArtem B. Bityutskiy } 783801c135cSArtem B. Bityutskiy 784801c135cSArtem B. Bityutskiy if (vol->reserved_pebs > ubi->good_peb_count) { 785801c135cSArtem B. Bityutskiy ubi_err("too large reserved_pebs"); 786801c135cSArtem B. Bityutskiy goto fail; 787801c135cSArtem B. Bityutskiy } 788801c135cSArtem B. Bityutskiy 789801c135cSArtem B. Bityutskiy n = ubi->leb_size - vol->data_pad; 790801c135cSArtem B. Bityutskiy if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { 791801c135cSArtem B. Bityutskiy ubi_err("bad usable_leb_size, has to be %lld", n); 792801c135cSArtem B. Bityutskiy goto fail; 793801c135cSArtem B. Bityutskiy } 794801c135cSArtem B. Bityutskiy 795801c135cSArtem B. Bityutskiy if (vol->name_len > UBI_VOL_NAME_MAX) { 796801c135cSArtem B. Bityutskiy ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); 797801c135cSArtem B. Bityutskiy goto fail; 798801c135cSArtem B. Bityutskiy } 799801c135cSArtem B. Bityutskiy 800801c135cSArtem B. Bityutskiy if (!vol->name) { 801801c135cSArtem B. Bityutskiy ubi_err("NULL volume name"); 802801c135cSArtem B. Bityutskiy goto fail; 803801c135cSArtem B. Bityutskiy } 804801c135cSArtem B. Bityutskiy 805801c135cSArtem B. Bityutskiy n = strnlen(vol->name, vol->name_len + 1); 806801c135cSArtem B. Bityutskiy if (n != vol->name_len) { 807801c135cSArtem B. Bityutskiy ubi_err("bad name_len %lld", n); 808801c135cSArtem B. Bityutskiy goto fail; 809801c135cSArtem B. Bityutskiy } 810801c135cSArtem B. Bityutskiy 811d08c3b78SVinit Agnihotri n = (long long)vol->used_ebs * vol->usable_leb_size; 812801c135cSArtem B. Bityutskiy if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 813896c0c06SArtem Bityutskiy if (vol->corrupted) { 814801c135cSArtem B. Bityutskiy ubi_err("corrupted dynamic volume"); 815801c135cSArtem B. Bityutskiy goto fail; 816801c135cSArtem B. Bityutskiy } 817801c135cSArtem B. Bityutskiy if (vol->used_ebs != vol->reserved_pebs) { 818801c135cSArtem B. Bityutskiy ubi_err("bad used_ebs"); 819801c135cSArtem B. Bityutskiy goto fail; 820801c135cSArtem B. Bityutskiy } 821801c135cSArtem B. Bityutskiy if (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 != n) { 826801c135cSArtem B. Bityutskiy ubi_err("bad used_bytes"); 827801c135cSArtem B. Bityutskiy goto fail; 828801c135cSArtem B. Bityutskiy } 829801c135cSArtem B. Bityutskiy } else { 830801c135cSArtem B. Bityutskiy if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { 831801c135cSArtem B. Bityutskiy ubi_err("bad used_ebs"); 832801c135cSArtem B. Bityutskiy goto fail; 833801c135cSArtem B. Bityutskiy } 834801c135cSArtem B. Bityutskiy if (vol->last_eb_bytes < 0 || 835801c135cSArtem B. Bityutskiy vol->last_eb_bytes > vol->usable_leb_size) { 836801c135cSArtem B. Bityutskiy ubi_err("bad last_eb_bytes"); 837801c135cSArtem B. Bityutskiy goto fail; 838801c135cSArtem B. Bityutskiy } 839801c135cSArtem B. Bityutskiy if (vol->used_bytes < 0 || vol->used_bytes > n || 840801c135cSArtem B. Bityutskiy vol->used_bytes < n - vol->usable_leb_size) { 841801c135cSArtem B. Bityutskiy ubi_err("bad used_bytes"); 842801c135cSArtem B. Bityutskiy goto fail; 843801c135cSArtem B. Bityutskiy } 844801c135cSArtem B. Bityutskiy } 845801c135cSArtem B. Bityutskiy 8463261ebd7SChristoph Hellwig alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment); 8473261ebd7SChristoph Hellwig data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad); 8483261ebd7SChristoph Hellwig name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len); 849801c135cSArtem B. Bityutskiy upd_marker = ubi->vtbl[vol_id].upd_marker; 850801c135cSArtem B. Bityutskiy name = &ubi->vtbl[vol_id].name[0]; 851801c135cSArtem B. Bityutskiy if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) 852801c135cSArtem B. Bityutskiy vol_type = UBI_DYNAMIC_VOLUME; 853801c135cSArtem B. Bityutskiy else 854801c135cSArtem B. Bityutskiy vol_type = UBI_STATIC_VOLUME; 855801c135cSArtem B. Bityutskiy 856801c135cSArtem B. Bityutskiy if (alignment != vol->alignment || data_pad != vol->data_pad || 857801c135cSArtem B. Bityutskiy upd_marker != vol->upd_marker || vol_type != vol->vol_type || 858801c135cSArtem B. Bityutskiy name_len != vol->name_len || strncmp(name, vol->name, name_len)) { 859801c135cSArtem B. Bityutskiy ubi_err("volume info is different"); 860801c135cSArtem B. Bityutskiy goto fail; 861801c135cSArtem B. Bityutskiy } 862801c135cSArtem B. Bityutskiy 863b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 864c8566350SArtem Bityutskiy return 0; 865801c135cSArtem B. Bityutskiy 866801c135cSArtem B. Bityutskiy fail: 86794784d91SArtem Bityutskiy ubi_err("paranoid check failed for volume %d", vol_id); 868f40ac9cdSArtem Bityutskiy if (vol) 869801c135cSArtem B. Bityutskiy ubi_dbg_dump_vol_info(vol); 870801c135cSArtem B. Bityutskiy ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); 871b89044bfSArtem Bityutskiy spin_unlock(&ubi->volumes_lock); 872c8566350SArtem Bityutskiy return -EINVAL; 873801c135cSArtem B. Bityutskiy } 874801c135cSArtem B. Bityutskiy 875801c135cSArtem B. Bityutskiy /** 876801c135cSArtem B. Bityutskiy * paranoid_check_volumes - check information about all volumes. 877801c135cSArtem B. Bityutskiy * @ubi: UBI device description object 878c8566350SArtem Bityutskiy * 879c8566350SArtem Bityutskiy * Returns zero if volumes are all right and a a negative error code if not. 880801c135cSArtem B. Bityutskiy */ 881c8566350SArtem Bityutskiy static int paranoid_check_volumes(struct ubi_device *ubi) 882801c135cSArtem B. Bityutskiy { 883c8566350SArtem Bityutskiy int i, err = 0; 884801c135cSArtem B. Bityutskiy 885c8566350SArtem Bityutskiy for (i = 0; i < ubi->vtbl_slots; i++) { 886c8566350SArtem Bityutskiy err = paranoid_check_volume(ubi, i); 887c8566350SArtem Bityutskiy if (err) 888c8566350SArtem Bityutskiy break; 889c8566350SArtem Bityutskiy } 890c8566350SArtem Bityutskiy 891c8566350SArtem Bityutskiy return err; 892801c135cSArtem B. Bityutskiy } 893801c135cSArtem B. Bityutskiy #endif 894