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 + -
显示快捷键?