848 lines · 24.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) International Business Machines Corp., 2006 * * Author: Artem Bityutskiy (Битюцкий Артём) */ /* This file mostly implements UBI kernel API functions */ #include <linux/module.h>#include <linux/err.h>#include <linux/slab.h>#include <linux/namei.h>#include <linux/fs.h>#include <asm/div64.h>#include "ubi.h" /** * ubi_do_get_device_info - get information about UBI device. * @ubi: UBI device description object * @di: the information is stored here * * This function is the same as 'ubi_get_device_info()', but it assumes the UBI * device is locked and cannot disappear. */void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di){	di->ubi_num = ubi->ubi_num;	di->leb_size = ubi->leb_size;	di->leb_start = ubi->leb_start;	di->min_io_size = ubi->min_io_size;	di->max_write_size = ubi->max_write_size;	di->ro_mode = ubi->ro_mode;	di->cdev = ubi->cdev.dev;}EXPORT_SYMBOL_GPL(ubi_do_get_device_info); /** * ubi_get_device_info - get information about UBI device. * @ubi_num: UBI device number * @di: the information is stored here * * This function returns %0 in case of success, %-EINVAL if the UBI device * number is invalid, and %-ENODEV if there is no such UBI device. */int ubi_get_device_info(int ubi_num, struct ubi_device_info *di){	struct ubi_device *ubi; 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)		return -EINVAL;	ubi = ubi_get_device(ubi_num);	if (!ubi)		return -ENODEV;	ubi_do_get_device_info(ubi, di);	ubi_put_device(ubi);	return 0;}EXPORT_SYMBOL_GPL(ubi_get_device_info); /** * ubi_do_get_volume_info - get information about UBI volume. * @ubi: UBI device description object * @vol: volume description object * @vi: the information is stored here */void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,			    struct ubi_volume_info *vi){	vi->vol_id = vol->vol_id;	vi->ubi_num = ubi->ubi_num;	vi->size = vol->reserved_pebs;	vi->used_bytes = vol->used_bytes;	vi->vol_type = vol->vol_type;	vi->corrupted = vol->corrupted;	vi->upd_marker = vol->upd_marker;	vi->alignment = vol->alignment;	vi->usable_leb_size = vol->usable_leb_size;	vi->name_len = vol->name_len;	vi->name = vol->name;	vi->cdev = vol->cdev.dev;	vi->dev = &vol->dev;} /** * ubi_get_volume_info - get information about UBI volume. * @desc: volume descriptor * @vi: the information is stored here */void ubi_get_volume_info(struct ubi_volume_desc *desc,			 struct ubi_volume_info *vi){	ubi_do_get_volume_info(desc->vol->ubi, desc->vol, vi);}EXPORT_SYMBOL_GPL(ubi_get_volume_info); /** * ubi_open_volume - open UBI volume. * @ubi_num: UBI device number * @vol_id: volume ID * @mode: open mode * * The @mode parameter specifies if the volume should be opened in read-only * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that * nobody else will be able to open this volume. UBI allows to have many volume * readers and one writer at a time. * * If a static volume is being opened for the first time since boot, it will be * checked by this function, which means it will be fully read and the CRC * checksum of each logical eraseblock will be checked. * * This function returns volume descriptor in case of success and a negative * error code in case of failure. */struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode){	int err;	struct ubi_volume_desc *desc;	struct ubi_device *ubi;	struct ubi_volume *vol; 	dbg_gen("open device %d, volume %d, mode %d", ubi_num, vol_id, mode); 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)		return ERR_PTR(-EINVAL); 	if (mode != UBI_READONLY && mode != UBI_READWRITE &&	    mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)		return ERR_PTR(-EINVAL); 	/*	 * First of all, we have to get the UBI device to prevent its removal.	 */	ubi = ubi_get_device(ubi_num);	if (!ubi)		return ERR_PTR(-ENODEV); 	if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {		err = -EINVAL;		goto out_put_ubi;	} 	desc = kmalloc_obj(struct ubi_volume_desc);	if (!desc) {		err = -ENOMEM;		goto out_put_ubi;	} 	err = -ENODEV;	if (!try_module_get(THIS_MODULE))		goto out_free; 	spin_lock(&ubi->volumes_lock);	vol = ubi->volumes[vol_id];	if (!vol || vol->is_dead)		goto out_unlock; 	err = -EBUSY;	switch (mode) {	case UBI_READONLY:		if (vol->exclusive)			goto out_unlock;		vol->readers += 1;		break; 	case UBI_READWRITE:		if (vol->exclusive || vol->writers > 0)			goto out_unlock;		vol->writers += 1;		break; 	case UBI_EXCLUSIVE:		if (vol->exclusive || vol->writers || vol->readers ||		    vol->metaonly)			goto out_unlock;		vol->exclusive = 1;		break; 	case UBI_METAONLY:		if (vol->metaonly || vol->exclusive)			goto out_unlock;		vol->metaonly = 1;		break;	}	get_device(&vol->dev);	vol->ref_count += 1;	spin_unlock(&ubi->volumes_lock); 	desc->vol = vol;	desc->mode = mode; 	mutex_lock(&ubi->ckvol_mutex);	if (!vol->checked && !vol->skip_check) {		/* This is the first open - check the volume */		err = ubi_check_volume(ubi, vol_id);		if (err < 0) {			mutex_unlock(&ubi->ckvol_mutex);			ubi_close_volume(desc);			return ERR_PTR(err);		}		if (err == 1) {			ubi_warn(ubi, "volume %d on UBI device %d is corrupted",				 vol_id, ubi->ubi_num);			vol->corrupted = 1;		}		vol->checked = 1;	}	mutex_unlock(&ubi->ckvol_mutex); 	return desc; out_unlock:	spin_unlock(&ubi->volumes_lock);	module_put(THIS_MODULE);out_free:	kfree(desc);out_put_ubi:	ubi_err(ubi, "cannot open device %d, volume %d, error %d",		ubi_num, vol_id, err);	ubi_put_device(ubi);	return ERR_PTR(err);}EXPORT_SYMBOL_GPL(ubi_open_volume); /** * ubi_open_volume_nm - open UBI volume by name. * @ubi_num: UBI device number * @name: volume name * @mode: open mode * * This function is similar to 'ubi_open_volume()', but opens a volume by name. */struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,					   int mode){	int i, vol_id = -1, len;	struct ubi_device *ubi;	struct ubi_volume_desc *ret; 	dbg_gen("open device %d, volume %s, mode %d", ubi_num, name, mode); 	if (!name)		return ERR_PTR(-EINVAL); 	len = strnlen(name, UBI_VOL_NAME_MAX + 1);	if (len > UBI_VOL_NAME_MAX)		return ERR_PTR(-EINVAL); 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)		return ERR_PTR(-EINVAL); 	ubi = ubi_get_device(ubi_num);	if (!ubi)		return ERR_PTR(-ENODEV); 	spin_lock(&ubi->volumes_lock);	/* Walk all volumes of this UBI device */	for (i = 0; i < ubi->vtbl_slots; i++) {		struct ubi_volume *vol = ubi->volumes[i]; 		if (vol && len == vol->name_len && !strcmp(name, vol->name)) {			vol_id = i;			break;		}	}	spin_unlock(&ubi->volumes_lock); 	if (vol_id >= 0)		ret = ubi_open_volume(ubi_num, vol_id, mode);	else		ret = ERR_PTR(-ENODEV); 	/*	 * We should put the UBI device even in case of success, because	 * 'ubi_open_volume()' took a reference as well.	 */	ubi_put_device(ubi);	return ret;}EXPORT_SYMBOL_GPL(ubi_open_volume_nm); /** * ubi_get_num_by_path - get UBI device and volume number from device path * @pathname: volume character device node path * @ubi_num: pointer to UBI device number to be set * @vol_id: pointer to UBI volume ID to be set * * Returns 0 on success and sets ubi_num and vol_id, returns error otherwise. */int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id){	int error;	struct path path;	struct kstat stat; 	error = kern_path(pathname, LOOKUP_FOLLOW, &path);	if (error)		return error; 	error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);	path_put(&path);	if (error)		return error; 	if (!S_ISCHR(stat.mode))		return -EINVAL; 	*ubi_num = ubi_major2num(MAJOR(stat.rdev));	*vol_id = MINOR(stat.rdev) - 1; 	if (*vol_id < 0 || *ubi_num < 0)		return -ENODEV; 	return 0;} /** * ubi_open_volume_path - open UBI volume by its character device node path. * @pathname: volume character device node path * @mode: open mode * * This function is similar to 'ubi_open_volume()', but opens a volume the path * to its character device node. */struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode){	int error, ubi_num, vol_id; 	dbg_gen("open volume %s, mode %d", pathname, mode); 	if (!pathname || !*pathname)		return ERR_PTR(-EINVAL); 	error = ubi_get_num_by_path(pathname, &ubi_num, &vol_id);	if (error)		return ERR_PTR(error); 	return ubi_open_volume(ubi_num, vol_id, mode);}EXPORT_SYMBOL_GPL(ubi_open_volume_path); /** * ubi_close_volume - close UBI volume. * @desc: volume descriptor */void ubi_close_volume(struct ubi_volume_desc *desc){	struct ubi_volume *vol = desc->vol;	struct ubi_device *ubi = vol->ubi; 	dbg_gen("close device %d, volume %d, mode %d",		ubi->ubi_num, vol->vol_id, desc->mode); 	spin_lock(&ubi->volumes_lock);	switch (desc->mode) {	case UBI_READONLY:		vol->readers -= 1;		break;	case UBI_READWRITE:		vol->writers -= 1;		break;	case UBI_EXCLUSIVE:		vol->exclusive = 0;		break;	case UBI_METAONLY:		vol->metaonly = 0;		break;	}	vol->ref_count -= 1;	spin_unlock(&ubi->volumes_lock); 	kfree(desc);	put_device(&vol->dev);	ubi_put_device(ubi);	module_put(THIS_MODULE);}EXPORT_SYMBOL_GPL(ubi_close_volume); /** * leb_read_sanity_check - does sanity checks on read requests. * @desc: volume descriptor * @lnum: logical eraseblock number to read from * @offset: offset within the logical eraseblock to read from * @len: how many bytes to read * * This function is used by ubi_leb_read() and ubi_leb_read_sg() * to perform sanity checks. */static int leb_read_sanity_check(struct ubi_volume_desc *desc, int lnum,				 int offset, int len){	struct ubi_volume *vol = desc->vol;	struct ubi_device *ubi = vol->ubi;	int vol_id = vol->vol_id; 	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||	    offset + len > vol->usable_leb_size)		return -EINVAL; 	if (vol->vol_type == UBI_STATIC_VOLUME) {		if (vol->used_ebs == 0)			/* Empty static UBI volume */			return 0;		if (lnum == vol->used_ebs - 1 &&		    offset + len > vol->last_eb_bytes)			return -EINVAL;	} 	if (vol->upd_marker)		return -EBADF; 	return 0;} /** * ubi_leb_read - read data. * @desc: volume descriptor * @lnum: logical eraseblock number to read from * @buf: buffer where to store the read data * @offset: offset within the logical eraseblock to read from * @len: how many bytes to read * @check: whether UBI has to check the read data's CRC or not. * * This function reads data from offset @offset of logical eraseblock @lnum and * stores the data at @buf. When reading from static volumes, @check specifies * whether the data has to be checked or not. If yes, the whole logical * eraseblock will be read and its CRC checksum will be checked (i.e., the CRC * checksum is per-eraseblock). So checking may substantially slow down the * read speed. The @check argument is ignored for dynamic volumes. * * In case of success, this function returns zero. In case of failure, this * function returns a negative error code. * * %-EBADMSG error code is returned: * o for both static and dynamic volumes if MTD driver has detected a data *   integrity problem (unrecoverable ECC checksum mismatch in case of NAND); * o for static volumes in case of data CRC mismatch. * * If the volume is damaged because of an interrupted update this function just * returns immediately with %-EBADF error code. */int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,		 int len, int check){	struct ubi_volume *vol = desc->vol;	struct ubi_device *ubi = vol->ubi;	int err, vol_id = vol->vol_id; 	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); 	err = leb_read_sanity_check(desc, lnum, offset, len);	if (err < 0)		return err; 	if (len == 0)		return 0; 	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {		ubi_warn(ubi, "mark volume %d as corrupted", vol_id);		vol->corrupted = 1;	} 	return err;}EXPORT_SYMBOL_GPL(ubi_leb_read);  /** * ubi_leb_read_sg - read data into a scatter gather list. * @desc: volume descriptor * @lnum: logical eraseblock number to read from * @sgl: UBI scatter gather list to store the read data * @offset: offset within the logical eraseblock to read from * @len: how many bytes to read * @check: whether UBI has to check the read data's CRC or not. * * This function works exactly like ubi_leb_read_sg(). But instead of * storing the read data into a buffer it writes to an UBI scatter gather * list. */int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,		    int offset, int len, int check){	struct ubi_volume *vol = desc->vol;	struct ubi_device *ubi = vol->ubi;	int err, vol_id = vol->vol_id; 	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); 	err = leb_read_sanity_check(desc, lnum, offset, len);	if (err < 0)		return err; 	if (len == 0)		return 0; 	err = ubi_eba_read_leb_sg(ubi, vol, sgl, lnum, offset, len, check);	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {

Lines 1–500 of 848.