2019-08-25 10:49:16 +01:00
// SPDX-License-Identifier: GPL-2.0
2006-03-27 01:14:37 -08:00
/*
2018-11-14 18:41:08 +00:00
* Copyright ( C ) 2018 Cambridge Greys Ltd
2016-11-09 20:43:25 +00:00
* Copyright ( C ) 2015 - 2016 Anton Ivanov ( aivanov @ brocade . com )
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 2000 Jeff Dike ( jdike @ karaya . com )
*/
/* 2001-09-28...2002-04-17
* Partition stuff by James_McMechan @ hotmail . com
* old style ubd by setting UBD_SHIFT to 0
* 2002 - 09 - 27. . .2002 - 10 - 18 massive tinkering for 2.5
* partitions have changed in 2.5
* 2003 - 01 - 29 more tinkering for 2.5 .59 - 1
* This should now address the sysfs problems and has
* the symlink for devfs to allow for booting with
* the common / dev / ubd / discX / . . . names rather than
* only / dev / ubdN / discN this version also has lots of
* clean ups preparing for ubd - many .
* James McMechan
*/
# define UBD_SHIFT 4
2011-08-18 18:04:41 -04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/blkdev.h>
2017-11-26 13:33:11 +01:00
# include <linux/blk-mq.h>
2011-08-18 18:04:41 -04:00
# include <linux/ata.h>
# include <linux/hdreg.h>
# include <linux/cdrom.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/ctype.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/platform_device.h>
# include <linux/scatterlist.h>
# include <asm/tlbflush.h>
2012-10-08 03:27:32 +01:00
# include <kern_util.h>
2005-04-16 15:20:36 -07:00
# include "mconsole_kern.h"
2012-10-08 03:27:32 +01:00
# include <init.h>
# include <irq_kern.h>
2011-08-18 18:04:41 -04:00
# include "ubd.h"
2012-10-08 03:27:32 +01:00
# include <os.h>
2005-04-16 15:20:36 -07:00
# include "cow.h"
2018-11-14 18:41:06 +00:00
/* Max request size is determined by sector mask - 32K */
# define UBD_MAX_REQUEST (8 * sizeof(long))
2005-04-16 15:20:36 -07:00
struct io_thread_req {
2007-02-10 01:44:16 -08:00
struct request * req ;
2005-04-16 15:20:36 -07:00
int fds [ 2 ] ;
unsigned long offsets [ 2 ] ;
unsigned long long offset ;
unsigned long length ;
char * buffer ;
int sectorsize ;
2005-10-10 23:10:32 -04:00
unsigned long sector_mask ;
unsigned long long cow_offset ;
unsigned long bitmap_words [ 2 ] ;
2005-04-16 15:20:36 -07:00
int error ;
} ;
2016-11-09 20:43:25 +00:00
static struct io_thread_req * ( * irq_req_buffer ) [ ] ;
static struct io_thread_req * irq_remainder ;
static int irq_remainder_size ;
static struct io_thread_req * ( * io_req_buffer ) [ ] ;
static struct io_thread_req * io_remainder ;
static int io_remainder_size ;
2005-10-10 23:10:32 -04:00
static inline int ubd_test_bit ( __u64 bit , unsigned char * data )
2005-04-16 15:20:36 -07:00
{
__u64 n ;
int bits , off ;
2005-10-10 23:10:32 -04:00
bits = sizeof ( data [ 0 ] ) * 8 ;
2005-04-16 15:20:36 -07:00
n = bit / bits ;
off = bit % bits ;
2007-05-06 14:51:41 -07:00
return ( data [ n ] & ( 1 < < off ) ) ! = 0 ;
2005-04-16 15:20:36 -07:00
}
2005-10-10 23:10:32 -04:00
static inline void ubd_set_bit ( __u64 bit , unsigned char * data )
2005-04-16 15:20:36 -07:00
{
__u64 n ;
int bits , off ;
2005-10-10 23:10:32 -04:00
bits = sizeof ( data [ 0 ] ) * 8 ;
2005-04-16 15:20:36 -07:00
n = bit / bits ;
off = bit % bits ;
2005-10-10 23:10:32 -04:00
data [ n ] | = ( 1 < < off ) ;
2005-04-16 15:20:36 -07:00
}
/*End stuff from ubd_user.h*/
# define DRIVER_NAME "uml-blkdev"
2006-10-30 22:07:07 -08:00
static DEFINE_MUTEX ( ubd_lock ) ;
2010-09-11 18:38:03 +02:00
static DEFINE_MUTEX ( ubd_mutex ) ; /* replaces BKL, might not be needed */
2005-04-16 15:20:36 -07:00
2008-03-02 09:16:26 -05:00
static int ubd_open ( struct block_device * bdev , fmode_t mode ) ;
2013-05-05 21:52:57 -04:00
static void ubd_release ( struct gendisk * disk , fmode_t mode ) ;
2008-03-02 09:16:26 -05:00
static int ubd_ioctl ( struct block_device * bdev , fmode_t mode ,
2005-04-16 15:20:36 -07:00
unsigned int cmd , unsigned long arg ) ;
2006-01-08 01:02:50 -08:00
static int ubd_getgeo ( struct block_device * bdev , struct hd_geometry * geo ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:03 -08:00
# define MAX_DEV (16)
2005-04-16 15:20:36 -07:00
2009-09-21 17:01:13 -07:00
static const struct block_device_operations ubd_blops = {
2005-04-16 15:20:36 -07:00
. owner = THIS_MODULE ,
2008-03-02 09:16:26 -05:00
. open = ubd_open ,
. release = ubd_release ,
. ioctl = ubd_ioctl ,
2019-11-30 20:09:07 +01:00
. compat_ioctl = blkdev_compat_ptr_ioctl ,
2006-01-08 01:02:50 -08:00
. getgeo = ubd_getgeo ,
2005-04-16 15:20:36 -07:00
} ;
/* Protected by ubd_lock */
2009-03-31 15:23:39 -07:00
static int fake_major = UBD_MAJOR ;
2005-04-16 15:20:36 -07:00
static struct gendisk * ubd_gendisk [ MAX_DEV ] ;
static struct gendisk * fake_gendisk [ MAX_DEV ] ;
2006-03-27 01:14:37 -08:00
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_BLK_DEV_UBD_SYNC
# define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
. cl = 1 } )
# else
# define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
. cl = 1 } )
# endif
static struct openflags global_openflags = OPEN_FLAGS ;
struct cow {
2006-10-30 22:07:04 -08:00
/* backing file name */
2005-04-16 15:20:36 -07:00
char * file ;
2006-10-30 22:07:04 -08:00
/* backing file fd */
2005-04-16 15:20:36 -07:00
int fd ;
unsigned long * bitmap ;
unsigned long bitmap_len ;
int bitmap_offset ;
2007-05-06 14:51:41 -07:00
int data_offset ;
2005-04-16 15:20:36 -07:00
} ;
2007-05-06 14:51:36 -07:00
# define MAX_SG 64
2005-04-16 15:20:36 -07:00
struct ubd {
2006-10-30 22:07:04 -08:00
/* name (and fd, below) of the file opened for writing, either the
* backing or the cow file . */
2005-04-16 15:20:36 -07:00
char * file ;
int count ;
int fd ;
__u64 size ;
struct openflags boot_openflags ;
struct openflags openflags ;
2006-10-30 22:07:10 -08:00
unsigned shared : 1 ;
unsigned no_cow : 1 ;
2018-11-14 18:41:09 +00:00
unsigned no_trim : 1 ;
2005-04-16 15:20:36 -07:00
struct cow cow ;
struct platform_device pdev ;
2007-02-10 01:44:16 -08:00
struct request_queue * queue ;
2017-11-26 13:33:11 +01:00
struct blk_mq_tag_set tag_set ;
2007-02-10 01:44:16 -08:00
spinlock_t lock ;
2017-11-26 13:33:11 +01:00
} ;
2005-04-16 15:20:36 -07:00
# define DEFAULT_COW { \
. file = NULL , \
2007-05-06 14:51:41 -07:00
. fd = - 1 , \
. bitmap = NULL , \
2005-04-16 15:20:36 -07:00
. bitmap_offset = 0 , \
2007-05-06 14:51:41 -07:00
. data_offset = 0 , \
2005-04-16 15:20:36 -07:00
}
# define DEFAULT_UBD { \
. file = NULL , \
. count = 0 , \
. fd = - 1 , \
. size = - 1 , \
. boot_openflags = OPEN_FLAGS , \
. openflags = OPEN_FLAGS , \
2007-05-06 14:51:41 -07:00
. no_cow = 0 , \
2018-11-14 18:41:09 +00:00
. no_trim = 0 , \
2006-03-27 01:14:37 -08:00
. shared = 0 , \
2007-05-06 14:51:41 -07:00
. cow = DEFAULT_COW , \
2011-01-23 15:21:25 +01:00
. lock = __SPIN_LOCK_UNLOCKED ( ubd_devs . lock ) , \
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:44:17 -08:00
/* Protected by ubd_lock */
2008-04-28 02:13:58 -07:00
static struct ubd ubd_devs [ MAX_DEV ] = { [ 0 . . . MAX_DEV - 1 ] = DEFAULT_UBD } ;
2005-04-16 15:20:36 -07:00
/* Only changed by fake_ide_setup which is a setup */
static int fake_ide = 0 ;
static struct proc_dir_entry * proc_ide_root = NULL ;
static struct proc_dir_entry * proc_ide = NULL ;
2017-11-26 13:33:11 +01:00
static blk_status_t ubd_queue_rq ( struct blk_mq_hw_ctx * hctx ,
const struct blk_mq_queue_data * bd ) ;
2005-04-16 15:20:36 -07:00
static void make_proc_ide ( void )
{
proc_ide_root = proc_mkdir ( " ide " , NULL ) ;
proc_ide = proc_mkdir ( " ide0 " , proc_ide_root ) ;
}
2009-12-14 18:00:11 -08:00
static int fake_ide_media_proc_show ( struct seq_file * m , void * v )
2005-04-16 15:20:36 -07:00
{
2009-12-14 18:00:11 -08:00
seq_puts ( m , " disk \n " ) ;
return 0 ;
}
2008-02-04 22:30:41 -08:00
static void make_ide_entries ( const char * dev_name )
2005-04-16 15:20:36 -07:00
{
struct proc_dir_entry * dir , * ent ;
char name [ 64 ] ;
if ( proc_ide_root = = NULL ) make_proc_ide ( ) ;
dir = proc_mkdir ( dev_name , proc_ide ) ;
if ( ! dir ) return ;
2018-05-15 15:57:23 +02:00
ent = proc_create_single ( " media " , S_IRUGO , dir ,
fake_ide_media_proc_show ) ;
2005-04-16 15:20:36 -07:00
if ( ! ent ) return ;
2008-02-04 22:30:41 -08:00
snprintf ( name , sizeof ( name ) , " ide0/%s " , dev_name ) ;
2005-04-16 15:20:36 -07:00
proc_symlink ( dev_name , proc_ide_root , name ) ;
}
static int fake_ide_setup ( char * str )
{
fake_ide = 1 ;
2007-05-06 14:51:41 -07:00
return 1 ;
2005-04-16 15:20:36 -07:00
}
__setup ( " fake_ide " , fake_ide_setup ) ;
__uml_help ( fake_ide_setup ,
" fake_ide \n "
" Create ide0 entries that map onto ubd devices. \n \n "
) ;
static int parse_unit ( char * * ptr )
{
char * str = * ptr , * end ;
int n = - 1 ;
if ( isdigit ( * str ) ) {
n = simple_strtoul ( str , & end , 0 ) ;
if ( end = = str )
2007-05-06 14:51:41 -07:00
return - 1 ;
2005-04-16 15:20:36 -07:00
* ptr = end ;
}
2006-10-30 22:07:03 -08:00
else if ( ( ' a ' < = * str ) & & ( * str < = ' z ' ) ) {
2005-04-16 15:20:36 -07:00
n = * str - ' a ' ;
str + + ;
* ptr = str ;
}
2007-05-06 14:51:41 -07:00
return n ;
2005-04-16 15:20:36 -07:00
}
2006-10-30 22:07:12 -08:00
/* If *index_out == -1 at exit, the passed option was a general one;
* otherwise , the str pointer is used ( and owned ) inside ubd_devs array , so it
* should not be freed on exit .
*/
2007-02-10 01:43:53 -08:00
static int ubd_setup_common ( char * str , int * index_out , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev ;
2005-04-16 15:20:36 -07:00
struct openflags flags = global_openflags ;
char * backing_file ;
2007-02-10 01:44:17 -08:00
int n , err = 0 , i ;
2005-04-16 15:20:36 -07:00
if ( index_out ) * index_out = - 1 ;
n = * str ;
if ( n = = ' = ' ) {
char * end ;
int major ;
str + + ;
if ( ! strcmp ( str , " sync " ) ) {
global_openflags = of_sync ( global_openflags ) ;
2019-04-02 10:43:32 +02:00
return err ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:44:17 -08:00
err = - EINVAL ;
2005-04-16 15:20:36 -07:00
major = simple_strtoul ( str , & end , 0 ) ;
if ( ( * end ! = ' \0 ' ) | | ( end = = str ) ) {
2007-02-10 01:43:53 -08:00
* error_out = " Didn't parse major number " ;
2019-04-02 10:43:32 +02:00
return err ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
mutex_lock ( & ubd_lock ) ;
2009-03-31 15:23:39 -07:00
if ( fake_major ! = UBD_MAJOR ) {
2007-02-10 01:43:53 -08:00
* error_out = " Can't assign a fake major twice " ;
goto out1 ;
}
2006-03-27 01:14:37 -08:00
2007-02-10 01:43:53 -08:00
fake_major = major ;
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " Setting extra ubd major number to %d \n " ,
major ) ;
2007-02-10 01:43:53 -08:00
err = 0 ;
out1 :
mutex_unlock ( & ubd_lock ) ;
return err ;
2005-04-16 15:20:36 -07:00
}
n = parse_unit ( & str ) ;
if ( n < 0 ) {
2007-02-10 01:43:53 -08:00
* error_out = " Couldn't parse device number " ;
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
if ( n > = MAX_DEV ) {
2007-02-10 01:43:53 -08:00
* error_out = " Device number out of range " ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
err = - EBUSY ;
2006-10-30 22:07:07 -08:00
mutex_lock ( & ubd_lock ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
ubd_dev = & ubd_devs [ n ] ;
if ( ubd_dev - > file ! = NULL ) {
2007-02-10 01:43:53 -08:00
* error_out = " Device is already configured " ;
2005-04-16 15:20:36 -07:00
goto out ;
}
if ( index_out )
* index_out = n ;
2007-02-10 01:43:53 -08:00
err = - EINVAL ;
2018-11-14 18:41:09 +00:00
for ( i = 0 ; i < sizeof ( " rscdt= " ) ; i + + ) {
2005-04-16 15:20:36 -07:00
switch ( * str ) {
case ' r ' :
flags . w = 0 ;
break ;
case ' s ' :
flags . s = 1 ;
break ;
case ' d ' :
2006-10-30 22:07:05 -08:00
ubd_dev - > no_cow = 1 ;
2005-04-16 15:20:36 -07:00
break ;
2006-03-27 01:14:37 -08:00
case ' c ' :
2006-10-30 22:07:05 -08:00
ubd_dev - > shared = 1 ;
2006-03-27 01:14:37 -08:00
break ;
2018-11-14 18:41:09 +00:00
case ' t ' :
ubd_dev - > no_trim = 1 ;
break ;
2005-04-16 15:20:36 -07:00
case ' = ' :
str + + ;
goto break_loop ;
default :
2007-02-10 01:43:53 -08:00
* error_out = " Expected '=' or flag letter "
2018-11-14 18:41:09 +00:00
" (r, s, c, t or d) " ;
2005-04-16 15:20:36 -07:00
goto out ;
}
str + + ;
}
2007-02-10 01:43:53 -08:00
if ( * str = = ' = ' )
* error_out = " Too many flags specified " ;
else
* error_out = " Missing '=' " ;
2005-04-16 15:20:36 -07:00
goto out ;
break_loop :
backing_file = strchr ( str , ' , ' ) ;
2007-02-10 01:43:53 -08:00
if ( backing_file = = NULL )
2005-04-16 15:20:36 -07:00
backing_file = strchr ( str , ' : ' ) ;
2007-02-10 01:43:53 -08:00
if ( backing_file ! = NULL ) {
if ( ubd_dev - > no_cow ) {
* error_out = " Can't specify both 'd' and a cow file " ;
goto out ;
}
2005-04-16 15:20:36 -07:00
else {
* backing_file = ' \0 ' ;
backing_file + + ;
}
}
2007-02-10 01:43:53 -08:00
err = 0 ;
2006-10-30 22:07:05 -08:00
ubd_dev - > file = str ;
ubd_dev - > cow . file = backing_file ;
ubd_dev - > boot_openflags = flags ;
2005-04-16 15:20:36 -07:00
out :
2006-10-30 22:07:07 -08:00
mutex_unlock ( & ubd_lock ) ;
2007-02-10 01:43:53 -08:00
return err ;
2005-04-16 15:20:36 -07:00
}
static int ubd_setup ( char * str )
{
2007-02-10 01:43:53 -08:00
char * error ;
int err ;
err = ubd_setup_common ( str , NULL , & error ) ;
if ( err )
printk ( KERN_ERR " Failed to initialize device with \" %s \" : "
" %s \n " , str , error ) ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
__setup ( " ubd " , ubd_setup ) ;
__uml_help ( ubd_setup ,
" ubd<n><flags>=<filename>[(:|,)<filename2>] \n "
" This is used to associate a device with a file in the underlying \n "
" filesystem. When specifying two filenames, the first one is the \n "
" COW name and the second is the backing file name. As separator you can \n "
" use either a ':' or a ',': the first one allows writing things like; \n "
" ubd0=~/Uml/root_cow:~/Uml/root_backing_file \n "
" while with a ',' the shell would not expand the 2nd '~'. \n "
2007-02-10 01:43:53 -08:00
" When using only one filename, UML will detect whether to treat it like \n "
2005-04-16 15:20:36 -07:00
" a COW file or a backing file. To override this detection, add the 'd' \n "
" flag: \n "
" ubd0d=BackingFile \n "
" Usually, there is a filesystem in the file, but \n "
" that's not required. Swap devices containing swap files can be \n "
" specified like this. Also, a file which doesn't contain a \n "
" filesystem can have its contents read in the virtual \n "
" machine by running 'dd' on the device. <n> must be in the range \n "
" 0 to 7. Appending an 'r' to the number will cause that device \n "
" to be mounted read-only. For example ubd1r=./ext_fs. Appending \n "
2008-02-04 22:30:37 -08:00
" an 's' will cause data to be written to disk on the host immediately. \n "
" 'c' will cause the device to be treated as being shared between multiple \n "
" UMLs and file locking will be turned off - this is appropriate for a \n "
" cluster filesystem and inappropriate at almost all other times. \n \n "
2018-11-14 18:41:09 +00:00
" 't' will disable trim/discard support on the device (enabled by default). \n \n "
2005-04-16 15:20:36 -07:00
) ;
2008-02-04 22:30:48 -08:00
static int udb_setup ( char * str )
2005-04-16 15:20:36 -07:00
{
printk ( " udb%s specified on command line is almost certainly a ubd -> "
" udb TYPO \n " , str ) ;
2007-05-06 14:51:41 -07:00
return 1 ;
2005-04-16 15:20:36 -07:00
}
__setup ( " udb " , udb_setup ) ;
__uml_help ( udb_setup ,
" udb \n "
2005-05-28 15:51:55 -07:00
" This option is here solely to catch ubd -> udb typos, which can be \n "
" to impossible to catch visually unless you specifically look for \n "
" them. The only result of any option starting with 'udb' is an error \n "
2005-04-16 15:20:36 -07:00
" in the boot output. \n \n "
) ;
2005-10-10 23:10:32 -04:00
/* Only changed by ubd_init, which is an initcall. */
2008-04-28 02:13:58 -07:00
static int thread_fd = - 1 ;
2007-05-06 14:51:36 -07:00
2016-11-09 20:43:25 +00:00
/* Function to read several request pointers at a time
* handling fractional reads if ( and as ) needed
*/
static int bulk_req_safe_read (
int fd ,
struct io_thread_req * ( * request_buffer ) [ ] ,
struct io_thread_req * * remainder ,
int * remainder_size ,
int max_recs
)
{
int n = 0 ;
int res = 0 ;
if ( * remainder_size > 0 ) {
memmove (
( char * ) request_buffer ,
( char * ) remainder , * remainder_size
) ;
n = * remainder_size ;
}
res = os_read_file (
fd ,
( ( char * ) request_buffer ) + * remainder_size ,
sizeof ( struct io_thread_req * ) * max_recs
- * remainder_size
) ;
if ( res > 0 ) {
n + = res ;
if ( ( n % sizeof ( struct io_thread_req * ) ) > 0 ) {
/*
* Read somehow returned not a multiple of dword
* theoretically possible , but never observed in the
* wild , so read routine must be able to handle it
*/
* remainder_size = n % sizeof ( struct io_thread_req * ) ;
WARN ( * remainder_size > 0 , " UBD IPC read returned a partial result " ) ;
memmove (
remainder ,
( ( char * ) request_buffer ) +
( n / sizeof ( struct io_thread_req * ) ) * sizeof ( struct io_thread_req * ) ,
* remainder_size
) ;
n = n - * remainder_size ;
}
} else {
n = res ;
}
return n ;
}
2007-02-10 01:44:16 -08:00
/* Called without dev->lock held, and only in interrupt context. */
2005-10-10 23:10:32 -04:00
static void ubd_handler ( void )
2005-04-16 15:20:36 -07:00
{
2005-10-10 23:10:32 -04:00
int n ;
2016-11-09 20:43:25 +00:00
int count ;
2005-10-10 23:10:32 -04:00
2007-05-06 14:51:36 -07:00
while ( 1 ) {
2016-11-09 20:43:25 +00:00
n = bulk_req_safe_read (
thread_fd ,
irq_req_buffer ,
& irq_remainder ,
& irq_remainder_size ,
UBD_REQ_BUFFER_SIZE
) ;
if ( n < 0 ) {
2007-05-06 14:51:36 -07:00
if ( n = = - EAGAIN )
break ;
printk ( KERN_ERR " spurious interrupt in ubd_handler, "
" err = %d \n " , - n ) ;
return ;
}
2016-11-09 20:43:25 +00:00
for ( count = 0 ; count < n / sizeof ( struct io_thread_req * ) ; count + + ) {
2017-11-26 13:33:11 +01:00
struct io_thread_req * io_req = ( * irq_req_buffer ) [ count ] ;
2018-11-14 18:41:09 +00:00
if ( ( io_req - > error = = BLK_STS_NOTSUPP ) & & ( req_op ( io_req - > req ) = = REQ_OP_DISCARD ) ) {
blk_queue_max_discard_sectors ( io_req - > req - > q , 0 ) ;
blk_queue_max_write_zeroes_sectors ( io_req - > req - > q , 0 ) ;
blk_queue_flag_clear ( QUEUE_FLAG_DISCARD , io_req - > req - > q ) ;
}
if ( ( io_req - > error ) | | ( io_req - > buffer = = NULL ) )
blk_mq_end_request ( io_req - > req , io_req - > error ) ;
else {
if ( ! blk_update_request ( io_req - > req , io_req - > error , io_req - > length ) )
__blk_mq_end_request ( io_req - > req , io_req - > error ) ;
}
2017-11-26 13:33:11 +01:00
kfree ( io_req ) ;
2016-11-09 20:43:25 +00:00
}
2007-05-06 14:51:36 -07:00
}
2005-04-16 15:20:36 -07:00
}
2006-10-08 22:49:34 +01:00
static irqreturn_t ubd_intr ( int irq , void * dev )
2005-04-16 15:20:36 -07:00
{
2005-10-10 23:10:32 -04:00
ubd_handler ( ) ;
2007-05-06 14:51:41 -07:00
return IRQ_HANDLED ;
2005-10-10 23:10:32 -04:00
}
2005-09-03 15:57:46 -07:00
2005-10-10 23:10:32 -04:00
/* Only changed by ubd_init, which is an initcall. */
static int io_pid = - 1 ;
2005-09-03 15:57:46 -07:00
2008-04-28 02:13:58 -07:00
static void kill_io_thread ( void )
2005-10-10 23:10:32 -04:00
{
2006-03-27 01:14:37 -08:00
if ( io_pid ! = - 1 )
2005-10-10 23:10:32 -04:00
os_kill_process ( io_pid , 1 ) ;
2005-09-03 15:57:46 -07:00
}
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
__uml_exitcall ( kill_io_thread ) ;
2006-10-30 22:07:12 -08:00
static inline int ubd_file_size ( struct ubd * ubd_dev , __u64 * size_out )
2005-04-16 15:20:36 -07:00
{
char * file ;
2011-11-02 13:17:27 +01:00
int fd ;
int err ;
__u32 version ;
__u32 align ;
char * backing_file ;
2019-11-05 09:39:51 +01:00
time64_t mtime ;
2011-11-02 13:17:27 +01:00
unsigned long long size ;
int sector_size ;
int bitmap_offset ;
if ( ubd_dev - > file & & ubd_dev - > cow . file ) {
file = ubd_dev - > cow . file ;
goto out ;
}
2012-08-02 00:44:22 +02:00
fd = os_open_file ( ubd_dev - > file , of_read ( OPENFLAGS ( ) ) , 0 ) ;
2011-11-02 13:17:27 +01:00
if ( fd < 0 )
return fd ;
err = read_cow_header ( file_reader , & fd , & version , & backing_file , \
& mtime , & size , & sector_size , & align , & bitmap_offset ) ;
os_close_file ( fd ) ;
2005-04-16 15:20:36 -07:00
2011-11-02 13:17:27 +01:00
if ( err = = - EINVAL )
file = ubd_dev - > file ;
else
file = backing_file ;
out :
2007-05-06 14:51:41 -07:00
return os_file_size ( file , size_out ) ;
2005-04-16 15:20:36 -07:00
}
2008-04-28 02:13:58 -07:00
static int read_cow_bitmap ( int fd , void * buf , int offset , int len )
{
int err ;
2015-12-21 18:54:00 +00:00
err = os_pread_file ( fd , buf , len , offset ) ;
2008-04-28 02:13:58 -07:00
if ( err < 0 )
return err ;
return 0 ;
}
2019-11-05 09:39:51 +01:00
static int backing_file_mismatch ( char * file , __u64 size , time64_t mtime )
2008-04-28 02:13:58 -07:00
{
2019-11-05 09:39:51 +01:00
time64_t modtime ;
2008-04-28 02:13:58 -07:00
unsigned long long actual ;
int err ;
err = os_file_modtime ( file , & modtime ) ;
if ( err < 0 ) {
printk ( KERN_ERR " Failed to get modification time of backing "
" file \" %s \" , err = %d \n " , file , - err ) ;
return err ;
}
err = os_file_size ( file , & actual ) ;
if ( err < 0 ) {
printk ( KERN_ERR " Failed to get size of backing file \" %s \" , "
" err = %d \n " , file , - err ) ;
return err ;
}
if ( actual ! = size ) {
/*__u64 can be a long on AMD64 and with %lu GCC complains; so
* the typecast . */
printk ( KERN_ERR " Size mismatch (%llu vs %llu) of COW header "
" vs backing file \n " , ( unsigned long long ) size , actual ) ;
return - EINVAL ;
}
if ( modtime ! = mtime ) {
2019-11-05 09:39:51 +01:00
printk ( KERN_ERR " mtime mismatch (%lld vs %lld) of COW header vs "
2008-04-28 02:13:58 -07:00
" backing file \n " , mtime , modtime ) ;
return - EINVAL ;
}
return 0 ;
}
static int path_requires_switch ( char * from_cmdline , char * from_cow , char * cow )
{
struct uml_stat buf1 , buf2 ;
int err ;
if ( from_cmdline = = NULL )
return 0 ;
if ( ! strcmp ( from_cmdline , from_cow ) )
return 0 ;
err = os_stat_file ( from_cmdline , & buf1 ) ;
if ( err < 0 ) {
printk ( KERN_ERR " Couldn't stat '%s', err = %d \n " , from_cmdline ,
- err ) ;
return 0 ;
}
err = os_stat_file ( from_cow , & buf2 ) ;
if ( err < 0 ) {
printk ( KERN_ERR " Couldn't stat '%s', err = %d \n " , from_cow ,
- err ) ;
return 1 ;
}
if ( ( buf1 . ust_dev = = buf2 . ust_dev ) & & ( buf1 . ust_ino = = buf2 . ust_ino ) )
return 0 ;
printk ( KERN_ERR " Backing file mismatch - \" %s \" requested, "
" \" %s \" specified in COW header of \" %s \" \n " ,
from_cmdline , from_cow , cow ) ;
return 1 ;
}
static int open_ubd_file ( char * file , struct openflags * openflags , int shared ,
char * * backing_file_out , int * bitmap_offset_out ,
unsigned long * bitmap_len_out , int * data_offset_out ,
int * create_cow_out )
{
2019-11-05 09:39:51 +01:00
time64_t mtime ;
2008-04-28 02:13:58 -07:00
unsigned long long size ;
__u32 version , align ;
char * backing_file ;
int fd , err , sectorsize , asked_switch , mode = 0644 ;
fd = os_open_file ( file , * openflags , mode ) ;
if ( fd < 0 ) {
if ( ( fd = = - ENOENT ) & & ( create_cow_out ! = NULL ) )
* create_cow_out = 1 ;
if ( ! openflags - > w | |
( ( fd ! = - EROFS ) & & ( fd ! = - EACCES ) ) )
return fd ;
openflags - > w = 0 ;
fd = os_open_file ( file , * openflags , mode ) ;
if ( fd < 0 )
return fd ;
}
if ( shared )
printk ( KERN_INFO " Not locking \" %s \" on the host \n " , file ) ;
else {
err = os_lock_file ( fd , openflags - > w ) ;
if ( err < 0 ) {
printk ( KERN_ERR " Failed to lock '%s', err = %d \n " ,
file , - err ) ;
goto out_close ;
}
}
/* Successful return case! */
if ( backing_file_out = = NULL )
return fd ;
err = read_cow_header ( file_reader , & fd , & version , & backing_file , & mtime ,
& size , & sectorsize , & align , bitmap_offset_out ) ;
if ( err & & ( * backing_file_out ! = NULL ) ) {
printk ( KERN_ERR " Failed to read COW header from COW file "
" \" %s \" , errno = %d \n " , file , - err ) ;
goto out_close ;
}
if ( err )
return fd ;
asked_switch = path_requires_switch ( * backing_file_out , backing_file ,
file ) ;
/* Allow switching only if no mismatch. */
if ( asked_switch & & ! backing_file_mismatch ( * backing_file_out , size ,
mtime ) ) {
printk ( KERN_ERR " Switching backing file to '%s' \n " ,
* backing_file_out ) ;
err = write_cow_header ( file , fd , * backing_file_out ,
sectorsize , align , & size ) ;
if ( err ) {
printk ( KERN_ERR " Switch failed, errno = %d \n " , - err ) ;
goto out_close ;
}
} else {
* backing_file_out = backing_file ;
err = backing_file_mismatch ( * backing_file_out , size , mtime ) ;
if ( err )
goto out_close ;
}
cow_sizes ( version , size , sectorsize , align , * bitmap_offset_out ,
bitmap_len_out , data_offset_out ) ;
return fd ;
out_close :
os_close_file ( fd ) ;
return err ;
}
static int create_cow_file ( char * cow_file , char * backing_file ,
struct openflags flags ,
int sectorsize , int alignment , int * bitmap_offset_out ,
unsigned long * bitmap_len_out , int * data_offset_out )
{
int err , fd ;
flags . c = 1 ;
fd = open_ubd_file ( cow_file , & flags , 0 , NULL , NULL , NULL , NULL , NULL ) ;
if ( fd < 0 ) {
err = fd ;
printk ( KERN_ERR " Open of COW file '%s' failed, errno = %d \n " ,
cow_file , - err ) ;
goto out ;
}
err = init_cow_file ( fd , cow_file , backing_file , sectorsize , alignment ,
bitmap_offset_out , bitmap_len_out ,
data_offset_out ) ;
if ( ! err )
return fd ;
os_close_file ( fd ) ;
out :
return err ;
}
2006-10-30 22:07:06 -08:00
static void ubd_close_dev ( struct ubd * ubd_dev )
2005-04-16 15:20:36 -07:00
{
2006-10-30 22:07:05 -08:00
os_close_file ( ubd_dev - > fd ) ;
if ( ubd_dev - > cow . file = = NULL )
2005-04-16 15:20:36 -07:00
return ;
2006-10-30 22:07:05 -08:00
os_close_file ( ubd_dev - > cow . fd ) ;
vfree ( ubd_dev - > cow . bitmap ) ;
ubd_dev - > cow . bitmap = NULL ;
2005-04-16 15:20:36 -07:00
}
2006-10-30 22:07:05 -08:00
static int ubd_open_dev ( struct ubd * ubd_dev )
2005-04-16 15:20:36 -07:00
{
struct openflags flags ;
char * * back_ptr ;
int err , create_cow , * create_ptr ;
2006-10-30 22:07:11 -08:00
int fd ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
ubd_dev - > openflags = ubd_dev - > boot_openflags ;
2005-04-16 15:20:36 -07:00
create_cow = 0 ;
2006-10-30 22:07:05 -08:00
create_ptr = ( ubd_dev - > cow . file ! = NULL ) ? & create_cow : NULL ;
back_ptr = ubd_dev - > no_cow ? NULL : & ubd_dev - > cow . file ;
2006-10-30 22:07:11 -08:00
fd = open_ubd_file ( ubd_dev - > file , & ubd_dev - > openflags , ubd_dev - > shared ,
2006-10-30 22:07:05 -08:00
back_ptr , & ubd_dev - > cow . bitmap_offset ,
& ubd_dev - > cow . bitmap_len , & ubd_dev - > cow . data_offset ,
2006-03-27 01:14:37 -08:00
create_ptr ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:11 -08:00
if ( ( fd = = - ENOENT ) & & create_cow ) {
fd = create_cow_file ( ubd_dev - > file , ubd_dev - > cow . file ,
2018-11-14 18:41:06 +00:00
ubd_dev - > openflags , SECTOR_SIZE , PAGE_SIZE ,
2006-10-30 22:07:05 -08:00
& ubd_dev - > cow . bitmap_offset ,
& ubd_dev - > cow . bitmap_len ,
& ubd_dev - > cow . data_offset ) ;
2006-10-30 22:07:11 -08:00
if ( fd > = 0 ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " Creating \" %s \" as COW file for "
2006-10-30 22:07:05 -08:00
" \" %s \" \n " , ubd_dev - > file , ubd_dev - > cow . file ) ;
2005-04-16 15:20:36 -07:00
}
}
2006-10-30 22:07:11 -08:00
if ( fd < 0 ) {
2006-10-30 22:07:05 -08:00
printk ( " Failed to open '%s', errno = %d \n " , ubd_dev - > file ,
2006-10-30 22:07:11 -08:00
- fd ) ;
return fd ;
2005-04-16 15:20:36 -07:00
}
2006-10-30 22:07:11 -08:00
ubd_dev - > fd = fd ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > cow . file ! = NULL ) {
2010-02-26 00:20:38 -05:00
blk_queue_max_hw_sectors ( ubd_dev - > queue , 8 * sizeof ( long ) ) ;
2007-08-22 14:01:53 -07:00
2005-04-16 15:20:36 -07:00
err = - ENOMEM ;
2007-10-16 01:27:19 -07:00
ubd_dev - > cow . bitmap = vmalloc ( ubd_dev - > cow . bitmap_len ) ;
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > cow . bitmap = = NULL ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR " Failed to vmalloc COW bitmap \n " ) ;
goto error ;
}
flush_tlb_kernel_vm ( ) ;
2006-10-30 22:07:05 -08:00
err = read_cow_bitmap ( ubd_dev - > fd , ubd_dev - > cow . bitmap ,
ubd_dev - > cow . bitmap_offset ,
ubd_dev - > cow . bitmap_len ) ;
2005-04-16 15:20:36 -07:00
if ( err < 0 )
goto error ;
2006-10-30 22:07:05 -08:00
flags = ubd_dev - > openflags ;
2005-04-16 15:20:36 -07:00
flags . w = 0 ;
2006-10-30 22:07:05 -08:00
err = open_ubd_file ( ubd_dev - > cow . file , & flags , ubd_dev - > shared , NULL ,
2006-03-27 01:14:37 -08:00
NULL , NULL , NULL , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( err < 0 ) goto error ;
2006-10-30 22:07:05 -08:00
ubd_dev - > cow . fd = err ;
2005-04-16 15:20:36 -07:00
}
2018-11-14 18:41:09 +00:00
if ( ubd_dev - > no_trim = = 0 ) {
ubd_dev - > queue - > limits . discard_granularity = SECTOR_SIZE ;
ubd_dev - > queue - > limits . discard_alignment = SECTOR_SIZE ;
blk_queue_max_discard_sectors ( ubd_dev - > queue , UBD_MAX_REQUEST ) ;
blk_queue_max_write_zeroes_sectors ( ubd_dev - > queue , UBD_MAX_REQUEST ) ;
blk_queue_flag_set ( QUEUE_FLAG_DISCARD , ubd_dev - > queue ) ;
}
2018-11-14 18:41:06 +00:00
blk_queue_flag_set ( QUEUE_FLAG_NONROT , ubd_dev - > queue ) ;
2007-05-06 14:51:41 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
error :
2006-10-30 22:07:05 -08:00
os_close_file ( ubd_dev - > fd ) ;
2007-05-06 14:51:41 -07:00
return err ;
2005-04-16 15:20:36 -07:00
}
2007-05-06 14:51:29 -07:00
static void ubd_device_release ( struct device * dev )
{
2009-05-04 12:40:54 -07:00
struct ubd * ubd_dev = dev_get_drvdata ( dev ) ;
2007-05-06 14:51:29 -07:00
blk_cleanup_queue ( ubd_dev - > queue ) ;
2017-11-26 13:33:11 +01:00
blk_mq_free_tag_set ( & ubd_dev - > tag_set ) ;
2007-05-06 14:51:29 -07:00
* ubd_dev = ( ( struct ubd ) DEFAULT_UBD ) ;
}
2006-10-30 22:07:06 -08:00
static int ubd_disk_register ( int major , u64 size , int unit ,
2007-02-10 01:44:17 -08:00
struct gendisk * * disk_out )
2005-04-16 15:20:36 -07:00
{
2016-06-20 10:44:32 -07:00
struct device * parent = NULL ;
2005-04-16 15:20:36 -07:00
struct gendisk * disk ;
disk = alloc_disk ( 1 < < UBD_SHIFT ) ;
if ( disk = = NULL )
2007-05-06 14:51:41 -07:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
disk - > major = major ;
disk - > first_minor = unit < < UBD_SHIFT ;
disk - > fops = & ubd_blops ;
set_capacity ( disk , size / 512 ) ;
2009-03-31 15:23:39 -07:00
if ( major = = UBD_MAJOR )
2005-04-16 15:20:36 -07:00
sprintf ( disk - > disk_name , " ubd%c " , ' a ' + unit ) ;
2005-06-20 21:15:16 -07:00
else
2005-04-16 15:20:36 -07:00
sprintf ( disk - > disk_name , " ubd_fake%d " , unit ) ;
/* sysfs register (not for ide fake devices) */
2009-03-31 15:23:39 -07:00
if ( major = = UBD_MAJOR ) {
2006-10-30 22:07:05 -08:00
ubd_devs [ unit ] . pdev . id = unit ;
ubd_devs [ unit ] . pdev . name = DRIVER_NAME ;
2007-05-06 14:51:29 -07:00
ubd_devs [ unit ] . pdev . dev . release = ubd_device_release ;
2009-05-04 12:40:54 -07:00
dev_set_drvdata ( & ubd_devs [ unit ] . pdev . dev , & ubd_devs [ unit ] ) ;
2006-10-30 22:07:05 -08:00
platform_device_register ( & ubd_devs [ unit ] . pdev ) ;
2016-06-20 10:44:32 -07:00
parent = & ubd_devs [ unit ] . pdev . dev ;
2005-04-16 15:20:36 -07:00
}
2006-10-30 22:07:05 -08:00
disk - > private_data = & ubd_devs [ unit ] ;
2007-02-10 01:44:16 -08:00
disk - > queue = ubd_devs [ unit ] . queue ;
2018-09-28 08:17:19 +02:00
device_add_disk ( parent , disk , NULL ) ;
2005-04-16 15:20:36 -07:00
* disk_out = disk ;
return 0 ;
}
2018-11-14 18:41:06 +00:00
# define ROUND_BLOCK(n) ((n + (SECTOR_SIZE - 1)) & (-SECTOR_SIZE))
2005-04-16 15:20:36 -07:00
2017-11-26 13:33:11 +01:00
static const struct blk_mq_ops ubd_mq_ops = {
. queue_rq = ubd_queue_rq ,
} ;
2007-02-10 01:43:53 -08:00
static int ubd_add ( int n , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev = & ubd_devs [ n ] ;
2007-02-10 01:43:53 -08:00
int err = 0 ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > file = = NULL )
2005-09-03 15:57:29 -07:00
goto out ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
err = ubd_file_size ( ubd_dev , & ubd_dev - > size ) ;
2007-02-10 01:43:53 -08:00
if ( err < 0 ) {
* error_out = " Couldn't determine size of device's file " ;
2006-09-29 01:58:51 -07:00
goto out ;
2007-02-10 01:43:53 -08:00
}
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
ubd_dev - > size = ROUND_BLOCK ( ubd_dev - > size ) ;
2005-04-16 15:20:36 -07:00
2017-11-26 13:33:11 +01:00
ubd_dev - > tag_set . ops = & ubd_mq_ops ;
ubd_dev - > tag_set . queue_depth = 64 ;
ubd_dev - > tag_set . numa_node = NUMA_NO_NODE ;
ubd_dev - > tag_set . flags = BLK_MQ_F_SHOULD_MERGE ;
ubd_dev - > tag_set . driver_data = ubd_dev ;
ubd_dev - > tag_set . nr_hw_queues = 1 ;
2007-05-06 14:51:36 -07:00
2017-11-26 13:33:11 +01:00
err = blk_mq_alloc_tag_set ( & ubd_dev - > tag_set ) ;
if ( err )
2006-09-29 01:58:51 -07:00
goto out ;
2017-11-26 13:33:11 +01:00
ubd_dev - > queue = blk_mq_init_queue ( & ubd_dev - > tag_set ) ;
if ( IS_ERR ( ubd_dev - > queue ) ) {
err = PTR_ERR ( ubd_dev - > queue ) ;
2019-02-26 15:55:25 +00:00
goto out_cleanup_tags ;
2007-02-10 01:44:16 -08:00
}
2017-11-26 13:33:11 +01:00
2007-02-10 01:44:16 -08:00
ubd_dev - > queue - > queuedata = ubd_dev ;
2016-03-30 10:19:17 -06:00
blk_queue_write_cache ( ubd_dev - > queue , true , false ) ;
2007-02-10 01:44:16 -08:00
2010-02-26 00:20:39 -05:00
blk_queue_max_segments ( ubd_dev - > queue , MAX_SG ) ;
2009-03-31 15:23:39 -07:00
err = ubd_disk_register ( UBD_MAJOR , ubd_dev - > size , n , & ubd_gendisk [ n ] ) ;
2007-02-10 01:44:16 -08:00
if ( err ) {
* error_out = " Failed to register device " ;
2017-11-26 13:33:11 +01:00
goto out_cleanup_tags ;
2007-02-10 01:44:16 -08:00
}
2006-03-27 01:14:37 -08:00
2009-03-31 15:23:39 -07:00
if ( fake_major ! = UBD_MAJOR )
2006-10-30 22:07:06 -08:00
ubd_disk_register ( fake_major , ubd_dev - > size , n ,
2007-02-10 01:44:16 -08:00
& fake_gendisk [ n ] ) ;
2005-04-16 15:20:36 -07:00
2008-02-04 22:31:18 -08:00
/*
* Perhaps this should also be under the " if (fake_major) " above
* using the fake_disk - > disk_name
*/
2005-04-16 15:20:36 -07:00
if ( fake_ide )
make_ide_entries ( ubd_gendisk [ n ] - > disk_name ) ;
2005-09-03 15:57:29 -07:00
err = 0 ;
out :
return err ;
2007-02-10 01:44:16 -08:00
2017-11-26 13:33:11 +01:00
out_cleanup_tags :
blk_mq_free_tag_set ( & ubd_dev - > tag_set ) ;
2019-02-26 15:55:25 +00:00
if ( ! ( IS_ERR ( ubd_dev - > queue ) ) )
blk_cleanup_queue ( ubd_dev - > queue ) ;
2007-02-10 01:44:16 -08:00
goto out ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
static int ubd_config ( char * str , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2006-10-30 22:07:09 -08:00
int n , ret ;
2005-04-16 15:20:36 -07:00
2007-02-10 01:43:53 -08:00
/* This string is possibly broken up and stored, so it's only
* freed if ubd_setup_common fails , or if only general options
* were set .
*/
2006-01-06 00:18:48 -08:00
str = kstrdup ( str , GFP_KERNEL ) ;
2006-10-30 22:07:09 -08:00
if ( str = = NULL ) {
2007-02-10 01:43:53 -08:00
* error_out = " Failed to allocate memory " ;
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
ret = ubd_setup_common ( str , & n , error_out ) ;
if ( ret )
2006-10-30 22:07:09 -08:00
goto err_free ;
2007-02-10 01:43:53 -08:00
2006-10-30 22:07:09 -08:00
if ( n = = - 1 ) {
ret = 0 ;
2006-10-30 22:07:12 -08:00
goto err_free ;
2005-04-16 15:20:36 -07:00
}
2007-05-06 14:51:41 -07:00
mutex_lock ( & ubd_lock ) ;
2007-02-10 01:43:53 -08:00
ret = ubd_add ( n , error_out ) ;
2006-10-30 22:07:09 -08:00
if ( ret )
2006-10-30 22:07:05 -08:00
ubd_devs [ n ] . file = NULL ;
2007-05-06 14:51:41 -07:00
mutex_unlock ( & ubd_lock ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:09 -08:00
out :
2007-05-06 14:51:41 -07:00
return ret ;
2006-10-30 22:07:09 -08:00
err_free :
kfree ( str ) ;
goto out ;
2005-04-16 15:20:36 -07:00
}
static int ubd_get_config ( char * name , char * str , int size , char * * error_out )
{
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev ;
2005-04-16 15:20:36 -07:00
int n , len = 0 ;
n = parse_unit ( & name ) ;
if ( ( n > = MAX_DEV ) | | ( n < 0 ) ) {
* error_out = " ubd_get_config : device number out of range " ;
2007-05-06 14:51:41 -07:00
return - 1 ;
2005-04-16 15:20:36 -07:00
}
2006-10-30 22:07:05 -08:00
ubd_dev = & ubd_devs [ n ] ;
2006-10-30 22:07:07 -08:00
mutex_lock ( & ubd_lock ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > file = = NULL ) {
2005-04-16 15:20:36 -07:00
CONFIG_CHUNK ( str , size , len , " " , 1 ) ;
goto out ;
}
2006-10-30 22:07:05 -08:00
CONFIG_CHUNK ( str , size , len , ubd_dev - > file , 0 ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > cow . file ! = NULL ) {
2005-04-16 15:20:36 -07:00
CONFIG_CHUNK ( str , size , len , " , " , 0 ) ;
2006-10-30 22:07:05 -08:00
CONFIG_CHUNK ( str , size , len , ubd_dev - > cow . file , 1 ) ;
2005-04-16 15:20:36 -07:00
}
else CONFIG_CHUNK ( str , size , len , " " , 1 ) ;
out :
2006-10-30 22:07:07 -08:00
mutex_unlock ( & ubd_lock ) ;
2007-05-06 14:51:41 -07:00
return len ;
2005-04-16 15:20:36 -07:00
}
2005-06-25 14:55:25 -07:00
static int ubd_id ( char * * str , int * start_out , int * end_out )
{
2007-05-06 14:51:41 -07:00
int n ;
2005-06-25 14:55:25 -07:00
n = parse_unit ( str ) ;
2007-05-06 14:51:41 -07:00
* start_out = 0 ;
* end_out = MAX_DEV - 1 ;
return n ;
2005-06-25 14:55:25 -07:00
}
2007-02-10 01:43:53 -08:00
static int ubd_remove ( int n , char * * error_out )
2005-04-16 15:20:36 -07:00
{
2007-05-06 14:51:29 -07:00
struct gendisk * disk = ubd_gendisk [ n ] ;
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev ;
2005-06-25 14:55:25 -07:00
int err = - ENODEV ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:07 -08:00
mutex_lock ( & ubd_lock ) ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
ubd_dev = & ubd_devs [ n ] ;
2005-04-16 15:20:36 -07:00
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > file = = NULL )
2005-06-25 14:55:25 -07:00
goto out ;
2005-04-16 15:20:36 -07:00
2005-06-25 14:55:25 -07:00
/* you cannot remove a open disk */
err = - EBUSY ;
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > count > 0 )
2005-04-16 15:20:36 -07:00
goto out ;
2007-05-06 14:51:41 -07:00
ubd_gendisk [ n ] = NULL ;
2007-05-06 14:51:01 -07:00
if ( disk ! = NULL ) {
del_gendisk ( disk ) ;
put_disk ( disk ) ;
}
2005-04-16 15:20:36 -07:00
if ( fake_gendisk [ n ] ! = NULL ) {
del_gendisk ( fake_gendisk [ n ] ) ;
put_disk ( fake_gendisk [ n ] ) ;
fake_gendisk [ n ] = NULL ;
}
err = 0 ;
2007-05-06 14:51:29 -07:00
platform_device_unregister ( & ubd_dev - > pdev ) ;
2005-06-25 14:55:25 -07:00
out :
2006-10-30 22:07:07 -08:00
mutex_unlock ( & ubd_lock ) ;
2005-06-25 14:55:25 -07:00
return err ;
2005-04-16 15:20:36 -07:00
}
2007-02-10 01:43:53 -08:00
/* All these are called by mconsole in process context and without
2007-02-10 01:44:17 -08:00
* ubd - specific locks . The structure itself is const except for . list .
2007-02-10 01:43:53 -08:00
*/
2005-04-16 15:20:36 -07:00
static struct mc_device ubd_mc = {
2007-02-10 01:44:01 -08:00
. list = LIST_HEAD_INIT ( ubd_mc . list ) ,
2005-04-16 15:20:36 -07:00
. name = " ubd " ,
. config = ubd_config ,
2007-05-06 14:51:41 -07:00
. get_config = ubd_get_config ,
2005-06-25 14:55:25 -07:00
. id = ubd_id ,
2005-04-16 15:20:36 -07:00
. remove = ubd_remove ,
} ;
2006-10-30 22:07:12 -08:00
static int __init ubd_mc_init ( void )
2005-04-16 15:20:36 -07:00
{
mconsole_register_dev ( & ubd_mc ) ;
return 0 ;
}
__initcall ( ubd_mc_init ) ;
2006-10-30 22:07:12 -08:00
static int __init ubd0_init ( void )
{
struct ubd * ubd_dev = & ubd_devs [ 0 ] ;
2007-02-10 01:44:17 -08:00
mutex_lock ( & ubd_lock ) ;
2006-10-30 22:07:12 -08:00
if ( ubd_dev - > file = = NULL )
ubd_dev - > file = " root_fs " ;
2007-02-10 01:44:17 -08:00
mutex_unlock ( & ubd_lock ) ;
2007-05-06 14:51:41 -07:00
return 0 ;
2006-10-30 22:07:12 -08:00
}
__initcall ( ubd0_init ) ;
2007-02-10 01:44:17 -08:00
/* Used in ubd_init, which is an initcall */
2005-11-09 22:32:44 +00:00
static struct platform_driver ubd_driver = {
. driver = {
. name = DRIVER_NAME ,
} ,
2005-04-16 15:20:36 -07:00
} ;
2006-10-30 22:07:12 -08:00
static int __init ubd_init ( void )
2005-04-16 15:20:36 -07:00
{
2007-02-10 01:43:53 -08:00
char * error ;
int i , err ;
2005-04-16 15:20:36 -07:00
2009-03-31 15:23:39 -07:00
if ( register_blkdev ( UBD_MAJOR , " ubd " ) )
2005-04-16 15:20:36 -07:00
return - 1 ;
2009-03-31 15:23:39 -07:00
if ( fake_major ! = UBD_MAJOR ) {
2005-04-16 15:20:36 -07:00
char name [ sizeof ( " ubd_nnn \0 " ) ] ;
snprintf ( name , sizeof ( name ) , " ubd_%d " , fake_major ) ;
if ( register_blkdev ( fake_major , " ubd " ) )
return - 1 ;
}
2016-11-09 20:43:25 +00:00
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 13:55:00 -07:00
irq_req_buffer = kmalloc_array ( UBD_REQ_BUFFER_SIZE ,
sizeof ( struct io_thread_req * ) ,
GFP_KERNEL
2016-11-09 20:43:25 +00:00
) ;
irq_remainder = 0 ;
if ( irq_req_buffer = = NULL ) {
printk ( KERN_ERR " Failed to initialize ubd buffering \n " ) ;
return - 1 ;
}
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 13:55:00 -07:00
io_req_buffer = kmalloc_array ( UBD_REQ_BUFFER_SIZE ,
sizeof ( struct io_thread_req * ) ,
GFP_KERNEL
2016-11-09 20:43:25 +00:00
) ;
io_remainder = 0 ;
if ( io_req_buffer = = NULL ) {
printk ( KERN_ERR " Failed to initialize ubd buffering \n " ) ;
return - 1 ;
}
2005-11-09 22:32:44 +00:00
platform_driver_register ( & ubd_driver ) ;
2007-05-06 14:51:41 -07:00
mutex_lock ( & ubd_lock ) ;
2007-02-10 01:43:53 -08:00
for ( i = 0 ; i < MAX_DEV ; i + + ) {
err = ubd_add ( i , & error ) ;
if ( err )
printk ( KERN_ERR " Failed to initialize ubd device %d : "
" %s \n " , i , error ) ;
}
2007-05-06 14:51:41 -07:00
mutex_unlock ( & ubd_lock ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
late_initcall ( ubd_init ) ;
2006-10-30 22:07:12 -08:00
static int __init ubd_driver_init ( void ) {
2005-10-10 23:10:32 -04:00
unsigned long stack ;
int err ;
/* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
if ( global_openflags . s ) {
printk ( KERN_INFO " ubd: Synchronous mode \n " ) ;
/* Letting ubd=sync be like using ubd#s= instead of ubd#= is
* enough . So use anyway the io thread . */
}
stack = alloc_stack ( 0 , 0 ) ;
2006-03-27 01:14:37 -08:00
io_pid = start_io_thread ( stack + PAGE_SIZE - sizeof ( void * ) ,
2005-10-10 23:10:32 -04:00
& thread_fd ) ;
if ( io_pid < 0 ) {
2006-03-27 01:14:37 -08:00
printk ( KERN_ERR
2005-10-10 23:10:32 -04:00
" ubd : Failed to start I/O thread (errno = %d) - "
" falling back to synchronous I/O \n " , - io_pid ) ;
io_pid = - 1 ;
2007-05-06 14:51:41 -07:00
return 0 ;
2005-10-10 23:10:32 -04:00
}
2006-03-27 01:14:37 -08:00
err = um_request_irq ( UBD_IRQ , thread_fd , IRQ_READ , ubd_intr ,
2011-09-22 16:58:46 +08:00
0 , " ubd " , ubd_devs ) ;
2005-10-10 23:10:32 -04:00
if ( err ! = 0 )
printk ( KERN_ERR " um_request_irq failed - errno = %d \n " , - err ) ;
2006-03-31 02:30:10 -08:00
return 0 ;
2005-10-10 23:10:32 -04:00
}
device_initcall ( ubd_driver_init ) ;
2008-03-02 09:16:26 -05:00
static int ubd_open ( struct block_device * bdev , fmode_t mode )
2005-04-16 15:20:36 -07:00
{
2008-03-02 09:16:26 -05:00
struct gendisk * disk = bdev - > bd_disk ;
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev = disk - > private_data ;
2005-04-16 15:20:36 -07:00
int err = 0 ;
2010-09-11 18:38:03 +02:00
mutex_lock ( & ubd_mutex ) ;
2006-10-30 22:07:05 -08:00
if ( ubd_dev - > count = = 0 ) {
err = ubd_open_dev ( ubd_dev ) ;
2005-04-16 15:20:36 -07:00
if ( err ) {
printk ( KERN_ERR " %s: Can't open \" %s \" : errno = %d \n " ,
2006-10-30 22:07:05 -08:00
disk - > disk_name , ubd_dev - > file , - err ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
}
2006-10-30 22:07:05 -08:00
ubd_dev - > count + + ;
set_disk_ro ( disk , ! ubd_dev - > openflags . w ) ;
2005-05-01 08:58:57 -07:00
/* This should no more be needed. And it didn't work anyway to exclude
* read - write remounting of filesystems . */
2008-03-02 09:16:26 -05:00
/*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
2006-10-30 22:07:06 -08:00
if ( - - ubd_dev - > count = = 0 ) ubd_close_dev ( ubd_dev ) ;
2005-04-16 15:20:36 -07:00
err = - EROFS ;
2005-05-01 08:58:57 -07:00
} */
2010-08-07 18:25:34 +02:00
out :
2010-09-11 18:38:03 +02:00
mutex_unlock ( & ubd_mutex ) ;
2007-05-06 14:51:41 -07:00
return err ;
2005-04-16 15:20:36 -07:00
}
2013-05-05 21:52:57 -04:00
static void ubd_release ( struct gendisk * disk , fmode_t mode )
2005-04-16 15:20:36 -07:00
{
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev = disk - > private_data ;
2005-04-16 15:20:36 -07:00
2010-09-11 18:38:03 +02:00
mutex_lock ( & ubd_mutex ) ;
2006-10-30 22:07:05 -08:00
if ( - - ubd_dev - > count = = 0 )
2006-10-30 22:07:06 -08:00
ubd_close_dev ( ubd_dev ) ;
2010-09-11 18:38:03 +02:00
mutex_unlock ( & ubd_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-10-10 23:10:32 -04:00
static void cowify_bitmap ( __u64 io_offset , int length , unsigned long * cow_mask ,
__u64 * cow_offset , unsigned long * bitmap ,
__u64 bitmap_offset , unsigned long * bitmap_words ,
__u64 bitmap_len )
2005-04-16 15:20:36 -07:00
{
2018-11-14 18:41:06 +00:00
__u64 sector = io_offset > > SECTOR_SHIFT ;
2005-10-10 23:10:32 -04:00
int i , update_bitmap = 0 ;
2018-11-14 18:41:06 +00:00
for ( i = 0 ; i < length > > SECTOR_SHIFT ; i + + ) {
2005-10-10 23:10:32 -04:00
if ( cow_mask ! = NULL )
ubd_set_bit ( i , ( unsigned char * ) cow_mask ) ;
if ( ubd_test_bit ( sector + i , ( unsigned char * ) bitmap ) )
continue ;
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
update_bitmap = 1 ;
ubd_set_bit ( sector + i , ( unsigned char * ) bitmap ) ;
}
if ( ! update_bitmap )
return ;
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
* cow_offset = sector / ( sizeof ( unsigned long ) * 8 ) ;
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
/* This takes care of the case where we're exactly at the end of the
* device , and * cow_offset + 1 is off the end . So , just back it up
* by one word . Thanks to Lynn Kerby for the fix and James McMechan
* for the original diagnosis .
*/
2008-05-12 14:01:56 -07:00
if ( * cow_offset = = ( DIV_ROUND_UP ( bitmap_len ,
sizeof ( unsigned long ) ) - 1 ) )
2005-10-10 23:10:32 -04:00
( * cow_offset ) - - ;
bitmap_words [ 0 ] = bitmap [ * cow_offset ] ;
bitmap_words [ 1 ] = bitmap [ * cow_offset + 1 ] ;
* cow_offset * = sizeof ( unsigned long ) ;
* cow_offset + = bitmap_offset ;
}
static void cowify_req ( struct io_thread_req * req , unsigned long * bitmap ,
__u64 bitmap_offset , __u64 bitmap_len )
{
2018-11-14 18:41:06 +00:00
__u64 sector = req - > offset > > SECTOR_SHIFT ;
2005-10-10 23:10:32 -04:00
int i ;
2018-11-14 18:41:06 +00:00
if ( req - > length > ( sizeof ( req - > sector_mask ) * 8 ) < < SECTOR_SHIFT )
2005-10-10 23:10:32 -04:00
panic ( " Operation too long " ) ;
2018-11-14 18:41:06 +00:00
if ( req_op ( req - > req ) = = REQ_OP_READ ) {
for ( i = 0 ; i < req - > length > > SECTOR_SHIFT ; i + + ) {
2005-10-10 23:10:32 -04:00
if ( ubd_test_bit ( sector + i , ( unsigned char * ) bitmap ) )
2006-03-27 01:14:37 -08:00
ubd_set_bit ( i , ( unsigned char * )
2005-10-10 23:10:32 -04:00
& req - > sector_mask ) ;
2007-05-06 14:51:41 -07:00
}
2005-10-10 23:10:32 -04:00
}
else cowify_bitmap ( req - > offset , req - > length , & req - > sector_mask ,
& req - > cow_offset , bitmap , bitmap_offset ,
req - > bitmap_words , bitmap_len ) ;
2005-04-16 15:20:36 -07:00
}
2018-10-18 22:55:03 +02:00
static int ubd_queue_one_vec ( struct blk_mq_hw_ctx * hctx , struct request * req ,
u64 off , struct bio_vec * bvec )
2005-04-16 15:20:36 -07:00
{
2018-10-18 22:55:03 +02:00
struct ubd * dev = hctx - > queue - > queuedata ;
struct io_thread_req * io_req ;
int ret ;
2005-04-16 15:20:36 -07:00
2018-10-18 22:55:03 +02:00
io_req = kmalloc ( sizeof ( struct io_thread_req ) , GFP_ATOMIC ) ;
if ( ! io_req )
return - ENOMEM ;
2013-08-18 13:30:06 +02:00
io_req - > req = req ;
2018-10-18 22:55:03 +02:00
if ( dev - > cow . file )
io_req - > fds [ 0 ] = dev - > cow . fd ;
else
io_req - > fds [ 0 ] = dev - > fd ;
2018-11-08 13:07:23 +00:00
io_req - > error = 0 ;
2017-11-26 13:33:11 +01:00
2018-11-14 18:41:07 +00:00
if ( bvec ! = NULL ) {
2018-10-18 22:55:03 +02:00
io_req - > buffer = page_address ( bvec - > bv_page ) + bvec - > bv_offset ;
2018-11-14 18:41:07 +00:00
io_req - > length = bvec - > bv_len ;
} else {
io_req - > buffer = NULL ;
io_req - > length = blk_rq_bytes ( req ) ;
2018-10-18 22:55:03 +02:00
}
2013-08-18 13:30:07 +02:00
2018-11-14 18:41:07 +00:00
io_req - > sectorsize = SECTOR_SIZE ;
io_req - > fds [ 1 ] = dev - > fd ;
io_req - > cow_offset = - 1 ;
io_req - > offset = off ;
io_req - > sector_mask = 0 ;
io_req - > offsets [ 0 ] = 0 ;
io_req - > offsets [ 1 ] = dev - > cow . data_offset ;
if ( dev - > cow . file )
cowify_req ( io_req , dev - > cow . bitmap ,
dev - > cow . bitmap_offset , dev - > cow . bitmap_len ) ;
2018-10-18 22:55:03 +02:00
ret = os_write_file ( thread_fd , & io_req , sizeof ( io_req ) ) ;
if ( ret ! = sizeof ( io_req ) ) {
if ( ret ! = - EAGAIN )
pr_err ( " write to io thread failed: %d \n " , - ret ) ;
2013-08-18 13:30:07 +02:00
kfree ( io_req ) ;
}
2018-10-18 22:55:03 +02:00
return ret ;
2013-08-18 13:30:07 +02:00
}
2018-11-14 18:41:07 +00:00
static int queue_rw_req ( struct blk_mq_hw_ctx * hctx , struct request * req )
{
struct req_iterator iter ;
struct bio_vec bvec ;
int ret ;
u64 off = ( u64 ) blk_rq_pos ( req ) < < SECTOR_SHIFT ;
rq_for_each_segment ( bvec , req , iter ) {
ret = ubd_queue_one_vec ( hctx , req , off , & bvec ) ;
if ( ret < 0 )
return ret ;
off + = bvec . bv_len ;
}
return 0 ;
}
2017-11-26 13:33:11 +01:00
static blk_status_t ubd_queue_rq ( struct blk_mq_hw_ctx * hctx ,
const struct blk_mq_queue_data * bd )
2005-04-16 15:20:36 -07:00
{
2018-11-07 14:34:05 -07:00
struct ubd * ubd_dev = hctx - > queue - > queuedata ;
2017-11-26 13:33:11 +01:00
struct request * req = bd - > rq ;
2018-11-14 18:41:07 +00:00
int ret = 0 , res = BLK_STS_OK ;
2007-05-06 14:51:36 -07:00
2017-11-26 13:33:11 +01:00
blk_mq_start_request ( req ) ;
2018-11-07 14:34:05 -07:00
spin_lock_irq ( & ubd_dev - > lock ) ;
2018-11-14 18:41:07 +00:00
switch ( req_op ( req ) ) {
/* operations with no lentgth/offset arguments */
case REQ_OP_FLUSH :
2018-10-18 22:55:03 +02:00
ret = ubd_queue_one_vec ( hctx , req , 0 , NULL ) ;
2018-11-14 18:41:07 +00:00
break ;
case REQ_OP_READ :
case REQ_OP_WRITE :
ret = queue_rw_req ( hctx , req ) ;
break ;
2018-11-14 18:41:09 +00:00
case REQ_OP_DISCARD :
case REQ_OP_WRITE_ZEROES :
ret = ubd_queue_one_vec ( hctx , req , ( u64 ) blk_rq_pos ( req ) < < 9 , NULL ) ;
break ;
2018-11-14 18:41:07 +00:00
default :
WARN_ON_ONCE ( 1 ) ;
res = BLK_STS_NOTSUPP ;
2017-11-26 13:33:11 +01:00
}
2018-11-14 18:41:07 +00:00
2018-11-07 14:34:05 -07:00
spin_unlock_irq ( & ubd_dev - > lock ) ;
2019-10-29 09:13:34 +00:00
if ( ret < 0 ) {
if ( ret = = - ENOMEM )
res = BLK_STS_RESOURCE ;
else
res = BLK_STS_DEV_RESOURCE ;
}
2018-11-07 14:34:05 -07:00
2018-11-14 18:41:07 +00:00
return res ;
2005-04-16 15:20:36 -07:00
}
2006-01-08 01:02:50 -08:00
static int ubd_getgeo ( struct block_device * bdev , struct hd_geometry * geo )
{
2006-10-30 22:07:05 -08:00
struct ubd * ubd_dev = bdev - > bd_disk - > private_data ;
2006-01-08 01:02:50 -08:00
geo - > heads = 128 ;
geo - > sectors = 32 ;
2006-10-30 22:07:05 -08:00
geo - > cylinders = ubd_dev - > size / ( 128 * 32 * 512 ) ;
2006-01-08 01:02:50 -08:00
return 0 ;
}
2008-03-02 09:16:26 -05:00
static int ubd_ioctl ( struct block_device * bdev , fmode_t mode ,
2005-04-16 15:20:36 -07:00
unsigned int cmd , unsigned long arg )
{
2008-03-02 09:16:26 -05:00
struct ubd * ubd_dev = bdev - > bd_disk - > private_data ;
2009-04-01 21:42:21 +02:00
u16 ubd_id [ ATA_ID_WORDS ] ;
2005-04-16 15:20:36 -07:00
switch ( cmd ) {
struct cdrom_volctrl volume ;
case HDIO_GET_IDENTITY :
2009-04-01 21:42:21 +02:00
memset ( & ubd_id , 0 , ATA_ID_WORDS * 2 ) ;
ubd_id [ ATA_ID_CYLS ] = ubd_dev - > size / ( 128 * 32 * 512 ) ;
ubd_id [ ATA_ID_HEADS ] = 128 ;
ubd_id [ ATA_ID_SECTORS ] = 32 ;
2005-04-16 15:20:36 -07:00
if ( copy_to_user ( ( char __user * ) arg , ( char * ) & ubd_id ,
sizeof ( ubd_id ) ) )
2007-05-06 14:51:41 -07:00
return - EFAULT ;
return 0 ;
2007-02-10 01:44:17 -08:00
2005-04-16 15:20:36 -07:00
case CDROMVOLREAD :
if ( copy_from_user ( & volume , ( char __user * ) arg , sizeof ( volume ) ) )
2007-05-06 14:51:41 -07:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
volume . channel0 = 255 ;
volume . channel1 = 255 ;
volume . channel2 = 255 ;
volume . channel3 = 255 ;
if ( copy_to_user ( ( char __user * ) arg , & volume , sizeof ( volume ) ) )
2007-05-06 14:51:41 -07:00
return - EFAULT ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-05-06 14:51:41 -07:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
2018-11-14 18:41:06 +00:00
static int map_error ( int error_code )
{
switch ( error_code ) {
case 0 :
return BLK_STS_OK ;
case ENOSYS :
case EOPNOTSUPP :
return BLK_STS_NOTSUPP ;
case ENOSPC :
return BLK_STS_NOSPC ;
}
return BLK_STS_IOERR ;
}
2018-11-14 18:41:08 +00:00
/*
* Everything from here onwards * IS NOT PART OF THE KERNEL *
*
* The following functions are part of UML hypervisor code .
* All functions from here onwards are executed as a helper
* thread and are not allowed to execute any kernel functions .
*
* Any communication must occur strictly via shared memory and IPC .
*
* Do not add printks , locks , kernel memory operations , etc - it
* will result in unpredictable behaviour and / or crashes .
*/
2005-10-10 23:10:32 -04:00
static int update_bitmap ( struct io_thread_req * req )
2005-04-16 15:20:36 -07:00
{
2005-10-10 23:10:32 -04:00
int n ;
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
if ( req - > cow_offset = = - 1 )
2018-11-14 18:41:06 +00:00
return map_error ( 0 ) ;
2005-04-16 15:20:36 -07:00
2015-12-21 18:54:00 +00:00
n = os_pwrite_file ( req - > fds [ 1 ] , & req - > bitmap_words ,
sizeof ( req - > bitmap_words ) , req - > cow_offset ) ;
2018-11-14 18:41:09 +00:00
if ( n ! = sizeof ( req - > bitmap_words ) )
2018-11-14 18:41:06 +00:00
return map_error ( - n ) ;
2005-04-16 15:20:36 -07:00
2018-11-14 18:41:06 +00:00
return map_error ( 0 ) ;
2005-10-10 23:10:32 -04:00
}
2005-04-16 15:20:36 -07:00
2008-04-28 02:13:58 -07:00
static void do_io ( struct io_thread_req * req )
2005-10-10 23:10:32 -04:00
{
2018-11-14 18:41:09 +00:00
char * buf = NULL ;
2005-10-10 23:10:32 -04:00
unsigned long len ;
int n , nsectors , start , end , bit ;
__u64 off ;
2018-11-14 18:41:09 +00:00
/* FLUSH is really a special case, we cannot "case" it with others */
2018-11-14 18:41:06 +00:00
if ( req_op ( req - > req ) = = REQ_OP_FLUSH ) {
2013-08-18 13:30:06 +02:00
/* fds[0] is always either the rw image or our cow file */
2018-11-14 18:41:08 +00:00
req - > error = map_error ( - os_sync_file ( req - > fds [ 0 ] ) ) ;
2013-08-18 13:30:06 +02:00
return ;
}
2005-10-10 23:10:32 -04:00
nsectors = req - > length / req - > sectorsize ;
start = 0 ;
do {
bit = ubd_test_bit ( start , ( unsigned char * ) & req - > sector_mask ) ;
end = start ;
while ( ( end < nsectors ) & &
( ubd_test_bit ( end , ( unsigned char * )
& req - > sector_mask ) = = bit ) )
end + + ;
off = req - > offset + req - > offsets [ bit ] +
start * req - > sectorsize ;
len = ( end - start ) * req - > sectorsize ;
2018-11-14 18:41:09 +00:00
if ( req - > buffer ! = NULL )
buf = & req - > buffer [ start * req - > sectorsize ] ;
2005-10-10 23:10:32 -04:00
2018-11-14 18:41:09 +00:00
switch ( req_op ( req - > req ) ) {
case REQ_OP_READ :
2005-10-10 23:10:32 -04:00
n = 0 ;
do {
buf = & buf [ n ] ;
len - = n ;
2015-12-21 18:54:00 +00:00
n = os_pread_file ( req - > fds [ bit ] , buf , len , off ) ;
2018-11-14 18:41:09 +00:00
if ( n < 0 ) {
2018-11-14 18:41:06 +00:00
req - > error = map_error ( - n ) ;
2005-10-10 23:10:32 -04:00
return ;
}
} while ( ( n < len ) & & ( n ! = 0 ) ) ;
if ( n < len ) memset ( & buf [ n ] , 0 , len - n ) ;
2018-11-14 18:41:09 +00:00
break ;
case REQ_OP_WRITE :
2015-12-21 18:54:00 +00:00
n = os_pwrite_file ( req - > fds [ bit ] , buf , len , off ) ;
2005-10-10 23:10:32 -04:00
if ( n ! = len ) {
2018-11-14 18:41:06 +00:00
req - > error = map_error ( - n ) ;
2005-10-10 23:10:32 -04:00
return ;
}
2018-11-14 18:41:09 +00:00
break ;
case REQ_OP_DISCARD :
case REQ_OP_WRITE_ZEROES :
n = os_falloc_punch ( req - > fds [ bit ] , off , len ) ;
if ( n ) {
req - > error = map_error ( - n ) ;
return ;
}
break ;
default :
WARN_ON_ONCE ( 1 ) ;
req - > error = BLK_STS_NOTSUPP ;
return ;
2005-10-10 23:10:32 -04:00
}
start = end ;
} while ( start < nsectors ) ;
2005-04-16 15:20:36 -07:00
2005-10-10 23:10:32 -04:00
req - > error = update_bitmap ( req ) ;
2005-04-16 15:20:36 -07:00
}
2005-10-10 23:10:32 -04:00
/* Changed in start_io_thread, which is serialized by being called only
* from ubd_init , which is an initcall .
*/
int kernel_fd = - 1 ;
2006-10-30 22:07:12 -08:00
/* Only changed by the io thread. XXX: currently unused. */
static int io_count = 0 ;
2005-10-10 23:10:32 -04:00
int io_thread ( void * arg )
{
2016-11-09 20:43:25 +00:00
int n , count , written , res ;
2005-10-10 23:10:32 -04:00
2013-08-18 13:30:08 +02:00
os_fix_helper_signals ( ) ;
2005-10-10 23:10:32 -04:00
while ( 1 ) {
2016-11-09 20:43:25 +00:00
n = bulk_req_safe_read (
kernel_fd ,
io_req_buffer ,
& io_remainder ,
& io_remainder_size ,
UBD_REQ_BUFFER_SIZE
) ;
2020-03-16 20:45:07 -04:00
if ( n < = 0 ) {
if ( n = = - EAGAIN )
2016-11-09 20:43:25 +00:00
ubd_read_poll ( - 1 ) ;
2020-03-16 20:45:07 -04:00
continue ;
2005-10-10 23:10:32 -04:00
}
2016-11-09 20:43:25 +00:00
for ( count = 0 ; count < n / sizeof ( struct io_thread_req * ) ; count + + ) {
io_count + + ;
do_io ( ( * io_req_buffer ) [ count ] ) ;
}
written = 0 ;
do {
2020-03-16 20:45:06 -04:00
res = os_write_file ( kernel_fd ,
( ( char * ) io_req_buffer ) + written ,
n - written ) ;
2017-11-20 21:17:58 +00:00
if ( res > = 0 ) {
2016-11-09 20:43:25 +00:00
written + = res ;
}
if ( written < n ) {
ubd_write_poll ( - 1 ) ;
}
} while ( written < n ) ;
2005-10-10 23:10:32 -04:00
}
2006-01-06 00:18:49 -08:00
return 0 ;
}