2019-05-29 07:18:00 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-25 13:25:22 -03:00
/*
* Copyright ( c ) 2014 Ezequiel Garcia
* Copyright ( c ) 2011 Free Electrons
*
* Driver parameter handling strongly based on drivers / mtd / ubi / build . c
* Copyright ( c ) International Business Machines Corp . , 2006
* Copyright ( c ) Nokia Corporation , 2007
* Authors : Artem Bityutskiy , Frank Haverkamp
*/
/*
* Read - only block devices on top of UBI volumes
*
* A simple implementation to allow a block device to be layered on top of a
* UBI volume . The implementation is provided by creating a static 1 - to - 1
* mapping between the block device and the UBI volume .
*
* The addressed byte is obtained from the addressed block sector , which is
* mapped linearly into the corresponding LEB :
*
* LEB number = addressed byte / LEB size
*
2014-03-04 12:00:26 +02:00
* This feature is compiled in the UBI core , and adds a ' block ' parameter
* to allow early creation of block devices on top of UBI volumes . Runtime
* block creation / removal for UBI volumes is provided through two UBI ioctls :
2014-03-05 13:01:56 +02:00
* UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK .
2014-02-25 13:25:22 -03:00
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/mtd/ubi.h>
# include <linux/blkdev.h>
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
# include <linux/blk-mq.h>
2014-02-25 13:25:22 -03:00
# include <linux/hdreg.h>
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
# include <linux/scatterlist.h>
2015-03-17 10:37:26 -07:00
# include <linux/idr.h>
2014-02-25 13:25:22 -03:00
# include <asm/div64.h>
# include "ubi-media.h"
# include "ubi.h"
/* Maximum number of supported devices */
# define UBIBLOCK_MAX_DEVICES 32
/* Maximum length of the 'block=' parameter */
# define UBIBLOCK_PARAM_LEN 63
/* Maximum number of comma-separated items in the 'block=' parameter */
# define UBIBLOCK_PARAM_COUNT 2
struct ubiblock_param {
int ubi_num ;
int vol_id ;
char name [ UBIBLOCK_PARAM_LEN + 1 ] ;
} ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
struct ubiblock_pdu {
struct ubi_sgl usgl ;
} ;
2014-02-25 13:25:22 -03:00
/* Numbers of elements set in the @ubiblock_param array */
static int ubiblock_devs __initdata ;
/* MTD devices specification parameters */
static struct ubiblock_param ubiblock_param [ UBIBLOCK_MAX_DEVICES ] __initdata ;
struct ubiblock {
struct ubi_volume_desc * desc ;
int ubi_num ;
int vol_id ;
int refcnt ;
int leb_size ;
struct gendisk * gd ;
struct request_queue * rq ;
struct mutex dev_mutex ;
struct list_head list ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
struct blk_mq_tag_set tag_set ;
2014-02-25 13:25:22 -03:00
} ;
/* Linked list of all ubiblock instances */
static LIST_HEAD ( ubiblock_devices ) ;
2018-01-18 08:55:20 -05:00
static DEFINE_IDR ( ubiblock_minor_idr ) ;
/* Protects ubiblock_devices and ubiblock_minor_idr */
2014-02-25 13:25:22 -03:00
static DEFINE_MUTEX ( devices_mutex ) ;
static int ubiblock_major ;
static int __init ubiblock_set_param ( const char * val ,
const struct kernel_param * kp )
{
int i , ret ;
size_t len ;
struct ubiblock_param * param ;
char buf [ UBIBLOCK_PARAM_LEN ] ;
char * pbuf = & buf [ 0 ] ;
char * tokens [ UBIBLOCK_PARAM_COUNT ] ;
if ( ! val )
return - EINVAL ;
len = strnlen ( val , UBIBLOCK_PARAM_LEN ) ;
if ( len = = 0 ) {
2014-10-20 19:57:00 +03:00
pr_warn ( " UBI: block: empty 'block=' parameter - ignored \n " ) ;
2014-02-25 13:25:22 -03:00
return 0 ;
}
if ( len = = UBIBLOCK_PARAM_LEN ) {
2014-10-20 19:57:00 +03:00
pr_err ( " UBI: block: parameter \" %s \" is too long, max. is %d \n " ,
val , UBIBLOCK_PARAM_LEN ) ;
2014-02-25 13:25:22 -03:00
return - EINVAL ;
}
strcpy ( buf , val ) ;
/* Get rid of the final newline */
if ( buf [ len - 1 ] = = ' \n ' )
buf [ len - 1 ] = ' \0 ' ;
for ( i = 0 ; i < UBIBLOCK_PARAM_COUNT ; i + + )
tokens [ i ] = strsep ( & pbuf , " , " ) ;
param = & ubiblock_param [ ubiblock_devs ] ;
if ( tokens [ 1 ] ) {
/* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
ret = kstrtoint ( tokens [ 0 ] , 10 , & param - > ubi_num ) ;
if ( ret < 0 )
return - EINVAL ;
/* Second param can be a number or a name */
ret = kstrtoint ( tokens [ 1 ] , 10 , & param - > vol_id ) ;
if ( ret < 0 ) {
param - > vol_id = - 1 ;
strcpy ( param - > name , tokens [ 1 ] ) ;
}
} else {
/* One parameter: must be device path */
strcpy ( param - > name , tokens [ 0 ] ) ;
param - > ubi_num = - 1 ;
param - > vol_id = - 1 ;
}
ubiblock_devs + + ;
return 0 ;
}
2015-05-27 11:09:38 +09:30
static const struct kernel_param_ops ubiblock_param_ops = {
2014-02-25 13:25:22 -03:00
. set = ubiblock_set_param ,
} ;
module_param_cb ( block , & ubiblock_param_ops , NULL , 0 ) ;
MODULE_PARM_DESC ( block , " Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>. \n "
" Multiple \" block \" parameters may be specified. \n "
" UBI volumes may be specified by their number, name, or path to the device node. \n "
" Examples \n "
" Using the UBI volume path: \n "
" ubi.block=/dev/ubi0_0 \n "
" Using the UBI device, and the volume name: \n "
" ubi.block=0,rootfs \n "
" Using both UBI device number and UBI volume number: \n "
" ubi.block=0,0 \n " ) ;
static struct ubiblock * find_dev_nolock ( int ubi_num , int vol_id )
{
struct ubiblock * dev ;
list_for_each_entry ( dev , & ubiblock_devices , list )
if ( dev - > ubi_num = = ubi_num & & dev - > vol_id = = vol_id )
return dev ;
return NULL ;
}
2023-01-12 17:15:40 +01:00
static blk_status_t ubiblock_read ( struct request * req )
2014-02-25 13:25:22 -03:00
{
2023-01-12 17:15:40 +01:00
struct ubiblock_pdu * pdu = blk_mq_rq_to_pdu ( req ) ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
struct ubiblock * dev = req - > q - > queuedata ;
2023-01-12 17:15:40 +01:00
u64 pos = blk_rq_pos ( req ) < < 9 ;
int to_read = blk_rq_bytes ( req ) ;
int bytes_left = to_read ;
/* Get LEB:offset address to read from */
int offset = do_div ( pos , dev - > leb_size ) ;
int leb = pos ;
struct req_iterator iter ;
struct bio_vec bvec ;
int ret ;
2014-02-25 13:25:22 -03:00
2023-01-12 17:15:40 +01:00
blk_mq_start_request ( req ) ;
2014-02-25 13:25:22 -03:00
2023-01-12 17:15:40 +01:00
/*
* It is safe to ignore the return value of blk_rq_map_sg ( ) because
* the number of sg entries is limited to UBI_MAX_SG_COUNT
* and ubi_read_sg ( ) will check that limit .
*/
ubi_sgl_init ( & pdu - > usgl ) ;
blk_rq_map_sg ( req - > q , req , pdu - > usgl . sg ) ;
2014-02-25 13:25:22 -03:00
while ( bytes_left ) {
/*
* We can only read one LEB at a time . Therefore if the read
* length is larger than one LEB size , we split the operation .
*/
if ( offset + to_read > dev - > leb_size )
to_read = dev - > leb_size - offset ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
ret = ubi_read_sg ( dev - > desc , leb , & pdu - > usgl , offset , to_read ) ;
if ( ret < 0 )
2023-01-12 17:15:40 +01:00
break ;
2014-02-25 13:25:22 -03:00
bytes_left - = to_read ;
to_read = bytes_left ;
leb + = 1 ;
offset = 0 ;
}
2023-01-12 17:15:40 +01:00
rq_for_each_segment ( bvec , req , iter )
flush_dcache_page ( bvec . bv_page ) ;
return errno_to_blk_status ( ret ) ;
2014-02-25 13:25:22 -03:00
}
static int ubiblock_open ( struct block_device * bdev , fmode_t mode )
{
struct ubiblock * dev = bdev - > bd_disk - > private_data ;
int ret ;
mutex_lock ( & dev - > dev_mutex ) ;
if ( dev - > refcnt > 0 ) {
/*
* The volume is already open , just increase the reference
* counter .
*/
goto out_done ;
}
/*
* We want users to be aware they should only mount us as read - only .
* It ' s just a paranoid check , as write requests will get rejected
* in any case .
*/
if ( mode & FMODE_WRITE ) {
2018-01-29 11:18:20 +01:00
ret = - EROFS ;
2014-02-25 13:25:22 -03:00
goto out_unlock ;
}
dev - > desc = ubi_open_volume ( dev - > ubi_num , dev - > vol_id , UBI_READONLY ) ;
if ( IS_ERR ( dev - > desc ) ) {
2014-10-20 19:57:00 +03:00
dev_err ( disk_to_dev ( dev - > gd ) , " failed to open ubi volume %d_%d " ,
dev - > ubi_num , dev - > vol_id ) ;
2014-02-25 13:25:22 -03:00
ret = PTR_ERR ( dev - > desc ) ;
dev - > desc = NULL ;
goto out_unlock ;
}
out_done :
dev - > refcnt + + ;
mutex_unlock ( & dev - > dev_mutex ) ;
return 0 ;
out_unlock :
mutex_unlock ( & dev - > dev_mutex ) ;
return ret ;
}
static void ubiblock_release ( struct gendisk * gd , fmode_t mode )
{
struct ubiblock * dev = gd - > private_data ;
mutex_lock ( & dev - > dev_mutex ) ;
dev - > refcnt - - ;
if ( dev - > refcnt = = 0 ) {
ubi_close_volume ( dev - > desc ) ;
dev - > desc = NULL ;
}
mutex_unlock ( & dev - > dev_mutex ) ;
}
static int ubiblock_getgeo ( struct block_device * bdev , struct hd_geometry * geo )
{
/* Some tools might require this information */
geo - > heads = 1 ;
geo - > cylinders = 1 ;
geo - > sectors = get_capacity ( bdev - > bd_disk ) ;
geo - > start = 0 ;
return 0 ;
}
static const struct block_device_operations ubiblock_ops = {
. owner = THIS_MODULE ,
. open = ubiblock_open ,
. release = ubiblock_release ,
. getgeo = ubiblock_getgeo ,
} ;
2017-06-03 09:38:05 +02:00
static blk_status_t ubiblock_queue_rq ( struct blk_mq_hw_ctx * hctx ,
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
const struct blk_mq_queue_data * bd )
{
2023-01-12 17:15:40 +01:00
switch ( req_op ( bd - > rq ) ) {
2017-01-31 16:57:31 +01:00
case REQ_OP_READ :
2023-01-12 17:15:40 +01:00
return ubiblock_read ( bd - > rq ) ;
2017-01-31 16:57:31 +01:00
default :
2017-06-03 09:38:05 +02:00
return BLK_STS_IOERR ;
2017-01-31 16:57:31 +01:00
}
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
}
2017-05-01 10:19:08 -06:00
static int ubiblock_init_request ( struct blk_mq_tag_set * set ,
struct request * req , unsigned int hctx_idx ,
unsigned int numa_node )
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
{
struct ubiblock_pdu * pdu = blk_mq_rq_to_pdu ( req ) ;
sg_init_table ( pdu - > usgl . sg , UBI_MAX_SG_COUNT ) ;
return 0 ;
}
2017-03-30 13:39:16 -07:00
static const struct blk_mq_ops ubiblock_mq_ops = {
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
. queue_rq = ubiblock_queue_rq ,
. init_request = ubiblock_init_request ,
} ;
2019-09-01 22:32:05 +02:00
static int calc_disk_capacity ( struct ubi_volume_info * vi , u64 * disk_capacity )
{
u64 size = vi - > used_bytes > > 9 ;
if ( vi - > used_bytes % 512 ) {
2022-10-13 14:02:49 +02:00
if ( vi - > vol_type = = UBI_DYNAMIC_VOLUME )
pr_warn ( " UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored! \n " ,
vi - > used_bytes - ( size < < 9 ) ) ;
else
pr_info ( " UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored! \n " ,
vi - > used_bytes - ( size < < 9 ) ) ;
2019-09-01 22:32:05 +02:00
}
if ( ( sector_t ) size ! = size )
return - EFBIG ;
* disk_capacity = size ;
return 0 ;
}
2014-03-04 12:00:26 +02:00
int ubiblock_create ( struct ubi_volume_info * vi )
2014-02-25 13:25:22 -03:00
{
struct ubiblock * dev ;
struct gendisk * gd ;
2019-09-01 22:32:05 +02:00
u64 disk_capacity ;
2014-02-25 13:25:22 -03:00
int ret ;
2019-09-01 22:32:05 +02:00
ret = calc_disk_capacity ( vi , & disk_capacity ) ;
if ( ret ) {
return ret ;
}
2014-02-25 13:25:22 -03:00
/* Check that the volume isn't already handled */
mutex_lock ( & devices_mutex ) ;
if ( find_dev_nolock ( vi - > ubi_num , vi - > vol_id ) ) {
2018-01-18 08:55:20 -05:00
ret = - EEXIST ;
goto out_unlock ;
2014-02-25 13:25:22 -03:00
}
dev = kzalloc ( sizeof ( struct ubiblock ) , GFP_KERNEL ) ;
2018-01-18 08:55:20 -05:00
if ( ! dev ) {
ret = - ENOMEM ;
goto out_unlock ;
}
2014-02-25 13:25:22 -03:00
mutex_init ( & dev - > dev_mutex ) ;
dev - > ubi_num = vi - > ubi_num ;
dev - > vol_id = vi - > vol_id ;
dev - > leb_size = vi - > usable_leb_size ;
2021-06-02 09:53:41 +03:00
dev - > tag_set . ops = & ubiblock_mq_ops ;
dev - > tag_set . queue_depth = 64 ;
dev - > tag_set . numa_node = NUMA_NO_NODE ;
2023-01-12 17:15:40 +01:00
dev - > tag_set . flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING ;
2021-06-02 09:53:41 +03:00
dev - > tag_set . cmd_size = sizeof ( struct ubiblock_pdu ) ;
dev - > tag_set . driver_data = dev ;
dev - > tag_set . nr_hw_queues = 1 ;
ret = blk_mq_alloc_tag_set ( & dev - > tag_set ) ;
if ( ret ) {
dev_err ( disk_to_dev ( dev - > gd ) , " blk_mq_alloc_tag_set failed " ) ;
2022-08-17 09:14:06 +08:00
goto out_free_dev ;
2021-06-02 09:53:41 +03:00
}
2014-02-25 13:25:22 -03:00
/* Initialize the gendisk of this ubiblock device */
2021-06-02 09:53:41 +03:00
gd = blk_mq_alloc_disk ( & dev - > tag_set , dev ) ;
if ( IS_ERR ( gd ) ) {
ret = PTR_ERR ( gd ) ;
goto out_free_tags ;
2014-02-25 13:25:22 -03:00
}
gd - > fops = & ubiblock_ops ;
gd - > major = ubiblock_major ;
2021-06-02 09:53:41 +03:00
gd - > minors = 1 ;
2015-03-17 10:37:26 -07:00
gd - > first_minor = idr_alloc ( & ubiblock_minor_idr , dev , 0 , 0 , GFP_KERNEL ) ;
if ( gd - > first_minor < 0 ) {
dev_err ( disk_to_dev ( gd ) ,
" block: dynamic minor allocation failed " ) ;
ret = - ENODEV ;
2021-06-02 09:53:41 +03:00
goto out_cleanup_disk ;
2015-03-17 10:37:26 -07:00
}
2021-11-22 14:06:22 +01:00
gd - > flags | = GENHD_FL_NO_PART ;
2014-02-25 13:25:22 -03:00
gd - > private_data = dev ;
sprintf ( gd - > disk_name , " ubiblock%d_%d " , dev - > ubi_num , dev - > vol_id ) ;
set_capacity ( gd , disk_capacity ) ;
dev - > gd = gd ;
2021-06-02 09:53:41 +03:00
dev - > rq = gd - > queue ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
blk_queue_max_segments ( dev - > rq , UBI_MAX_SG_COUNT ) ;
2014-02-25 13:25:22 -03:00
list_add_tail ( & dev - > list , & ubiblock_devices ) ;
/* Must be the last step: anyone can call file ops from now on */
2022-12-22 19:33:31 +00:00
ret = device_add_disk ( vi - > dev , dev - > gd , NULL ) ;
2021-11-03 16:04:32 -07:00
if ( ret )
2023-01-12 17:15:40 +01:00
goto out_remove_minor ;
2021-11-03 16:04:32 -07:00
2014-10-20 19:57:00 +03:00
dev_info ( disk_to_dev ( dev - > gd ) , " created from ubi%d:%d(%s) " ,
dev - > ubi_num , dev - > vol_id , vi - > name ) ;
2018-01-18 08:55:20 -05:00
mutex_unlock ( & devices_mutex ) ;
2014-02-25 13:25:22 -03:00
return 0 ;
2015-03-17 10:37:26 -07:00
out_remove_minor :
idr_remove ( & ubiblock_minor_idr , gd - > first_minor ) ;
2021-06-02 09:53:41 +03:00
out_cleanup_disk :
2022-06-19 08:05:52 +02:00
put_disk ( dev - > gd ) ;
2021-06-02 09:53:41 +03:00
out_free_tags :
blk_mq_free_tag_set ( & dev - > tag_set ) ;
2014-02-25 13:25:22 -03:00
out_free_dev :
kfree ( dev ) ;
2018-01-18 08:55:20 -05:00
out_unlock :
mutex_unlock ( & devices_mutex ) ;
2014-02-25 13:25:22 -03:00
return ret ;
}
static void ubiblock_cleanup ( struct ubiblock * dev )
{
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
/* Stop new requests to arrive */
2014-02-25 13:25:22 -03:00
del_gendisk ( dev - > gd ) ;
UBI: Block: Add blk-mq support
Convert the driver to blk-mq.
Beside of moving to the modern block interface this change boosts
also the performance of the driver.
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xda
nand: Micron NAND 256MiB 3,3V 8-bit
nand: 256MiB, SLC, page size: 2048, OOB size: 64
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 4.39295 s, 58.1 MB/s
vs.
root@debian-armhf:~# dd if=/dev/ubiblock0_0 of=/dev/zero bs=1M
243+1 records in
243+1 records out
255080448 bytes (255 MB) copied, 2.87676 s, 88.7 MB/s
Cc: hch@infradead.org
Cc: axboe@fb.com
Cc: tom.leiming@gmail.com
Signed-off-by: Richard Weinberger <richard@nod.at>
Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Reviewed-by: Jens Axboe <axboe@fb.com>
Acked-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
2015-01-10 22:52:14 +01:00
/* Finally destroy the blk queue */
2014-10-20 19:57:00 +03:00
dev_info ( disk_to_dev ( dev - > gd ) , " released " ) ;
2022-06-19 08:05:52 +02:00
put_disk ( dev - > gd ) ;
2021-06-02 09:53:41 +03:00
blk_mq_free_tag_set ( & dev - > tag_set ) ;
2015-03-17 10:37:26 -07:00
idr_remove ( & ubiblock_minor_idr , dev - > gd - > first_minor ) ;
2014-02-25 13:25:22 -03:00
}
2014-03-04 12:00:26 +02:00
int ubiblock_remove ( struct ubi_volume_info * vi )
2014-02-25 13:25:22 -03:00
{
struct ubiblock * dev ;
2018-01-18 08:55:20 -05:00
int ret ;
2014-02-25 13:25:22 -03:00
mutex_lock ( & devices_mutex ) ;
dev = find_dev_nolock ( vi - > ubi_num , vi - > vol_id ) ;
if ( ! dev ) {
2018-01-18 08:55:20 -05:00
ret = - ENODEV ;
goto out_unlock ;
2014-02-25 13:25:22 -03:00
}
/* Found a device, let's lock it so we can check if it's busy */
mutex_lock ( & dev - > dev_mutex ) ;
if ( dev - > refcnt > 0 ) {
2018-01-18 08:55:20 -05:00
ret = - EBUSY ;
goto out_unlock_dev ;
2014-02-25 13:25:22 -03:00
}
/* Remove from device list */
list_del ( & dev - > list ) ;
ubiblock_cleanup ( dev ) ;
mutex_unlock ( & dev - > dev_mutex ) ;
2018-01-18 08:55:20 -05:00
mutex_unlock ( & devices_mutex ) ;
2014-02-25 13:25:22 -03:00
kfree ( dev ) ;
return 0 ;
2018-01-18 08:55:20 -05:00
out_unlock_dev :
mutex_unlock ( & dev - > dev_mutex ) ;
out_unlock :
mutex_unlock ( & devices_mutex ) ;
return ret ;
2014-02-25 13:25:22 -03:00
}
2014-05-05 07:11:52 -03:00
static int ubiblock_resize ( struct ubi_volume_info * vi )
2014-02-25 13:25:22 -03:00
{
struct ubiblock * dev ;
2019-09-01 22:32:05 +02:00
u64 disk_capacity ;
int ret ;
2014-02-25 13:25:22 -03:00
/*
* Need to lock the device list until we stop using the device ,
2014-03-04 12:00:26 +02:00
* otherwise the device struct might get released in
* ' ubiblock_remove ( ) ' .
2014-02-25 13:25:22 -03:00
*/
mutex_lock ( & devices_mutex ) ;
dev = find_dev_nolock ( vi - > ubi_num , vi - > vol_id ) ;
if ( ! dev ) {
mutex_unlock ( & devices_mutex ) ;
2014-05-05 07:11:52 -03:00
return - ENODEV ;
2014-02-25 13:25:22 -03:00
}
2019-09-01 22:32:05 +02:00
ret = calc_disk_capacity ( vi , & disk_capacity ) ;
if ( ret ) {
2014-08-20 10:19:38 +01:00
mutex_unlock ( & devices_mutex ) ;
2019-09-01 22:32:05 +02:00
if ( ret = = - EFBIG ) {
dev_warn ( disk_to_dev ( dev - > gd ) ,
" the volume is too big (%d LEBs), cannot resize " ,
vi - > size ) ;
}
return ret ;
2014-08-20 10:19:38 +01:00
}
2014-02-25 13:25:22 -03:00
mutex_lock ( & dev - > dev_mutex ) ;
2014-08-29 18:42:29 -03:00
if ( get_capacity ( dev - > gd ) ! = disk_capacity ) {
set_capacity ( dev - > gd , disk_capacity ) ;
2014-10-20 19:57:00 +03:00
dev_info ( disk_to_dev ( dev - > gd ) , " resized to %lld bytes " ,
vi - > used_bytes ) ;
2014-08-29 18:42:29 -03:00
}
2014-02-25 13:25:22 -03:00
mutex_unlock ( & dev - > dev_mutex ) ;
mutex_unlock ( & devices_mutex ) ;
2014-05-05 07:11:52 -03:00
return 0 ;
2014-02-25 13:25:22 -03:00
}
static int ubiblock_notify ( struct notifier_block * nb ,
unsigned long notification_type , void * ns_ptr )
{
struct ubi_notification * nt = ns_ptr ;
switch ( notification_type ) {
case UBI_VOLUME_ADDED :
/*
2014-03-04 12:00:26 +02:00
* We want to enforce explicit block device creation for
2014-02-25 13:25:22 -03:00
* volumes , so when a volume is added we do nothing .
*/
break ;
case UBI_VOLUME_REMOVED :
2014-03-04 12:00:26 +02:00
ubiblock_remove ( & nt - > vi ) ;
2014-02-25 13:25:22 -03:00
break ;
case UBI_VOLUME_RESIZED :
ubiblock_resize ( & nt - > vi ) ;
break ;
2014-08-29 18:42:29 -03:00
case UBI_VOLUME_UPDATED :
/*
* If the volume is static , a content update might mean the
* size ( i . e . used_bytes ) was also changed .
*/
if ( nt - > vi . vol_type = = UBI_STATIC_VOLUME )
ubiblock_resize ( & nt - > vi ) ;
break ;
2014-02-25 13:25:22 -03:00
default :
break ;
}
return NOTIFY_OK ;
}
static struct notifier_block ubiblock_notifier = {
. notifier_call = ubiblock_notify ,
} ;
static struct ubi_volume_desc * __init
open_volume_desc ( const char * name , int ubi_num , int vol_id )
{
if ( ubi_num = = - 1 )
/* No ubi num, name must be a vol device path */
return ubi_open_volume_path ( name , UBI_READONLY ) ;
else if ( vol_id = = - 1 )
/* No vol_id, must be vol_name */
return ubi_open_volume_nm ( ubi_num , name , UBI_READONLY ) ;
else
return ubi_open_volume ( ubi_num , vol_id , UBI_READONLY ) ;
}
2014-12-19 11:27:18 -08:00
static void __init ubiblock_create_from_param ( void )
2014-02-25 13:25:22 -03:00
{
2014-12-19 11:27:18 -08:00
int i , ret = 0 ;
2014-02-25 13:25:22 -03:00
struct ubiblock_param * p ;
struct ubi_volume_desc * desc ;
struct ubi_volume_info vi ;
2014-12-19 11:27:18 -08:00
/*
* If there is an error creating one of the ubiblocks , continue on to
* create the following ubiblocks . This helps in a circumstance where
* the kernel command - line specifies multiple block devices and some
* may be broken , but we still want the working ones to come up .
*/
2014-02-25 13:25:22 -03:00
for ( i = 0 ; i < ubiblock_devs ; i + + ) {
p = & ubiblock_param [ i ] ;
desc = open_volume_desc ( p - > name , p - > ubi_num , p - > vol_id ) ;
if ( IS_ERR ( desc ) ) {
2014-12-19 11:27:18 -08:00
pr_err (
2017-07-26 10:53:50 +01:00
" UBI: block: can't open volume on ubi%d_%d, err=%ld \n " ,
2014-12-19 11:27:18 -08:00
p - > ubi_num , p - > vol_id , PTR_ERR ( desc ) ) ;
continue ;
2014-02-25 13:25:22 -03:00
}
ubi_get_volume_info ( desc , & vi ) ;
ubi_close_volume ( desc ) ;
2014-03-04 12:00:26 +02:00
ret = ubiblock_create ( & vi ) ;
2014-02-25 13:25:22 -03:00
if ( ret ) {
2014-12-19 11:27:18 -08:00
pr_err (
2017-07-26 10:53:50 +01:00
" UBI: block: can't add '%s' volume on ubi%d_%d, err=%d \n " ,
2014-12-19 11:27:18 -08:00
vi . name , p - > ubi_num , p - > vol_id , ret ) ;
continue ;
2014-02-25 13:25:22 -03:00
}
}
}
2014-03-04 12:00:26 +02:00
static void ubiblock_remove_all ( void )
2014-02-25 13:25:22 -03:00
{
struct ubiblock * next ;
struct ubiblock * dev ;
2018-01-18 08:55:20 -05:00
mutex_lock ( & devices_mutex ) ;
2014-02-25 13:25:22 -03:00
list_for_each_entry_safe ( dev , next , & ubiblock_devices , list ) {
/* The module is being forcefully removed */
WARN_ON ( dev - > desc ) ;
/* Remove from device list */
list_del ( & dev - > list ) ;
ubiblock_cleanup ( dev ) ;
kfree ( dev ) ;
}
2018-01-18 08:55:20 -05:00
mutex_unlock ( & devices_mutex ) ;
2014-02-25 13:25:22 -03:00
}
int __init ubiblock_init ( void )
{
int ret ;
ubiblock_major = register_blkdev ( 0 , " ubiblock " ) ;
if ( ubiblock_major < 0 )
return ubiblock_major ;
2014-12-19 11:27:18 -08:00
/*
* Attach block devices from ' block = ' module param .
* Even if one block device in the param list fails to come up ,
* still allow the module to load and leave any others up .
*/
ubiblock_create_from_param ( ) ;
2014-02-25 13:25:22 -03:00
/*
2014-03-04 12:00:26 +02:00
* Block devices are only created upon user requests , so we ignore
* existing volumes .
2014-02-25 13:25:22 -03:00
*/
ret = ubi_register_volume_notifier ( & ubiblock_notifier , 1 ) ;
if ( ret )
goto err_unreg ;
return 0 ;
err_unreg :
unregister_blkdev ( ubiblock_major , " ubiblock " ) ;
2014-03-04 12:00:26 +02:00
ubiblock_remove_all ( ) ;
2014-02-25 13:25:22 -03:00
return ret ;
}
void __exit ubiblock_exit ( void )
{
ubi_unregister_volume_notifier ( & ubiblock_notifier ) ;
2014-03-04 12:00:26 +02:00
ubiblock_remove_all ( ) ;
2014-02-25 13:25:22 -03:00
unregister_blkdev ( ubiblock_major , " ubiblock " ) ;
}