build.c
来自「linux 内核源代码」· C语言 代码 · 共 864 行 · 第 1/2 页
C
864 行
/* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2007 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Artem Bityutskiy (Битюцкий Артём), * Frank Haverkamp *//* * This file includes UBI initialization and building of UBI devices. At the * moment UBI devices may only be added while UBI is initialized, but dynamic * device add/remove functionality is planned. Also, at the moment we only * attach UBI devices by scanning, which will become a bottleneck when flashes * reach certain large size. Then one may improve UBI and add other methods. */#include <linux/err.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/stringify.h>#include <linux/stat.h>#include <linux/log2.h>#include "ubi.h"/* Maximum length of the 'mtd=' parameter */#define MTD_PARAM_LEN_MAX 64/** * struct mtd_dev_param - MTD device parameter description data structure. * @name: MTD device name or number string * @vid_hdr_offs: VID header offset * @data_offs: data offset */struct mtd_dev_param{ char name[MTD_PARAM_LEN_MAX]; int vid_hdr_offs; int data_offs;};/* Numbers of elements set in the @mtd_dev_param array */static int mtd_devs = 0;/* MTD devices specification parameters */static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];/* Number of UBI devices in system */int ubi_devices_cnt;/* All UBI devices in system */struct ubi_device *ubi_devices[UBI_MAX_DEVICES];/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */struct class *ubi_class;/* "Show" method for files in '/<sysfs>/class/ubi/' */static ssize_t ubi_version_show(struct class *class, char *buf){ return sprintf(buf, "%d\n", UBI_VERSION);}/* UBI version attribute ('/<sysfs>/class/ubi/version') */static struct class_attribute ubi_version = __ATTR(version, S_IRUGO, ubi_version_show, NULL);static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf);/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */static struct device_attribute dev_eraseblock_size = __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_avail_eraseblocks = __ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_total_eraseblocks = __ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_volumes_count = __ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_max_ec = __ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_reserved_for_bad = __ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_bad_peb_count = __ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_max_vol_count = __ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_min_io_size = __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);static struct device_attribute dev_bgt_enabled = __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf){ const struct ubi_device *ubi; ubi = container_of(dev, struct ubi_device, dev); if (attr == &dev_eraseblock_size) return sprintf(buf, "%d\n", ubi->leb_size); else if (attr == &dev_avail_eraseblocks) return sprintf(buf, "%d\n", ubi->avail_pebs); else if (attr == &dev_total_eraseblocks) return sprintf(buf, "%d\n", ubi->good_peb_count); else if (attr == &dev_volumes_count) return sprintf(buf, "%d\n", ubi->vol_count); else if (attr == &dev_max_ec) return sprintf(buf, "%d\n", ubi->max_ec); else if (attr == &dev_reserved_for_bad) return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); else if (attr == &dev_bad_peb_count) return sprintf(buf, "%d\n", ubi->bad_peb_count); else if (attr == &dev_max_vol_count) return sprintf(buf, "%d\n", ubi->vtbl_slots); else if (attr == &dev_min_io_size) return sprintf(buf, "%d\n", ubi->min_io_size); else if (attr == &dev_bgt_enabled) return sprintf(buf, "%d\n", ubi->thread_enabled); else BUG(); return 0;}/* Fake "release" method for UBI devices */static void dev_release(struct device *dev) { }/** * ubi_sysfs_init - initialize sysfs for an UBI device. * @ubi: UBI device description object * * This function returns zero in case of success and a negative error code in * case of failure. */static int ubi_sysfs_init(struct ubi_device *ubi){ int err; ubi->dev.release = dev_release; ubi->dev.devt = MKDEV(ubi->major, 0); ubi->dev.class = ubi_class; sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); err = device_register(&ubi->dev); if (err) goto out; err = device_create_file(&ubi->dev, &dev_eraseblock_size); if (err) goto out_unregister; err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); if (err) goto out_eraseblock_size; err = device_create_file(&ubi->dev, &dev_total_eraseblocks); if (err) goto out_avail_eraseblocks; err = device_create_file(&ubi->dev, &dev_volumes_count); if (err) goto out_total_eraseblocks; err = device_create_file(&ubi->dev, &dev_max_ec); if (err) goto out_volumes_count; err = device_create_file(&ubi->dev, &dev_reserved_for_bad); if (err) goto out_volumes_max_ec; err = device_create_file(&ubi->dev, &dev_bad_peb_count); if (err) goto out_reserved_for_bad; err = device_create_file(&ubi->dev, &dev_max_vol_count); if (err) goto out_bad_peb_count; err = device_create_file(&ubi->dev, &dev_min_io_size); if (err) goto out_max_vol_count; err = device_create_file(&ubi->dev, &dev_bgt_enabled); if (err) goto out_min_io_size; return 0;out_min_io_size: device_remove_file(&ubi->dev, &dev_min_io_size);out_max_vol_count: device_remove_file(&ubi->dev, &dev_max_vol_count);out_bad_peb_count: device_remove_file(&ubi->dev, &dev_bad_peb_count);out_reserved_for_bad: device_remove_file(&ubi->dev, &dev_reserved_for_bad);out_volumes_max_ec: device_remove_file(&ubi->dev, &dev_max_ec);out_volumes_count: device_remove_file(&ubi->dev, &dev_volumes_count);out_total_eraseblocks: device_remove_file(&ubi->dev, &dev_total_eraseblocks);out_avail_eraseblocks: device_remove_file(&ubi->dev, &dev_avail_eraseblocks);out_eraseblock_size: device_remove_file(&ubi->dev, &dev_eraseblock_size);out_unregister: device_unregister(&ubi->dev);out: ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); return err;}/** * ubi_sysfs_close - close sysfs for an UBI device. * @ubi: UBI device description object */static void ubi_sysfs_close(struct ubi_device *ubi){ device_remove_file(&ubi->dev, &dev_bgt_enabled); device_remove_file(&ubi->dev, &dev_min_io_size); device_remove_file(&ubi->dev, &dev_max_vol_count); device_remove_file(&ubi->dev, &dev_bad_peb_count); device_remove_file(&ubi->dev, &dev_reserved_for_bad); device_remove_file(&ubi->dev, &dev_max_ec); device_remove_file(&ubi->dev, &dev_volumes_count); device_remove_file(&ubi->dev, &dev_total_eraseblocks); device_remove_file(&ubi->dev, &dev_avail_eraseblocks); device_remove_file(&ubi->dev, &dev_eraseblock_size); device_unregister(&ubi->dev);}/** * kill_volumes - destroy all volumes. * @ubi: UBI device description object */static void kill_volumes(struct ubi_device *ubi){ int i; for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) ubi_free_volume(ubi, i);}/** * uif_init - initialize user interfaces for an UBI device. * @ubi: UBI device description object * * This function returns zero in case of success and a negative error code in * case of failure. */static int uif_init(struct ubi_device *ubi){ int i, err; dev_t dev; mutex_init(&ubi->vtbl_mutex); spin_lock_init(&ubi->volumes_lock); sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); /* * Major numbers for the UBI character devices are allocated * dynamically. Major numbers of volume character devices are * equivalent to ones of the corresponding UBI character device. Minor * numbers of UBI character devices are 0, while minor numbers of * volume character devices start from 1. Thus, we allocate one major * number and ubi->vtbl_slots + 1 minor numbers. */ err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); if (err) { ubi_err("cannot register UBI character devices"); return err; } cdev_init(&ubi->cdev, &ubi_cdev_operations); ubi->major = MAJOR(dev); dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); ubi->cdev.owner = THIS_MODULE; dev = MKDEV(ubi->major, 0); err = cdev_add(&ubi->cdev, dev, 1); if (err) { ubi_err("cannot add character device %s", ubi->ubi_name); goto out_unreg; } err = ubi_sysfs_init(ubi); if (err) goto out_cdev; for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) { err = ubi_add_volume(ubi, i); if (err) goto out_volumes; } return 0;out_volumes: kill_volumes(ubi); ubi_sysfs_close(ubi);out_cdev: cdev_del(&ubi->cdev);out_unreg: unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); return err;}/** * uif_close - close user interfaces for an UBI device. * @ubi: UBI device description object */static void uif_close(struct ubi_device *ubi){ kill_volumes(ubi); ubi_sysfs_close(ubi); cdev_del(&ubi->cdev); unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1);}/** * attach_by_scanning - attach an MTD device using scanning method. * @ubi: UBI device descriptor * * This function returns zero in case of success and a negative error code in * case of failure. * * Note, currently this is the only method to attach UBI devices. Hopefully in * the future we'll have more scalable attaching methods and avoid full media * scanning. But even in this case scanning will be needed as a fall-back * attaching method if there are some on-flash table corruptions. */static int attach_by_scanning(struct ubi_device *ubi){ int err; struct ubi_scan_info *si; si = ubi_scan(ubi); if (IS_ERR(si)) return PTR_ERR(si); ubi->bad_peb_count = si->bad_peb_count; ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count; ubi->max_ec = si->max_ec; ubi->mean_ec = si->mean_ec; err = ubi_read_volume_table(ubi, si); if (err) goto out_si; err = ubi_wl_init_scan(ubi, si); if (err) goto out_vtbl; err = ubi_eba_init_scan(ubi, si); if (err) goto out_wl; ubi_scan_destroy_si(si); return 0;out_wl: ubi_wl_close(ubi);out_vtbl: vfree(ubi->vtbl);out_si: ubi_scan_destroy_si(si); return err;}/** * io_init - initialize I/O unit for a given UBI device. * @ubi: UBI device description object * * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are * assumed: * o EC header is always at offset zero - this cannot be changed; * o VID header starts just after the EC header at the closest address * aligned to @io->@hdrs_min_io_size; * o data starts just after the VID header at the closest address aligned to * @io->@min_io_size * * This function returns zero in case of success and a negative error code in * case of failure. */static int io_init(struct ubi_device *ubi){ if (ubi->mtd->numeraseregions != 0) { /* * Some flashes have several erase regions. Different regions * may have different eraseblock size and other * characteristics. It looks like mostly multi-region flashes * have one "main" region and one or more small regions to * store boot loader code or boot parameters or whatever. I * guess we should just pick the largest region. But this is * not implemented. */ ubi_err("multiple regions, not implemented"); return -EINVAL; } /* * Note, in this implementation we support MTD devices with 0x7FFFFFFF * physical eraseblocks maximum. */ ubi->peb_size = ubi->mtd->erasesize; ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; ubi->flash_size = ubi->mtd->size; if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) ubi->bad_allowed = 1; ubi->min_io_size = ubi->mtd->writesize; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; /* Make sure minimal I/O unit is power of 2 */ if (!is_power_of_2(ubi->min_io_size)) { ubi_err("bad min. I/O unit"); return -EINVAL; } ubi_assert(ubi->hdrs_min_io_size > 0); ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?