Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 897a316c authored by Artem Bityutskiy's avatar Artem Bityutskiy
Browse files

UBI: handle attach ioctl



Actually implement the MTD device attach/detach handlers.

Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent 9b79cc0f
Loading
Loading
Loading
Loading
+54 −26
Original line number Diff line number Diff line
@@ -621,18 +621,19 @@ static int io_init(struct ubi_device *ubi)
/**
 * ubi_attach_mtd_dev - attach an MTD device.
 * @mtd_dev: MTD device description object
 * @ubi_num: number to assign to the new UBI device
 * @vid_hdr_offset: VID header offset
 *
 * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
 * MTD device name, and tries to open it by this name. If it is unable to open,
 * it tries to convert @mtd_dev to an integer and open the MTD device by its
 * number. Returns new UBI device's number in case of success and a negative
 * error code in case of failure.
 * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
 * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
 * which case this function finds a vacant device nubert and assings it
 * automatically. Returns the new UBI device number in case of success and a
 * negative error code in case of failure.
 *
 * Note, the invocations of this function has to be serialized by the
 * @ubi_devices_mutex.
 */
int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset)
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
{
	struct ubi_device *ubi;
	int i, err;
@@ -643,34 +644,59 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset)
	 * Note, this function assumes that UBI devices creations and deletions
	 * are serialized, so it does not take the &ubi_devices_lock.
	 */
	for (i = 0; i < UBI_MAX_DEVICES; i++)
	for (i = 0; i < UBI_MAX_DEVICES; i++) {
		ubi = ubi_devices[i];
		if (ubi && mtd->index == ubi->mtd->index) {
			ubi_err("mtd%d is already attached to ubi%d",
			dbg_err("mtd%d is already attached to ubi%d",
				mtd->index, i);
			return -EEXIST;
		}
	}

	/*
	 * Make sure this MTD device is not emulated on top of an UBI volume
	 * already. Well, generally this recursion works fine, but there are
	 * different problems like the UBI module takes a reference to itself
	 * by attaching (and thus, opening) the emulated MTD device. This
	 * results in inability to unload the module. And in general it makes
	 * no sense to attach emulated MTD devices, so we prohibit this.
	 */
	if (mtd->type == MTD_UBIVOLUME) {
		ubi_err("refuse attaching mtd%d - it is already emulated on "
			"top of UBI", mtd->index);
		return -EINVAL;
	}

	if (ubi_num == UBI_DEV_NUM_AUTO) {
		/* Search for an empty slot in the @ubi_devices array */
	for (i = 0; i < UBI_MAX_DEVICES; i++)
		if (!ubi_devices[i])
		for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
			if (!ubi_devices[ubi_num])
				break;

	if (i == UBI_MAX_DEVICES) {
		ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
		if (ubi_num == UBI_MAX_DEVICES) {
			dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
			return -ENFILE;
		}
	} else {
		if (ubi_num >= UBI_MAX_DEVICES)
			return -EINVAL;

		/* Make sure ubi_num is not busy */
		if (ubi_devices[ubi_num]) {
			dbg_err("ubi%d already exists", ubi_num);
			return -EEXIST;
		}
	}

	ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
	if (!ubi)
		return -ENOMEM;

	ubi->mtd = mtd;
	ubi->ubi_num = i;
	ubi->ubi_num = ubi_num;
	ubi->vid_hdr_offset = vid_hdr_offset;

	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
		mtd->index, ubi->ubi_num, vid_hdr_offset);
		mtd->index, ubi_num, vid_hdr_offset);

	err = io_init(ubi);
	if (err)
@@ -710,7 +736,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset)
		goto out_uif;
	}

	ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num);
	ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
	ubi_msg("MTD device name:            \"%s\"", mtd->name);
	ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
	ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
@@ -739,8 +765,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset)
		wake_up_process(ubi->bgt_thread);
	}

	ubi_devices[ubi->ubi_num] = ubi;
	return ubi->ubi_num;
	ubi_devices[ubi_num] = ubi;
	return ubi_num;

out_uif:
	uif_close(ubi);
