xref: /linux/drivers/mtd/ubi/block.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29d54c8a3SEzequiel Garcia /*
39d54c8a3SEzequiel Garcia  * Copyright (c) 2014 Ezequiel Garcia
49d54c8a3SEzequiel Garcia  * Copyright (c) 2011 Free Electrons
59d54c8a3SEzequiel Garcia  *
69d54c8a3SEzequiel Garcia  * Driver parameter handling strongly based on drivers/mtd/ubi/build.c
79d54c8a3SEzequiel Garcia  *   Copyright (c) International Business Machines Corp., 2006
89d54c8a3SEzequiel Garcia  *   Copyright (c) Nokia Corporation, 2007
99d54c8a3SEzequiel Garcia  *   Authors: Artem Bityutskiy, Frank Haverkamp
109d54c8a3SEzequiel Garcia  */
119d54c8a3SEzequiel Garcia 
129d54c8a3SEzequiel Garcia /*
139d54c8a3SEzequiel Garcia  * Read-only block devices on top of UBI volumes
149d54c8a3SEzequiel Garcia  *
159d54c8a3SEzequiel Garcia  * A simple implementation to allow a block device to be layered on top of a
169d54c8a3SEzequiel Garcia  * UBI volume. The implementation is provided by creating a static 1-to-1
179d54c8a3SEzequiel Garcia  * mapping between the block device and the UBI volume.
189d54c8a3SEzequiel Garcia  *
199d54c8a3SEzequiel Garcia  * The addressed byte is obtained from the addressed block sector, which is
209d54c8a3SEzequiel Garcia  * mapped linearly into the corresponding LEB:
219d54c8a3SEzequiel Garcia  *
229d54c8a3SEzequiel Garcia  *   LEB number = addressed byte / LEB size
239d54c8a3SEzequiel Garcia  *
244d283ee2SArtem Bityutskiy  * This feature is compiled in the UBI core, and adds a 'block' parameter
254d283ee2SArtem Bityutskiy  * to allow early creation of block devices on top of UBI volumes. Runtime
264d283ee2SArtem Bityutskiy  * block creation/removal for UBI volumes is provided through two UBI ioctls:
278af87188SArtem Bityutskiy  * UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK.
289d54c8a3SEzequiel Garcia  */
299d54c8a3SEzequiel Garcia 
309d54c8a3SEzequiel Garcia #include <linux/module.h>
319d54c8a3SEzequiel Garcia #include <linux/init.h>
329d54c8a3SEzequiel Garcia #include <linux/err.h>
339d54c8a3SEzequiel Garcia #include <linux/kernel.h>
349d54c8a3SEzequiel Garcia #include <linux/list.h>
359d54c8a3SEzequiel Garcia #include <linux/mutex.h>
369d54c8a3SEzequiel Garcia #include <linux/slab.h>
379d54c8a3SEzequiel Garcia #include <linux/mtd/ubi.h>
389d54c8a3SEzequiel Garcia #include <linux/workqueue.h>
399d54c8a3SEzequiel Garcia #include <linux/blkdev.h>
40ff1f48eeSRichard Weinberger #include <linux/blk-mq.h>
419d54c8a3SEzequiel Garcia #include <linux/hdreg.h>
42ff1f48eeSRichard Weinberger #include <linux/scatterlist.h>
432bf50d42SDan Ehrenberg #include <linux/idr.h>
449d54c8a3SEzequiel Garcia #include <asm/div64.h>
459d54c8a3SEzequiel Garcia 
469d54c8a3SEzequiel Garcia #include "ubi-media.h"
479d54c8a3SEzequiel Garcia #include "ubi.h"
489d54c8a3SEzequiel Garcia 
499d54c8a3SEzequiel Garcia /* Maximum number of supported devices */
509d54c8a3SEzequiel Garcia #define UBIBLOCK_MAX_DEVICES 32
519d54c8a3SEzequiel Garcia 
529d54c8a3SEzequiel Garcia /* Maximum length of the 'block=' parameter */
539d54c8a3SEzequiel Garcia #define UBIBLOCK_PARAM_LEN 63
549d54c8a3SEzequiel Garcia 
559d54c8a3SEzequiel Garcia /* Maximum number of comma-separated items in the 'block=' parameter */
569d54c8a3SEzequiel Garcia #define UBIBLOCK_PARAM_COUNT 2
579d54c8a3SEzequiel Garcia 
589d54c8a3SEzequiel Garcia struct ubiblock_param {
599d54c8a3SEzequiel Garcia 	int ubi_num;
609d54c8a3SEzequiel Garcia 	int vol_id;
619d54c8a3SEzequiel Garcia 	char name[UBIBLOCK_PARAM_LEN+1];
629d54c8a3SEzequiel Garcia };
639d54c8a3SEzequiel Garcia 
64ff1f48eeSRichard Weinberger struct ubiblock_pdu {
65ff1f48eeSRichard Weinberger 	struct work_struct work;
66ff1f48eeSRichard Weinberger 	struct ubi_sgl usgl;
67ff1f48eeSRichard Weinberger };
68ff1f48eeSRichard Weinberger 
699d54c8a3SEzequiel Garcia /* Numbers of elements set in the @ubiblock_param array */
709d54c8a3SEzequiel Garcia static int ubiblock_devs __initdata;
719d54c8a3SEzequiel Garcia 
729d54c8a3SEzequiel Garcia /* MTD devices specification parameters */
739d54c8a3SEzequiel Garcia static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
749d54c8a3SEzequiel Garcia 
759d54c8a3SEzequiel Garcia struct ubiblock {
769d54c8a3SEzequiel Garcia 	struct ubi_volume_desc *desc;
779d54c8a3SEzequiel Garcia 	int ubi_num;
789d54c8a3SEzequiel Garcia 	int vol_id;
799d54c8a3SEzequiel Garcia 	int refcnt;
809d54c8a3SEzequiel Garcia 	int leb_size;
819d54c8a3SEzequiel Garcia 
829d54c8a3SEzequiel Garcia 	struct gendisk *gd;
839d54c8a3SEzequiel Garcia 	struct request_queue *rq;
849d54c8a3SEzequiel Garcia 
859d54c8a3SEzequiel Garcia 	struct workqueue_struct *wq;
869d54c8a3SEzequiel Garcia 
879d54c8a3SEzequiel Garcia 	struct mutex dev_mutex;
889d54c8a3SEzequiel Garcia 	struct list_head list;
89ff1f48eeSRichard Weinberger 	struct blk_mq_tag_set tag_set;
909d54c8a3SEzequiel Garcia };
919d54c8a3SEzequiel Garcia 
929d54c8a3SEzequiel Garcia /* Linked list of all ubiblock instances */
939d54c8a3SEzequiel Garcia static LIST_HEAD(ubiblock_devices);
947f29ae9fSBradley Bolen static DEFINE_IDR(ubiblock_minor_idr);
957f29ae9fSBradley Bolen /* Protects ubiblock_devices and ubiblock_minor_idr */
969d54c8a3SEzequiel Garcia static DEFINE_MUTEX(devices_mutex);
979d54c8a3SEzequiel Garcia static int ubiblock_major;
989d54c8a3SEzequiel Garcia 
999d54c8a3SEzequiel Garcia static int __init ubiblock_set_param(const char *val,
1009d54c8a3SEzequiel Garcia 				     const struct kernel_param *kp)
1019d54c8a3SEzequiel Garcia {
1029d54c8a3SEzequiel Garcia 	int i, ret;
1039d54c8a3SEzequiel Garcia 	size_t len;
1049d54c8a3SEzequiel Garcia 	struct ubiblock_param *param;
1059d54c8a3SEzequiel Garcia 	char buf[UBIBLOCK_PARAM_LEN];
1069d54c8a3SEzequiel Garcia 	char *pbuf = &buf[0];
1079d54c8a3SEzequiel Garcia 	char *tokens[UBIBLOCK_PARAM_COUNT];
1089d54c8a3SEzequiel Garcia 
1099d54c8a3SEzequiel Garcia 	if (!val)
1109d54c8a3SEzequiel Garcia 		return -EINVAL;
1119d54c8a3SEzequiel Garcia 
1129d54c8a3SEzequiel Garcia 	len = strnlen(val, UBIBLOCK_PARAM_LEN);
1139d54c8a3SEzequiel Garcia 	if (len == 0) {
11432608703STanya Brokhman 		pr_warn("UBI: block: empty 'block=' parameter - ignored\n");
1159d54c8a3SEzequiel Garcia 		return 0;
1169d54c8a3SEzequiel Garcia 	}
1179d54c8a3SEzequiel Garcia 
1189d54c8a3SEzequiel Garcia 	if (len == UBIBLOCK_PARAM_LEN) {
11932608703STanya Brokhman 		pr_err("UBI: block: parameter \"%s\" is too long, max. is %d\n",
1209d54c8a3SEzequiel Garcia 		       val, UBIBLOCK_PARAM_LEN);
1219d54c8a3SEzequiel Garcia 		return -EINVAL;
1229d54c8a3SEzequiel Garcia 	}
1239d54c8a3SEzequiel Garcia 
1249d54c8a3SEzequiel Garcia 	strcpy(buf, val);
1259d54c8a3SEzequiel Garcia 
1269d54c8a3SEzequiel Garcia 	/* Get rid of the final newline */
1279d54c8a3SEzequiel Garcia 	if (buf[len - 1] == '\n')
1289d54c8a3SEzequiel Garcia 		buf[len - 1] = '\0';
1299d54c8a3SEzequiel Garcia 
1309d54c8a3SEzequiel Garcia 	for (i = 0; i < UBIBLOCK_PARAM_COUNT; i++)
1319d54c8a3SEzequiel Garcia 		tokens[i] = strsep(&pbuf, ",");
1329d54c8a3SEzequiel Garcia 
1339d54c8a3SEzequiel Garcia 	param = &ubiblock_param[ubiblock_devs];
1349d54c8a3SEzequiel Garcia 	if (tokens[1]) {
1359d54c8a3SEzequiel Garcia 		/* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
1369d54c8a3SEzequiel Garcia 		ret = kstrtoint(tokens[0], 10, &param->ubi_num);
1379d54c8a3SEzequiel Garcia 		if (ret < 0)
1389d54c8a3SEzequiel Garcia 			return -EINVAL;
1399d54c8a3SEzequiel Garcia 
1409d54c8a3SEzequiel Garcia 		/* Second param can be a number or a name */
1419d54c8a3SEzequiel Garcia 		ret = kstrtoint(tokens[1], 10, &param->vol_id);
1429d54c8a3SEzequiel Garcia 		if (ret < 0) {
1439d54c8a3SEzequiel Garcia 			param->vol_id = -1;
1449d54c8a3SEzequiel Garcia 			strcpy(param->name, tokens[1]);
1459d54c8a3SEzequiel Garcia 		}
1469d54c8a3SEzequiel Garcia 
1479d54c8a3SEzequiel Garcia 	} else {
1489d54c8a3SEzequiel Garcia 		/* One parameter: must be device path */
1499d54c8a3SEzequiel Garcia 		strcpy(param->name, tokens[0]);
1509d54c8a3SEzequiel Garcia 		param->ubi_num = -1;
1519d54c8a3SEzequiel Garcia 		param->vol_id = -1;
1529d54c8a3SEzequiel Garcia 	}
1539d54c8a3SEzequiel Garcia 
1549d54c8a3SEzequiel Garcia 	ubiblock_devs++;
1559d54c8a3SEzequiel Garcia 
1569d54c8a3SEzequiel Garcia 	return 0;
1579d54c8a3SEzequiel Garcia }
1589d54c8a3SEzequiel Garcia 
1599c27847dSLuis R. Rodriguez static const struct kernel_param_ops ubiblock_param_ops = {
1609d54c8a3SEzequiel Garcia 	.set    = ubiblock_set_param,
1619d54c8a3SEzequiel Garcia };
1629d54c8a3SEzequiel Garcia module_param_cb(block, &ubiblock_param_ops, NULL, 0);
1639d54c8a3SEzequiel Garcia MODULE_PARM_DESC(block, "Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>.\n"
1649d54c8a3SEzequiel Garcia 			"Multiple \"block\" parameters may be specified.\n"
1659d54c8a3SEzequiel Garcia 			"UBI volumes may be specified by their number, name, or path to the device node.\n"
1669d54c8a3SEzequiel Garcia 			"Examples\n"
1679d54c8a3SEzequiel Garcia 			"Using the UBI volume path:\n"
1689d54c8a3SEzequiel Garcia 			"ubi.block=/dev/ubi0_0\n"
1699d54c8a3SEzequiel Garcia 			"Using the UBI device, and the volume name:\n"
1709d54c8a3SEzequiel Garcia 			"ubi.block=0,rootfs\n"
1719d54c8a3SEzequiel Garcia 			"Using both UBI device number and UBI volume number:\n"
1729d54c8a3SEzequiel Garcia 			"ubi.block=0,0\n");
1739d54c8a3SEzequiel Garcia 
1749d54c8a3SEzequiel Garcia static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
1759d54c8a3SEzequiel Garcia {
1769d54c8a3SEzequiel Garcia 	struct ubiblock *dev;
1779d54c8a3SEzequiel Garcia 
1789d54c8a3SEzequiel Garcia 	list_for_each_entry(dev, &ubiblock_devices, list)
1799d54c8a3SEzequiel Garcia 		if (dev->ubi_num == ubi_num && dev->vol_id == vol_id)
1809d54c8a3SEzequiel Garcia 			return dev;
1819d54c8a3SEzequiel Garcia 	return NULL;
1829d54c8a3SEzequiel Garcia }
1839d54c8a3SEzequiel Garcia 
184ff1f48eeSRichard Weinberger static int ubiblock_read(struct ubiblock_pdu *pdu)
1859d54c8a3SEzequiel Garcia {
186ff1f48eeSRichard Weinberger 	int ret, leb, offset, bytes_left, to_read;
187ff1f48eeSRichard Weinberger 	u64 pos;
188ff1f48eeSRichard Weinberger 	struct request *req = blk_mq_rq_from_pdu(pdu);
189ff1f48eeSRichard Weinberger 	struct ubiblock *dev = req->q->queuedata;
1909d54c8a3SEzequiel Garcia 
191ff1f48eeSRichard Weinberger 	to_read = blk_rq_bytes(req);
192ff1f48eeSRichard Weinberger 	pos = blk_rq_pos(req) << 9;
1939d54c8a3SEzequiel Garcia 
1949d54c8a3SEzequiel Garcia 	/* Get LEB:offset address to read from */
1959d54c8a3SEzequiel Garcia 	offset = do_div(pos, dev->leb_size);
1969d54c8a3SEzequiel Garcia 	leb = pos;
197ff1f48eeSRichard Weinberger 	bytes_left = to_read;
1989d54c8a3SEzequiel Garcia 
1999d54c8a3SEzequiel Garcia 	while (bytes_left) {
2009d54c8a3SEzequiel Garcia 		/*
2019d54c8a3SEzequiel Garcia 		 * We can only read one LEB at a time. Therefore if the read
2029d54c8a3SEzequiel Garcia 		 * length is larger than one LEB size, we split the operation.
2039d54c8a3SEzequiel Garcia 		 */
2049d54c8a3SEzequiel Garcia 		if (offset + to_read > dev->leb_size)
2059d54c8a3SEzequiel Garcia 			to_read = dev->leb_size - offset;
2069d54c8a3SEzequiel Garcia 
207ff1f48eeSRichard Weinberger 		ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
208ff1f48eeSRichard Weinberger 		if (ret < 0)
2099d54c8a3SEzequiel Garcia 			return ret;
2109d54c8a3SEzequiel Garcia 
2119d54c8a3SEzequiel Garcia 		bytes_left -= to_read;
2129d54c8a3SEzequiel Garcia 		to_read = bytes_left;
2139d54c8a3SEzequiel Garcia 		leb += 1;
2149d54c8a3SEzequiel Garcia 		offset = 0;
2159d54c8a3SEzequiel Garcia 	}
2169d54c8a3SEzequiel Garcia 	return 0;
2179d54c8a3SEzequiel Garcia }
2189d54c8a3SEzequiel Garcia 
2199d54c8a3SEzequiel Garcia static int ubiblock_open(struct block_device *bdev, fmode_t mode)
2209d54c8a3SEzequiel Garcia {
2219d54c8a3SEzequiel Garcia 	struct ubiblock *dev = bdev->bd_disk->private_data;
2229d54c8a3SEzequiel Garcia 	int ret;
2239d54c8a3SEzequiel Garcia 
2249d54c8a3SEzequiel Garcia 	mutex_lock(&dev->dev_mutex);
2259d54c8a3SEzequiel Garcia 	if (dev->refcnt > 0) {
2269d54c8a3SEzequiel Garcia 		/*
2279d54c8a3SEzequiel Garcia 		 * The volume is already open, just increase the reference
2289d54c8a3SEzequiel Garcia 		 * counter.
2299d54c8a3SEzequiel Garcia 		 */
2309d54c8a3SEzequiel Garcia 		goto out_done;
2319d54c8a3SEzequiel Garcia 	}
2329d54c8a3SEzequiel Garcia 
2339d54c8a3SEzequiel Garcia 	/*
2349d54c8a3SEzequiel Garcia 	 * We want users to be aware they should only mount us as read-only.
2359d54c8a3SEzequiel Garcia 	 * It's just a paranoid check, as write requests will get rejected
2369d54c8a3SEzequiel Garcia 	 * in any case.
2379d54c8a3SEzequiel Garcia 	 */
2389d54c8a3SEzequiel Garcia 	if (mode & FMODE_WRITE) {
23978a8dfbaSRomain Izard 		ret = -EROFS;
2409d54c8a3SEzequiel Garcia 		goto out_unlock;
2419d54c8a3SEzequiel Garcia 	}
2429d54c8a3SEzequiel Garcia 
2439d54c8a3SEzequiel Garcia 	dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY);
2449d54c8a3SEzequiel Garcia 	if (IS_ERR(dev->desc)) {
24532608703STanya Brokhman 		dev_err(disk_to_dev(dev->gd), "failed to open ubi volume %d_%d",
24632608703STanya Brokhman 			dev->ubi_num, dev->vol_id);
2479d54c8a3SEzequiel Garcia 		ret = PTR_ERR(dev->desc);
2489d54c8a3SEzequiel Garcia 		dev->desc = NULL;
2499d54c8a3SEzequiel Garcia 		goto out_unlock;
2509d54c8a3SEzequiel Garcia 	}
2519d54c8a3SEzequiel Garcia 
2529d54c8a3SEzequiel Garcia out_done:
2539d54c8a3SEzequiel Garcia 	dev->refcnt++;
2549d54c8a3SEzequiel Garcia 	mutex_unlock(&dev->dev_mutex);
2559d54c8a3SEzequiel Garcia 	return 0;
2569d54c8a3SEzequiel Garcia 
2579d54c8a3SEzequiel Garcia out_unlock:
2589d54c8a3SEzequiel Garcia 	mutex_unlock(&dev->dev_mutex);
2599d54c8a3SEzequiel Garcia 	return ret;
2609d54c8a3SEzequiel Garcia }
2619d54c8a3SEzequiel Garcia 
2629d54c8a3SEzequiel Garcia static void ubiblock_release(struct gendisk *gd, fmode_t mode)
2639d54c8a3SEzequiel Garcia {
2649d54c8a3SEzequiel Garcia 	struct ubiblock *dev = gd->private_data;
2659d54c8a3SEzequiel Garcia 
2669d54c8a3SEzequiel Garcia 	mutex_lock(&dev->dev_mutex);
2679d54c8a3SEzequiel Garcia 	dev->refcnt--;
2689d54c8a3SEzequiel Garcia 	if (dev->refcnt == 0) {
2699d54c8a3SEzequiel Garcia 		ubi_close_volume(dev->desc);
2709d54c8a3SEzequiel Garcia 		dev->desc = NULL;
2719d54c8a3SEzequiel Garcia 	}
2729d54c8a3SEzequiel Garcia 	mutex_unlock(&dev->dev_mutex);
2739d54c8a3SEzequiel Garcia }
2749d54c8a3SEzequiel Garcia 
2759d54c8a3SEzequiel Garcia static int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
2769d54c8a3SEzequiel Garcia {
2779d54c8a3SEzequiel Garcia 	/* Some tools might require this information */
2789d54c8a3SEzequiel Garcia 	geo->heads = 1;
2799d54c8a3SEzequiel Garcia 	geo->cylinders = 1;
2809d54c8a3SEzequiel Garcia 	geo->sectors = get_capacity(bdev->bd_disk);
2819d54c8a3SEzequiel Garcia 	geo->start = 0;
2829d54c8a3SEzequiel Garcia 	return 0;
2839d54c8a3SEzequiel Garcia }
2849d54c8a3SEzequiel Garcia 
2859d54c8a3SEzequiel Garcia static const struct block_device_operations ubiblock_ops = {
2869d54c8a3SEzequiel Garcia 	.owner = THIS_MODULE,
2879d54c8a3SEzequiel Garcia 	.open = ubiblock_open,
2889d54c8a3SEzequiel Garcia 	.release = ubiblock_release,
2899d54c8a3SEzequiel Garcia 	.getgeo	= ubiblock_getgeo,
2909d54c8a3SEzequiel Garcia };
2919d54c8a3SEzequiel Garcia 
292ff1f48eeSRichard Weinberger static void ubiblock_do_work(struct work_struct *work)
293ff1f48eeSRichard Weinberger {
294ff1f48eeSRichard Weinberger 	int ret;
295ff1f48eeSRichard Weinberger 	struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work);
296ff1f48eeSRichard Weinberger 	struct request *req = blk_mq_rq_from_pdu(pdu);
297ff1f48eeSRichard Weinberger 
298ff1f48eeSRichard Weinberger 	blk_mq_start_request(req);
299832b52a1SRichard Weinberger 
300832b52a1SRichard Weinberger 	/*
301832b52a1SRichard Weinberger 	 * It is safe to ignore the return value of blk_rq_map_sg() because
302832b52a1SRichard Weinberger 	 * the number of sg entries is limited to UBI_MAX_SG_COUNT
303832b52a1SRichard Weinberger 	 * and ubi_read_sg() will check that limit.
304832b52a1SRichard Weinberger 	 */
305ff1f48eeSRichard Weinberger 	blk_rq_map_sg(req->q, req, pdu->usgl.sg);
306ff1f48eeSRichard Weinberger 
307ff1f48eeSRichard Weinberger 	ret = ubiblock_read(pdu);
30898fb1ffdSKevin Cernekee 	rq_flush_dcache_pages(req);
30998fb1ffdSKevin Cernekee 
3102a842acaSChristoph Hellwig 	blk_mq_end_request(req, errno_to_blk_status(ret));
311ff1f48eeSRichard Weinberger }
312ff1f48eeSRichard Weinberger 
313fc17b653SChristoph Hellwig static blk_status_t ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
314ff1f48eeSRichard Weinberger 			     const struct blk_mq_queue_data *bd)
315ff1f48eeSRichard Weinberger {
316ff1f48eeSRichard Weinberger 	struct request *req = bd->rq;
317ff1f48eeSRichard Weinberger 	struct ubiblock *dev = hctx->queue->queuedata;
318ff1f48eeSRichard Weinberger 	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
319ff1f48eeSRichard Weinberger 
320aebf526bSChristoph Hellwig 	switch (req_op(req)) {
321aebf526bSChristoph Hellwig 	case REQ_OP_READ:
322ff1f48eeSRichard Weinberger 		ubi_sgl_init(&pdu->usgl);
323ff1f48eeSRichard Weinberger 		queue_work(dev->wq, &pdu->work);
324fc17b653SChristoph Hellwig 		return BLK_STS_OK;
325aebf526bSChristoph Hellwig 	default:
326fc17b653SChristoph Hellwig 		return BLK_STS_IOERR;
327aebf526bSChristoph Hellwig 	}
328aebf526bSChristoph Hellwig 
329ff1f48eeSRichard Weinberger }
330ff1f48eeSRichard Weinberger 
331d6296d39SChristoph Hellwig static int ubiblock_init_request(struct blk_mq_tag_set *set,
332d6296d39SChristoph Hellwig 		struct request *req, unsigned int hctx_idx,
333ff1f48eeSRichard Weinberger 		unsigned int numa_node)
334ff1f48eeSRichard Weinberger {
335ff1f48eeSRichard Weinberger 	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
336ff1f48eeSRichard Weinberger 
337ff1f48eeSRichard Weinberger 	sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
338ff1f48eeSRichard Weinberger 	INIT_WORK(&pdu->work, ubiblock_do_work);
339ff1f48eeSRichard Weinberger 
340ff1f48eeSRichard Weinberger 	return 0;
341ff1f48eeSRichard Weinberger }
342ff1f48eeSRichard Weinberger 
343f363b089SEric Biggers static const struct blk_mq_ops ubiblock_mq_ops = {
344ff1f48eeSRichard Weinberger 	.queue_rq       = ubiblock_queue_rq,
345ff1f48eeSRichard Weinberger 	.init_request	= ubiblock_init_request,
346ff1f48eeSRichard Weinberger };
347ff1f48eeSRichard Weinberger 
348*e46131b9SRichard Weinberger static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
349*e46131b9SRichard Weinberger {
350*e46131b9SRichard Weinberger 	u64 size = vi->used_bytes >> 9;
351*e46131b9SRichard Weinberger 
352*e46131b9SRichard Weinberger 	if (vi->used_bytes % 512) {
353*e46131b9SRichard Weinberger 		pr_warn("UBI: block: volume size is not a multiple of 512, "
354*e46131b9SRichard Weinberger 			"last %llu bytes are ignored!\n",
355*e46131b9SRichard Weinberger 			vi->used_bytes - (size << 9));
356*e46131b9SRichard Weinberger 	}
357*e46131b9SRichard Weinberger 
358*e46131b9SRichard Weinberger 	if ((sector_t)size != size)
359*e46131b9SRichard Weinberger 		return -EFBIG;
360*e46131b9SRichard Weinberger 
361*e46131b9SRichard Weinberger 	*disk_capacity = size;
362*e46131b9SRichard Weinberger 
363*e46131b9SRichard Weinberger 	return 0;
364*e46131b9SRichard Weinberger }
365*e46131b9SRichard Weinberger 
3664d283ee2SArtem Bityutskiy int ubiblock_create(struct ubi_volume_info *vi)
3679d54c8a3SEzequiel Garcia {
3689d54c8a3SEzequiel Garcia 	struct ubiblock *dev;
3699d54c8a3SEzequiel Garcia 	struct gendisk *gd;
370*e46131b9SRichard Weinberger 	u64 disk_capacity;
3719d54c8a3SEzequiel Garcia 	int ret;
3729d54c8a3SEzequiel Garcia 
373*e46131b9SRichard Weinberger 	ret = calc_disk_capacity(vi, &disk_capacity);
374*e46131b9SRichard Weinberger 	if (ret) {
375*e46131b9SRichard Weinberger 		return ret;
376*e46131b9SRichard Weinberger 	}
377*e46131b9SRichard Weinberger 
3789d54c8a3SEzequiel Garcia 	/* Check that the volume isn't already handled */
3799d54c8a3SEzequiel Garcia 	mutex_lock(&devices_mutex);
3809d54c8a3SEzequiel Garcia 	if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
3817f29ae9fSBradley Bolen 		ret = -EEXIST;
3827f29ae9fSBradley Bolen 		goto out_unlock;
3839d54c8a3SEzequiel Garcia 	}
3849d54c8a3SEzequiel Garcia 
3859d54c8a3SEzequiel Garcia 	dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
3867f29ae9fSBradley Bolen 	if (!dev) {
3877f29ae9fSBradley Bolen 		ret = -ENOMEM;
3887f29ae9fSBradley Bolen 		goto out_unlock;
3897f29ae9fSBradley Bolen 	}
3909d54c8a3SEzequiel Garcia 
3919d54c8a3SEzequiel Garcia 	mutex_init(&dev->dev_mutex);
3929d54c8a3SEzequiel Garcia 
3939d54c8a3SEzequiel Garcia 	dev->ubi_num = vi->ubi_num;
3949d54c8a3SEzequiel Garcia 	dev->vol_id = vi->vol_id;
3959d54c8a3SEzequiel Garcia 	dev->leb_size = vi->usable_leb_size;
3969d54c8a3SEzequiel Garcia 
3979d54c8a3SEzequiel Garcia 	/* Initialize the gendisk of this ubiblock device */
3989d54c8a3SEzequiel Garcia 	gd = alloc_disk(1);
3999d54c8a3SEzequiel Garcia 	if (!gd) {
400b62fc462SBen Dooks 		pr_err("UBI: block: alloc_disk failed\n");
4019d54c8a3SEzequiel Garcia 		ret = -ENODEV;
4029d54c8a3SEzequiel Garcia 		goto out_free_dev;
4039d54c8a3SEzequiel Garcia 	}
4049d54c8a3SEzequiel Garcia 
4059d54c8a3SEzequiel Garcia 	gd->fops = &ubiblock_ops;
4069d54c8a3SEzequiel Garcia 	gd->major = ubiblock_major;
4072bf50d42SDan Ehrenberg 	gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
4082bf50d42SDan Ehrenberg 	if (gd->first_minor < 0) {
4092bf50d42SDan Ehrenberg 		dev_err(disk_to_dev(gd),
4102bf50d42SDan Ehrenberg 			"block: dynamic minor allocation failed");
4112bf50d42SDan Ehrenberg 		ret = -ENODEV;
4122bf50d42SDan Ehrenberg 		goto out_put_disk;
4132bf50d42SDan Ehrenberg 	}
4149d54c8a3SEzequiel Garcia 	gd->private_data = dev;
4159d54c8a3SEzequiel Garcia 	sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
4169d54c8a3SEzequiel Garcia 	set_capacity(gd, disk_capacity);
4179d54c8a3SEzequiel Garcia 	dev->gd = gd;
4189d54c8a3SEzequiel Garcia 
419ff1f48eeSRichard Weinberger 	dev->tag_set.ops = &ubiblock_mq_ops;
420ff1f48eeSRichard Weinberger 	dev->tag_set.queue_depth = 64;
421ff1f48eeSRichard Weinberger 	dev->tag_set.numa_node = NUMA_NO_NODE;
422ff1f48eeSRichard Weinberger 	dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
423ff1f48eeSRichard Weinberger 	dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
424ff1f48eeSRichard Weinberger 	dev->tag_set.driver_data = dev;
425ff1f48eeSRichard Weinberger 	dev->tag_set.nr_hw_queues = 1;
426ff1f48eeSRichard Weinberger 
427ff1f48eeSRichard Weinberger 	ret = blk_mq_alloc_tag_set(&dev->tag_set);
428ff1f48eeSRichard Weinberger 	if (ret) {
429ff1f48eeSRichard Weinberger 		dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
4302bf50d42SDan Ehrenberg 		goto out_remove_minor;
4319d54c8a3SEzequiel Garcia 	}
4329d54c8a3SEzequiel Garcia 
433ff1f48eeSRichard Weinberger 	dev->rq = blk_mq_init_queue(&dev->tag_set);
4348168b9bbSDan Carpenter 	if (IS_ERR(dev->rq)) {
435ff1f48eeSRichard Weinberger 		dev_err(disk_to_dev(gd), "blk_mq_init_queue failed");
4368168b9bbSDan Carpenter 		ret = PTR_ERR(dev->rq);
437ff1f48eeSRichard Weinberger 		goto out_free_tags;
438ff1f48eeSRichard Weinberger 	}
439ff1f48eeSRichard Weinberger 	blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
440ff1f48eeSRichard Weinberger 
4419d54c8a3SEzequiel Garcia 	dev->rq->queuedata = dev;
4429d54c8a3SEzequiel Garcia 	dev->gd->queue = dev->rq;
4439d54c8a3SEzequiel Garcia 
4449d54c8a3SEzequiel Garcia 	/*
4459d54c8a3SEzequiel Garcia 	 * Create one workqueue per volume (per registered block device).
4469d54c8a3SEzequiel Garcia 	 * Rembember workqueues are cheap, they're not threads.
4479d54c8a3SEzequiel Garcia 	 */
448bebfef15SKees Cook 	dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
449151d6b21SHelmut Schaa 	if (!dev->wq) {
450151d6b21SHelmut Schaa 		ret = -ENOMEM;
4519d54c8a3SEzequiel Garcia 		goto out_free_queue;
452151d6b21SHelmut Schaa 	}
4539d54c8a3SEzequiel Garcia 
4549d54c8a3SEzequiel Garcia 	list_add_tail(&dev->list, &ubiblock_devices);
4559d54c8a3SEzequiel Garcia 
4569d54c8a3SEzequiel Garcia 	/* Must be the last step: anyone can call file ops from now on */
4579d54c8a3SEzequiel Garcia 	add_disk(dev->gd);
45832608703STanya Brokhman 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
45932608703STanya Brokhman 		 dev->ubi_num, dev->vol_id, vi->name);
4607f29ae9fSBradley Bolen 	mutex_unlock(&devices_mutex);
4619d54c8a3SEzequiel Garcia 	return 0;
4629d54c8a3SEzequiel Garcia 
4639d54c8a3SEzequiel Garcia out_free_queue:
4649d54c8a3SEzequiel Garcia 	blk_cleanup_queue(dev->rq);
465ff1f48eeSRichard Weinberger out_free_tags:
466ff1f48eeSRichard Weinberger 	blk_mq_free_tag_set(&dev->tag_set);
4672bf50d42SDan Ehrenberg out_remove_minor:
4682bf50d42SDan Ehrenberg 	idr_remove(&ubiblock_minor_idr, gd->first_minor);
4699d54c8a3SEzequiel Garcia out_put_disk:
4709d54c8a3SEzequiel Garcia 	put_disk(dev->gd);
4719d54c8a3SEzequiel Garcia out_free_dev:
4729d54c8a3SEzequiel Garcia 	kfree(dev);
4737f29ae9fSBradley Bolen out_unlock:
4747f29ae9fSBradley Bolen 	mutex_unlock(&devices_mutex);
4759d54c8a3SEzequiel Garcia 
4769d54c8a3SEzequiel Garcia 	return ret;
4779d54c8a3SEzequiel Garcia }
4789d54c8a3SEzequiel Garcia 
4799d54c8a3SEzequiel Garcia static void ubiblock_cleanup(struct ubiblock *dev)
4809d54c8a3SEzequiel Garcia {
481ff1f48eeSRichard Weinberger 	/* Stop new requests to arrive */
4829d54c8a3SEzequiel Garcia 	del_gendisk(dev->gd);
483ff1f48eeSRichard Weinberger 	/* Flush pending work */
484ff1f48eeSRichard Weinberger 	destroy_workqueue(dev->wq);
485ff1f48eeSRichard Weinberger 	/* Finally destroy the blk queue */
4869d54c8a3SEzequiel Garcia 	blk_cleanup_queue(dev->rq);
487ff1f48eeSRichard Weinberger 	blk_mq_free_tag_set(&dev->tag_set);
48832608703STanya Brokhman 	dev_info(disk_to_dev(dev->gd), "released");
4892bf50d42SDan Ehrenberg 	idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
4909d54c8a3SEzequiel Garcia 	put_disk(dev->gd);
4919d54c8a3SEzequiel Garcia }
4929d54c8a3SEzequiel Garcia 
4934d283ee2SArtem Bityutskiy int ubiblock_remove(struct ubi_volume_info *vi)
4949d54c8a3SEzequiel Garcia {
4959d54c8a3SEzequiel Garcia 	struct ubiblock *dev;
4967f29ae9fSBradley Bolen 	int ret;
4979d54c8a3SEzequiel Garcia 
4989d54c8a3SEzequiel Garcia 	mutex_lock(&devices_mutex);
4999d54c8a3SEzequiel Garcia 	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
5009d54c8a3SEzequiel Garcia 	if (!dev) {
5017f29ae9fSBradley Bolen 		ret = -ENODEV;
5027f29ae9fSBradley Bolen 		goto out_unlock;
5039d54c8a3SEzequiel Garcia 	}
5049d54c8a3SEzequiel Garcia 
5059d54c8a3SEzequiel Garcia 	/* Found a device, let's lock it so we can check if it's busy */
5069d54c8a3SEzequiel Garcia 	mutex_lock(&dev->dev_mutex);
5079d54c8a3SEzequiel Garcia 	if (dev->refcnt > 0) {
5087f29ae9fSBradley Bolen 		ret = -EBUSY;
5097f29ae9fSBradley Bolen 		goto out_unlock_dev;
5109d54c8a3SEzequiel Garcia 	}
5119d54c8a3SEzequiel Garcia 
5129d54c8a3SEzequiel Garcia 	/* Remove from device list */
5139d54c8a3SEzequiel Garcia 	list_del(&dev->list);
5149d54c8a3SEzequiel Garcia 	ubiblock_cleanup(dev);
5159d54c8a3SEzequiel Garcia 	mutex_unlock(&dev->dev_mutex);
5167f29ae9fSBradley Bolen 	mutex_unlock(&devices_mutex);
5177f29ae9fSBradley Bolen 
5189d54c8a3SEzequiel Garcia 	kfree(dev);
5199d54c8a3SEzequiel Garcia 	return 0;
5207f29ae9fSBradley Bolen 
5217f29ae9fSBradley Bolen out_unlock_dev:
5227f29ae9fSBradley Bolen 	mutex_unlock(&dev->dev_mutex);
5237f29ae9fSBradley Bolen out_unlock:
5247f29ae9fSBradley Bolen 	mutex_unlock(&devices_mutex);
5257f29ae9fSBradley Bolen 	return ret;
5269d54c8a3SEzequiel Garcia }
5279d54c8a3SEzequiel Garcia 
528495f2bf6SEzequiel Garcia static int ubiblock_resize(struct ubi_volume_info *vi)
5299d54c8a3SEzequiel Garcia {
5309d54c8a3SEzequiel Garcia 	struct ubiblock *dev;
531*e46131b9SRichard Weinberger 	u64 disk_capacity;
532*e46131b9SRichard Weinberger 	int ret;
5339d54c8a3SEzequiel Garcia 
5349d54c8a3SEzequiel Garcia 	/*
5359d54c8a3SEzequiel Garcia 	 * Need to lock the device list until we stop using the device,
5364d283ee2SArtem Bityutskiy 	 * otherwise the device struct might get released in
5374d283ee2SArtem Bityutskiy 	 * 'ubiblock_remove()'.
5389d54c8a3SEzequiel Garcia 	 */
5399d54c8a3SEzequiel Garcia 	mutex_lock(&devices_mutex);
5409d54c8a3SEzequiel Garcia 	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
5419d54c8a3SEzequiel Garcia 	if (!dev) {
5429d54c8a3SEzequiel Garcia 		mutex_unlock(&devices_mutex);
543495f2bf6SEzequiel Garcia 		return -ENODEV;
5449d54c8a3SEzequiel Garcia 	}
545*e46131b9SRichard Weinberger 
546*e46131b9SRichard Weinberger 	ret = calc_disk_capacity(vi, &disk_capacity);
547*e46131b9SRichard Weinberger 	if (ret) {
5483df77072SColin Ian King 		mutex_unlock(&devices_mutex);
549*e46131b9SRichard Weinberger 		if (ret == -EFBIG) {
550*e46131b9SRichard Weinberger 			dev_warn(disk_to_dev(dev->gd),
551*e46131b9SRichard Weinberger 				 "the volume is too big (%d LEBs), cannot resize",
55232608703STanya Brokhman 				 vi->size);
553*e46131b9SRichard Weinberger 		}
554*e46131b9SRichard Weinberger 		return ret;
5553df77072SColin Ian King 	}
5569d54c8a3SEzequiel Garcia 
5579d54c8a3SEzequiel Garcia 	mutex_lock(&dev->dev_mutex);
55806d9c290SEzequiel Garcia 
55906d9c290SEzequiel Garcia 	if (get_capacity(dev->gd) != disk_capacity) {
5609d54c8a3SEzequiel Garcia 		set_capacity(dev->gd, disk_capacity);
56132608703STanya Brokhman 		dev_info(disk_to_dev(dev->gd), "resized to %lld bytes",
56206d9c290SEzequiel Garcia 			 vi->used_bytes);
56306d9c290SEzequiel Garcia 	}
5649d54c8a3SEzequiel Garcia 	mutex_unlock(&dev->dev_mutex);
5659d54c8a3SEzequiel Garcia 	mutex_unlock(&devices_mutex);
566495f2bf6SEzequiel Garcia 	return 0;
5679d54c8a3SEzequiel Garcia }
5689d54c8a3SEzequiel Garcia 
5699d54c8a3SEzequiel Garcia static int ubiblock_notify(struct notifier_block *nb,
5709d54c8a3SEzequiel Garcia 			 unsigned long notification_type, void *ns_ptr)
5719d54c8a3SEzequiel Garcia {
5729d54c8a3SEzequiel Garcia 	struct ubi_notification *nt = ns_ptr;
5739d54c8a3SEzequiel Garcia 
5749d54c8a3SEzequiel Garcia 	switch (notification_type) {
5759d54c8a3SEzequiel Garcia 	case UBI_VOLUME_ADDED:
5769d54c8a3SEzequiel Garcia 		/*
5774d283ee2SArtem Bityutskiy 		 * We want to enforce explicit block device creation for
5789d54c8a3SEzequiel Garcia 		 * volumes, so when a volume is added we do nothing.
5799d54c8a3SEzequiel Garcia 		 */
5809d54c8a3SEzequiel Garcia 		break;
5819d54c8a3SEzequiel Garcia 	case UBI_VOLUME_REMOVED:
5824d283ee2SArtem Bityutskiy 		ubiblock_remove(&nt->vi);
5839d54c8a3SEzequiel Garcia 		break;
5849d54c8a3SEzequiel Garcia 	case UBI_VOLUME_RESIZED:
5859d54c8a3SEzequiel Garcia 		ubiblock_resize(&nt->vi);
5869d54c8a3SEzequiel Garcia 		break;
58706d9c290SEzequiel Garcia 	case UBI_VOLUME_UPDATED:
58806d9c290SEzequiel Garcia 		/*
58906d9c290SEzequiel Garcia 		 * If the volume is static, a content update might mean the
59006d9c290SEzequiel Garcia 		 * size (i.e. used_bytes) was also changed.
59106d9c290SEzequiel Garcia 		 */
59206d9c290SEzequiel Garcia 		if (nt->vi.vol_type == UBI_STATIC_VOLUME)
59306d9c290SEzequiel Garcia 			ubiblock_resize(&nt->vi);
59406d9c290SEzequiel Garcia 		break;
5959d54c8a3SEzequiel Garcia 	default:
5969d54c8a3SEzequiel Garcia 		break;
5979d54c8a3SEzequiel Garcia 	}
5989d54c8a3SEzequiel Garcia 	return NOTIFY_OK;
5999d54c8a3SEzequiel Garcia }
6009d54c8a3SEzequiel Garcia 
6019d54c8a3SEzequiel Garcia static struct notifier_block ubiblock_notifier = {
6029d54c8a3SEzequiel Garcia 	.notifier_call = ubiblock_notify,
6039d54c8a3SEzequiel Garcia };
6049d54c8a3SEzequiel Garcia 
6059d54c8a3SEzequiel Garcia static struct ubi_volume_desc * __init
6069d54c8a3SEzequiel Garcia open_volume_desc(const char *name, int ubi_num, int vol_id)
6079d54c8a3SEzequiel Garcia {
6089d54c8a3SEzequiel Garcia 	if (ubi_num == -1)
6099d54c8a3SEzequiel Garcia 		/* No ubi num, name must be a vol device path */
6109d54c8a3SEzequiel Garcia 		return ubi_open_volume_path(name, UBI_READONLY);
6119d54c8a3SEzequiel Garcia 	else if (vol_id == -1)
6129d54c8a3SEzequiel Garcia 		/* No vol_id, must be vol_name */
6139d54c8a3SEzequiel Garcia 		return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
6149d54c8a3SEzequiel Garcia 	else
6159d54c8a3SEzequiel Garcia 		return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
6169d54c8a3SEzequiel Garcia }
6179d54c8a3SEzequiel Garcia 
6181440061bSDan Ehrenberg static void __init ubiblock_create_from_param(void)
6199d54c8a3SEzequiel Garcia {
6201440061bSDan Ehrenberg 	int i, ret = 0;
6219d54c8a3SEzequiel Garcia 	struct ubiblock_param *p;
6229d54c8a3SEzequiel Garcia 	struct ubi_volume_desc *desc;
6239d54c8a3SEzequiel Garcia 	struct ubi_volume_info vi;
6249d54c8a3SEzequiel Garcia 
6251440061bSDan Ehrenberg 	/*
6261440061bSDan Ehrenberg 	 * If there is an error creating one of the ubiblocks, continue on to
6271440061bSDan Ehrenberg 	 * create the following ubiblocks. This helps in a circumstance where
6281440061bSDan Ehrenberg 	 * the kernel command-line specifies multiple block devices and some
6291440061bSDan Ehrenberg 	 * may be broken, but we still want the working ones to come up.
6301440061bSDan Ehrenberg 	 */
6319d54c8a3SEzequiel Garcia 	for (i = 0; i < ubiblock_devs; i++) {
6329d54c8a3SEzequiel Garcia 		p = &ubiblock_param[i];
6339d54c8a3SEzequiel Garcia 
6349d54c8a3SEzequiel Garcia 		desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
6359d54c8a3SEzequiel Garcia 		if (IS_ERR(desc)) {
6361440061bSDan Ehrenberg 			pr_err(
637b62fc462SBen Dooks 			       "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
6381440061bSDan Ehrenberg 			       p->ubi_num, p->vol_id, PTR_ERR(desc));
6391440061bSDan Ehrenberg 			continue;
6409d54c8a3SEzequiel Garcia 		}
6419d54c8a3SEzequiel Garcia 
6429d54c8a3SEzequiel Garcia 		ubi_get_volume_info(desc, &vi);
6439d54c8a3SEzequiel Garcia 		ubi_close_volume(desc);
6449d54c8a3SEzequiel Garcia 
6454d283ee2SArtem Bityutskiy 		ret = ubiblock_create(&vi);
6469d54c8a3SEzequiel Garcia 		if (ret) {
6471440061bSDan Ehrenberg 			pr_err(
648b62fc462SBen Dooks 			       "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
6491440061bSDan Ehrenberg 			       vi.name, p->ubi_num, p->vol_id, ret);
6501440061bSDan Ehrenberg 			continue;
6519d54c8a3SEzequiel Garcia 		}
6529d54c8a3SEzequiel Garcia 	}
6539d54c8a3SEzequiel Garcia }
6549d54c8a3SEzequiel Garcia 
6554d283ee2SArtem Bityutskiy static void ubiblock_remove_all(void)
6569d54c8a3SEzequiel Garcia {
6579d54c8a3SEzequiel Garcia 	struct ubiblock *next;
6589d54c8a3SEzequiel Garcia 	struct ubiblock *dev;
6599d54c8a3SEzequiel Garcia 
6607f29ae9fSBradley Bolen 	mutex_lock(&devices_mutex);
6619d54c8a3SEzequiel Garcia 	list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
6629d54c8a3SEzequiel Garcia 		/* The module is being forcefully removed */
6639d54c8a3SEzequiel Garcia 		WARN_ON(dev->desc);
6649d54c8a3SEzequiel Garcia 		/* Remove from device list */
6659d54c8a3SEzequiel Garcia 		list_del(&dev->list);
6669d54c8a3SEzequiel Garcia 		ubiblock_cleanup(dev);
6679d54c8a3SEzequiel Garcia 		kfree(dev);
6689d54c8a3SEzequiel Garcia 	}
6697f29ae9fSBradley Bolen 	mutex_unlock(&devices_mutex);
6709d54c8a3SEzequiel Garcia }
6719d54c8a3SEzequiel Garcia 
6729d54c8a3SEzequiel Garcia int __init ubiblock_init(void)
6739d54c8a3SEzequiel Garcia {
6749d54c8a3SEzequiel Garcia 	int ret;
6759d54c8a3SEzequiel Garcia 
6769d54c8a3SEzequiel Garcia 	ubiblock_major = register_blkdev(0, "ubiblock");
6779d54c8a3SEzequiel Garcia 	if (ubiblock_major < 0)
6789d54c8a3SEzequiel Garcia 		return ubiblock_major;
6799d54c8a3SEzequiel Garcia 
6801440061bSDan Ehrenberg 	/*
6811440061bSDan Ehrenberg 	 * Attach block devices from 'block=' module param.
6821440061bSDan Ehrenberg 	 * Even if one block device in the param list fails to come up,
6831440061bSDan Ehrenberg 	 * still allow the module to load and leave any others up.
6841440061bSDan Ehrenberg 	 */
6851440061bSDan Ehrenberg 	ubiblock_create_from_param();
6869d54c8a3SEzequiel Garcia 
6879d54c8a3SEzequiel Garcia 	/*
6884d283ee2SArtem Bityutskiy 	 * Block devices are only created upon user requests, so we ignore
6894d283ee2SArtem Bityutskiy 	 * existing volumes.
6909d54c8a3SEzequiel Garcia 	 */
6919d54c8a3SEzequiel Garcia 	ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
6929d54c8a3SEzequiel Garcia 	if (ret)
6939d54c8a3SEzequiel Garcia 		goto err_unreg;
6949d54c8a3SEzequiel Garcia 	return 0;
6959d54c8a3SEzequiel Garcia 
6969d54c8a3SEzequiel Garcia err_unreg:
6979d54c8a3SEzequiel Garcia 	unregister_blkdev(ubiblock_major, "ubiblock");
6984d283ee2SArtem Bityutskiy 	ubiblock_remove_all();
6999d54c8a3SEzequiel Garcia 	return ret;
7009d54c8a3SEzequiel Garcia }
7019d54c8a3SEzequiel Garcia 
7029d54c8a3SEzequiel Garcia void __exit ubiblock_exit(void)
7039d54c8a3SEzequiel Garcia {
7049d54c8a3SEzequiel Garcia 	ubi_unregister_volume_notifier(&ubiblock_notifier);
7054d283ee2SArtem Bityutskiy 	ubiblock_remove_all();
7069d54c8a3SEzequiel Garcia 	unregister_blkdev(ubiblock_major, "ubiblock");
7079d54c8a3SEzequiel Garcia }
708