@@ -781,23 +807,24 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
	spin_lock(&ubi_devices_lock);
	ubi = ubi_devices[ubi_num];
	if (!ubi) {
		spin_lock(&ubi_devices_lock);
		spin_unlock(&ubi_devices_lock);
		return -EINVAL;
	}

	if (ubi->ref_count) {
		if (!anyway) {
			spin_lock(&ubi_devices_lock);
			spin_unlock(&ubi_devices_lock);
			return -EBUSY;
		}
		/* This may only happen if there is a bug */
		ubi_err("%s reference count %d, destroy anyway",
			ubi->ubi_name, ubi->ref_count);
	}
	ubi_devices[ubi->ubi_num] = NULL;
	ubi_devices[ubi_num] = NULL;
	spin_unlock(&ubi_devices_lock);

	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num);
	ubi_assert(ubi_num == ubi->ubi_num);
	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);

	/*
	 * Before freeing anything, we have to stop the background thread to
@@ -935,7 +962,8 @@ static int __init ubi_init(void)
		}

		mutex_lock(&ubi_devices_mutex);
		err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs);
		err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
					 p->vid_hdr_offs);
		mutex_unlock(&ubi_devices_mutex);
		if (err < 0) {
			put_mtd_device(mtd);
+80 −15
Original line number Diff line number Diff line
@@ -44,17 +44,6 @@
#include <asm/div64.h>
#include "ubi.h"

/*
 * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
 * logical eraseblock erase is a debug-only feature).
 */
#define UBI_CDEV_IOC_MAX_SEQ 2
#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
#define VOL_CDEV_IOC_MAX_SEQ 1
#else
#define VOL_CDEV_IOC_MAX_SEQ 2
#endif

/**
 * get_exclusive - get exclusive access to an UBI volume.
 * @desc: volume descriptor
@@ -582,8 +571,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
		struct ubi_mkvol_req req;

		dbg_msg("create volume");
		err = copy_from_user(&req, argp,
				       sizeof(struct ubi_mkvol_req));
		err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
		if (err) {
			err = -EFAULT;
			break;
@@ -647,8 +635,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
		struct ubi_rsvol_req req;

		dbg_msg("re-size volume");
		err = copy_from_user(&req, argp,
				       sizeof(struct ubi_rsvol_req));
		err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
		if (err) {
			err = -EFAULT;
			break;
@@ -684,8 +671,86 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
	return err;
}

static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
			   unsigned int cmd, unsigned long arg)
{
	int err = 0;
	void __user *argp = (void __user *)arg;

	if (!capable(CAP_SYS_RESOURCE))
		return -EPERM;

	switch (cmd) {
	/* Attach an MTD device command */
	case UBI_IOCATT:
	{
		struct ubi_attach_req req;
		struct mtd_info *mtd;

		dbg_msg("attach MTD device");
		err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
		if (err) {
			err = -EFAULT;
			break;
		}

		if (req.mtd_num < 0 ||
		    (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
			err = -EINVAL;
			break;
		}

		mtd = get_mtd_device(NULL, req.mtd_num);
		if (IS_ERR(mtd)) {
			err = PTR_ERR(mtd);
			break;
		}

		/*
		 * Note, further request verification is done by
		 * 'ubi_attach_mtd_dev()'.
		 */
		mutex_lock(&ubi_devices_mutex);
		err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);
		mutex_unlock(&ubi_devices_mutex);
		if (err < 0)
			put_mtd_device(mtd);
		else
			/* @err contains UBI device number */
			err = put_user(err, (__user int32_t *)argp);

		break;
	}

	/* Detach an MTD device command */
	case UBI_IOCDET:
	{
		int ubi_num;

		dbg_msg("dettach MTD device");
		err = get_user(ubi_num, (__user int32_t *)argp);
		if (err) {
			err = -EFAULT;
			break;
		}

		mutex_lock(&ubi_devices_mutex);
		err = ubi_detach_mtd_dev(ubi_num, 0);
		mutex_unlock(&ubi_devices_mutex);
		break;
	}

	default:
		err = -ENOTTY;
		break;
	}

	return err;
}

/* UBI control character device operations */
struct file_operations ubi_ctrl_cdev_operations = {
	.ioctl = ctrl_cdev_ioctl,
	.owner = THIS_MODULE,
};

+1 −1
Original line number Diff line number Diff line
@@ -483,7 +483,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
			 struct ubi_vid_hdr *vid_hdr);

/* build.c */
int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset);
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset);
int ubi_detach_mtd_dev(int ubi_num, int anyway);
struct ubi_device *ubi_get_device(int ubi_num);
void ubi_put_device(struct ubi_device *ubi);