2001-10-03 16:41:29 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2012-02-08 15:15:38 +04:00
* Copyright ( C ) 2004 - 2012 Red Hat , Inc . All rights reserved .
2001-10-03 16:41:29 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-10-03 16:41:29 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2003-04-15 17:24:42 +04:00
# include "device.h"
2002-11-18 17:01:16 +03:00
# include "metadata.h"
2003-07-05 02:34:56 +04:00
# include "lvmcache.h"
# include "memlock.h"
2003-11-21 22:54:40 +03:00
# include "locking.h"
2001-10-04 14:13:07 +04:00
2002-12-20 02:25:55 +03:00
# include <limits.h>
2001-10-04 14:13:07 +04:00
# include <sys/stat.h>
2002-07-22 12:10:54 +04:00
# include <fcntl.h>
2002-08-14 18:58:00 +04:00
# include <unistd.h>
2001-10-04 14:13:07 +04:00
# include <sys/ioctl.h>
2003-04-15 17:24:42 +04:00
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2003-04-15 17:24:42 +04:00
# define u64 uint64_t /* Missing without __KERNEL__ */
2003-07-05 02:34:56 +04:00
# undef WNOHANG /* Avoid redefinition */
# undef WUNTRACED /* Avoid redefinition */
2003-04-15 17:24:42 +04:00
# include <linux / fs.h> /* For block ioctl definitions */
# define BLKSIZE_SHIFT SECTOR_SHIFT
2004-01-27 23:53:57 +03:00
# ifndef BLKGETSIZE64 /* fs.h out-of-date */
# define BLKGETSIZE64 _IOR(0x12, 114, size_t)
# endif /* BLKGETSIZE64 */
2011-04-13 01:59:01 +04:00
# ifndef BLKDISCARD
# define BLKDISCARD _IO(0x12,119)
# endif
2003-07-05 02:34:56 +04:00
# else
# include <sys / disk.h>
# define BLKBSZGET DKIOCGETBLOCKSIZE
# define BLKSSZGET DKIOCGETBLOCKSIZE
# define BLKGETSIZE64 DKIOCGETBLOCKCOUNT
# define BLKFLSBUF DKIOCSYNCHRONIZECACHE
# define BLKSIZE_SHIFT 0
2003-11-06 20:14:06 +03:00
# endif
# ifdef O_DIRECT_SUPPORT
2003-07-05 02:34:56 +04:00
# ifndef O_DIRECT
2003-11-06 20:14:06 +03:00
# error O_DIRECT support configured but O_DIRECT definition not found in headers
2003-07-05 02:34:56 +04:00
# endif
2003-04-15 17:24:42 +04:00
# endif
2001-11-13 21:52:52 +03:00
2018-01-10 16:19:12 +03:00
/*
* Always read at least 8 k from disk .
* This seems to be a good compromise for the existing LVM2 metadata layout .
*/
# define MIN_READ_SIZE (8 * 1024)
2008-11-04 01:14:30 +03:00
static DM_LIST_INIT ( _open_devices ) ;
2016-01-15 18:41:27 +03:00
static unsigned _dev_size_seqno = 1 ;
2003-07-05 02:34:56 +04:00
2017-12-05 02:18:56 +03:00
static const char * _reasons [ ] = {
" dev signatures " ,
" PV labels " ,
" VG metadata header " ,
" VG metadata content " ,
2017-12-07 06:34:59 +03:00
" extra VG metadata header " ,
" extra VG metadata content " ,
2017-12-05 02:18:56 +03:00
" LVM1 metadata " ,
" pool metadata " ,
" LV content " ,
" logging " ,
} ;
static const char * _reason_text ( dev_io_reason_t reason )
{
return _reasons [ ( unsigned ) reason ] ;
}
2018-01-10 05:09:06 +03:00
/*
* Release the memory holding the last data we read
*/
static void _release_devbuf ( struct device_buffer * devbuf )
{
dm_free ( devbuf - > malloc_address ) ;
devbuf - > malloc_address = NULL ;
}
void devbufs_release ( struct device * dev )
{
2018-01-10 15:03:31 +03:00
if ( ( dev - > flags & DEV_REGULAR ) )
return ;
2018-01-10 05:09:06 +03:00
_release_devbuf ( & dev - > last_devbuf ) ;
_release_devbuf ( & dev - > last_extra_devbuf ) ;
}
2003-07-05 02:34:56 +04:00
/*-----------------------------------------------------------------
* The standard io loop that keeps submitting an io until it ' s
* all gone .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2018-01-10 05:09:06 +03:00
static int _io_sync ( struct device_buffer * devbuf )
2003-07-05 02:34:56 +04:00
{
2018-01-10 05:09:06 +03:00
struct device_area * where = & devbuf - > where ;
2003-07-05 02:34:56 +04:00
int fd = dev_fd ( where - > dev ) ;
2018-01-10 05:09:06 +03:00
char * buffer = devbuf - > buf ;
2003-07-05 02:34:56 +04:00
ssize_t n = 0 ;
size_t total = 0 ;
2013-05-29 14:38:09 +04:00
if ( lseek ( fd , ( off_t ) where - > start , SEEK_SET ) = = ( off_t ) - 1 ) {
2004-12-10 19:01:35 +03:00
log_error ( " %s: lseek % " PRIu64 " failed: %s " ,
dev_name ( where - > dev ) , ( uint64_t ) where - > start ,
strerror ( errno ) ) ;
2003-07-05 02:34:56 +04:00
return 0 ;
}
while ( total < ( size_t ) where - > size ) {
do
2018-01-10 05:09:06 +03:00
n = devbuf - > write ?
2003-07-05 02:34:56 +04:00
write ( fd , buffer , ( size_t ) where - > size - total ) :
read ( fd , buffer , ( size_t ) where - > size - total ) ;
while ( ( n < 0 ) & & ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) ) ) ;
2004-12-10 19:01:35 +03:00
if ( n < 0 )
2010-05-06 02:37:52 +04:00
log_error_once ( " %s: %s failed after % " PRIu64 " of % " PRIu64
" at % " PRIu64 " : %s " , dev_name ( where - > dev ) ,
2018-01-10 05:09:06 +03:00
devbuf - > write ? " write " : " read " ,
2010-05-06 02:37:52 +04:00
( uint64_t ) total ,
( uint64_t ) where - > size ,
( uint64_t ) where - > start , strerror ( errno ) ) ;
2004-12-10 19:01:35 +03:00
2003-07-05 02:34:56 +04:00
if ( n < = 0 )
break ;
total + = n ;
buffer + = n ;
}
return ( total = = ( size_t ) where - > size ) ;
}
2018-01-10 05:09:06 +03:00
static int _io ( struct device_buffer * devbuf , dev_io_reason_t reason )
{
struct device_area * where = & devbuf - > where ;
int fd = dev_fd ( where - > dev ) ;
if ( fd < 0 ) {
log_error ( " Attempt to read an unopened device (%s). " ,
dev_name ( where - > dev ) ) ;
return 0 ;
}
log_debug_io ( " %s %s(fd %d):%8 " PRIu64 " bytes (sync) at % " PRIu64 " %s (for %s) " ,
devbuf - > write ? " Write " : " Read " , dev_name ( where - > dev ) , fd ,
where - > size , ( uint64_t ) where - > start ,
( devbuf - > write & & test_mode ( ) ) ? " (test mode - suppressed) " : " " , _reason_text ( reason ) ) ;
/*
* Skip all writes in test mode .
*/
if ( devbuf - > write & & test_mode ( ) )
return 1 ;
if ( where - > size > SSIZE_MAX ) {
log_error ( " Read size too large: % " PRIu64 , where - > size ) ;
return 0 ;
}
return _io_sync ( devbuf ) ;
}
2003-07-05 02:34:56 +04:00
/*-----------------------------------------------------------------
* LVM2 uses O_DIRECT when performing metadata io , which requires
* block size aligned accesses . If any io is not aligned we have
* to perform the io via a bounce buffer , obviously this is quite
* inefficient .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
2013-12-12 14:26:35 +04:00
* Get the physical and logical block size for a device .
2003-07-05 02:34:56 +04:00
*/
2013-12-12 14:26:35 +04:00
int dev_get_block_size ( struct device * dev , unsigned int * physical_block_size , unsigned int * block_size )
2003-07-05 02:34:56 +04:00
{
2004-12-10 19:01:35 +03:00
const char * name = dev_name ( dev ) ;
2013-12-12 14:26:35 +04:00
int needs_open ;
int r = 1 ;
needs_open = ( ! dev - > open_count & & ( dev - > phys_block_size = = - 1 | | dev - > block_size = = - 1 ) ) ;
if ( needs_open & & ! dev_open_readonly ( dev ) )
return_0 ;
2011-03-30 00:19:03 +04:00
if ( dev - > block_size = = - 1 ) {
2004-12-10 19:01:35 +03:00
if ( ioctl ( dev_fd ( dev ) , BLKBSZGET , & dev - > block_size ) < 0 ) {
log_sys_error ( " ioctl BLKBSZGET " , name ) ;
2013-12-12 14:26:35 +04:00
r = 0 ;
goto out ;
2004-12-10 19:01:35 +03:00
}
2017-11-13 17:43:32 +03:00
log_debug_devs ( " %s: Block size is %u bytes " , name , dev - > block_size ) ;
2003-07-05 02:34:56 +04:00
}
2013-12-17 18:16:25 +04:00
# ifdef BLKPBSZGET
/* BLKPBSZGET is available in kernel >= 2.6.32 only */
if ( dev - > phys_block_size = = - 1 ) {
if ( ioctl ( dev_fd ( dev ) , BLKPBSZGET , & dev - > phys_block_size ) < 0 ) {
log_sys_error ( " ioctl BLKPBSZGET " , name ) ;
r = 0 ;
goto out ;
}
2017-11-13 17:43:32 +03:00
log_debug_devs ( " %s: Physical block size is %u bytes " , name , dev - > phys_block_size ) ;
2013-12-17 18:16:25 +04:00
}
2014-10-13 21:15:41 +04:00
# elif defined (BLKSSZGET)
2013-12-17 18:16:25 +04:00
/* if we can't get physical block size, just use logical block size instead */
2013-12-18 16:52:01 +04:00
if ( dev - > phys_block_size = = - 1 ) {
if ( ioctl ( dev_fd ( dev ) , BLKSSZGET , & dev - > phys_block_size ) < 0 ) {
log_sys_error ( " ioctl BLKSSZGET " , name ) ;
r = 0 ;
goto out ;
}
2017-11-13 17:43:32 +03:00
log_debug_devs ( " %s: Physical block size can't be determined: Using logical block size of %u bytes " , name , dev - > phys_block_size ) ;
2013-12-18 16:52:01 +04:00
}
# else
/* if even BLKSSZGET is not available, use default 512b */
if ( dev - > phys_block_size = = - 1 ) {
dev - > phys_block_size = 512 ;
2017-11-13 17:43:32 +03:00
log_debug_devs ( " %s: Physical block size can't be determined: Using block size of %u bytes instead " , name , dev - > phys_block_size ) ;
2013-12-18 16:52:01 +04:00
}
2013-12-17 18:16:25 +04:00
# endif
2013-12-18 16:52:01 +04:00
2013-12-12 14:26:35 +04:00
* physical_block_size = ( unsigned int ) dev - > phys_block_size ;
* block_size = ( unsigned int ) dev - > block_size ;
out :
2014-01-22 19:20:09 +04:00
if ( needs_open & & ! dev_close ( dev ) )
stack ;
2004-12-10 19:01:35 +03:00
2013-12-12 14:26:35 +04:00
return r ;
2003-07-05 02:34:56 +04:00
}
/*
* Widens a region to be an aligned region .
*/
static void _widen_region ( unsigned int block_size , struct device_area * region ,
struct device_area * result )
{
uint64_t mask = block_size - 1 , delta ;
memcpy ( result , region , sizeof ( * result ) ) ;
/* adjust the start */
delta = result - > start & mask ;
if ( delta ) {
result - > start - = delta ;
result - > size + = delta ;
}
/* adjust the end */
delta = ( result - > start + result - > size ) & mask ;
if ( delta )
result - > size + = block_size - delta ;
}
2011-02-19 02:09:55 +03:00
static int _aligned_io ( struct device_area * where , char * buffer ,
2017-12-05 02:18:56 +03:00
int should_write , dev_io_reason_t reason )
2003-07-05 02:34:56 +04:00
{
2018-01-10 05:09:06 +03:00
char * bounce , * bounce_buf = NULL ;
2013-12-12 14:26:35 +04:00
unsigned int physical_block_size = 0 ;
2003-07-05 02:34:56 +04:00
unsigned int block_size = 0 ;
2017-12-05 04:00:38 +03:00
unsigned buffer_was_widened = 0 ;
2003-07-05 02:34:56 +04:00
uintptr_t mask ;
struct device_area widened ;
2018-01-10 05:09:06 +03:00
struct device_buffer * devbuf ;
2010-09-23 02:31:45 +04:00
int r = 0 ;
2003-07-05 02:34:56 +04:00
if ( ! ( where - > dev - > flags & DEV_REGULAR ) & &
2013-12-12 14:26:35 +04:00
! dev_get_block_size ( where - > dev , & physical_block_size , & block_size ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2003-07-05 02:34:56 +04:00
if ( ! block_size )
2006-08-17 22:23:44 +04:00
block_size = lvm_getpagesize ( ) ;
2018-01-10 16:19:12 +03:00
/* Apply minimum read size */
if ( ! should_write & & block_size < MIN_READ_SIZE )
block_size = MIN_READ_SIZE ;
2017-12-05 04:00:38 +03:00
mask = block_size - 1 ;
2003-07-05 02:34:56 +04:00
_widen_region ( block_size , where , & widened ) ;
2017-12-05 04:00:38 +03:00
/* Did we widen the buffer? When writing, this means means read-modify-write. */
if ( where - > size ! = widened . size | | where - > start ! = widened . start ) {
buffer_was_widened = 1 ;
log_debug_io ( " Widening request for % " PRIu64 " bytes at % " PRIu64 " to % " PRIu64 " bytes at % " PRIu64 " on %s (for %s) " ,
where - > size , ( uint64_t ) where - > start , widened . size , ( uint64_t ) widened . start , dev_name ( where - > dev ) , _reason_text ( reason ) ) ;
2018-01-10 05:09:06 +03:00
}
2003-07-05 02:34:56 +04:00
2018-01-10 16:18:56 +03:00
if ( should_write & & ! buffer_was_widened & & ! ( ( uintptr_t ) buffer & mask ) )
2018-01-10 05:09:06 +03:00
/* Perform the I/O directly. */
bounce = buffer ;
2018-01-09 23:25:43 +03:00
# ifndef DEBUG_MEM
2018-01-10 05:09:06 +03:00
else if ( ! ( bounce_buf = bounce = dm_malloc_aligned ( ( size_t ) widened . size , 0 ) ) ) {
2018-01-09 23:25:43 +03:00
log_error ( " Bounce buffer malloc failed " ) ;
return 0 ;
}
# else
2018-01-10 05:09:06 +03:00
else {
/* Allocate a bounce buffer with an extra block */
if ( ! ( bounce_buf = bounce = dm_malloc ( ( size_t ) widened . size + block_size ) ) ) {
log_error ( " Bounce buffer malloc failed " ) ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
2018-01-10 05:09:06 +03:00
/*
* Realign start of bounce buffer ( using the extra sector )
*/
if ( ( ( uintptr_t ) bounce ) & mask )
bounce = ( char * ) ( ( ( ( uintptr_t ) bounce ) + mask ) & ~ mask ) ;
}
2018-01-09 23:25:43 +03:00
# endif
2003-07-05 02:34:56 +04:00
2018-01-10 16:18:56 +03:00
devbuf = DEV_DEVBUF ( where - > dev , reason ) ;
2018-01-10 05:09:06 +03:00
_release_devbuf ( devbuf ) ;
devbuf - > malloc_address = bounce_buf ;
devbuf - > buf = bounce ;
devbuf - > where . dev = where - > dev ;
devbuf - > where . start = widened . start ;
devbuf - > where . size = widened . size ;
devbuf - > write = 0 ;
2017-12-05 04:00:38 +03:00
/* Do we need to read into the bounce buffer? */
if ( ( ! should_write | | buffer_was_widened ) & &
2018-01-10 05:09:06 +03:00
! _io ( devbuf , reason ) ) {
2008-01-30 16:19:47 +03:00
if ( ! should_write )
2018-01-10 05:09:06 +03:00
goto_bad ;
2017-12-05 04:00:38 +03:00
/* FIXME Handle errors properly! */
2003-07-05 02:34:56 +04:00
/* FIXME pre-extend the file */
memset ( bounce , ' \n ' , widened . size ) ;
}
if ( should_write ) {
2018-01-10 05:09:06 +03:00
if ( bounce_buf ) {
memcpy ( bounce + ( where - > start - widened . start ) , buffer ,
( size_t ) where - > size ) ;
log_debug_io ( " Overwriting % " PRIu64 " bytes at % " PRIu64 " (for %s) " , where - > size ,
( uint64_t ) where - > start , _reason_text ( reason ) ) ;
}
2003-07-05 02:34:56 +04:00
/* ... then we write */
2018-01-10 05:09:06 +03:00
devbuf - > write = 1 ;
if ( ! ( r = _io ( devbuf , reason ) ) )
goto_bad ;
2010-09-27 23:15:13 +04:00
2018-01-10 05:09:06 +03:00
_release_devbuf ( devbuf ) ;
return 1 ;
2003-07-05 02:34:56 +04:00
}
2018-01-10 05:09:06 +03:00
/* read */
/* We store what we just read as it often also satisfies the next request */
2018-01-15 22:32:59 +03:00
devbuf - > data_offset = where - > start - widened . start ;
2003-07-05 02:34:56 +04:00
2018-01-10 05:09:06 +03:00
return 1 ;
2010-09-23 02:31:45 +04:00
2018-01-10 05:09:06 +03:00
bad :
_release_devbuf ( devbuf ) ;
return 0 ;
2003-07-05 02:34:56 +04:00
}
2016-01-15 18:41:27 +03:00
static int _dev_get_size_file ( struct device * dev , uint64_t * size )
2005-05-03 21:28:23 +04:00
{
const char * name = dev_name ( dev ) ;
struct stat info ;
2003-07-05 02:34:56 +04:00
2016-01-15 18:41:27 +03:00
if ( dev - > size_seqno = = _dev_size_seqno ) {
log_very_verbose ( " %s: using cached size % " PRIu64 " sectors " ,
name , dev - > size ) ;
* size = dev - > size ;
return 1 ;
}
2005-05-03 21:28:23 +04:00
if ( stat ( name , & info ) ) {
log_sys_error ( " stat " , name ) ;
return 0 ;
}
* size = info . st_size ;
* size > > = SECTOR_SHIFT ; /* Convert to sectors */
2016-01-15 18:41:27 +03:00
dev - > size = * size ;
dev - > size_seqno = _dev_size_seqno ;
2005-05-03 21:28:23 +04:00
log_very_verbose ( " %s: size is % " PRIu64 " sectors " , name , * size ) ;
return 1 ;
}
2015-03-03 17:37:17 +03:00
static int _dev_get_size_dev ( struct device * dev , uint64_t * size )
2001-10-03 16:41:29 +04:00
{
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2001-10-03 16:41:29 +04:00
2016-01-15 18:41:27 +03:00
if ( dev - > size_seqno = = _dev_size_seqno ) {
log_very_verbose ( " %s: using cached size % " PRIu64 " sectors " ,
name , dev - > size ) ;
* size = dev - > size ;
return 1 ;
}
2015-03-03 17:37:17 +03:00
if ( ! dev_open_readonly ( dev ) )
return_0 ;
2001-10-03 16:41:29 +04:00
2015-03-03 17:37:17 +03:00
if ( ioctl ( dev_fd ( dev ) , BLKGETSIZE64 , size ) < 0 ) {
2003-04-15 17:24:42 +04:00
log_sys_error ( " ioctl BLKGETSIZE64 " , name ) ;
2015-03-03 17:37:17 +03:00
if ( ! dev_close ( dev ) )
2004-12-21 20:54:52 +03:00
log_sys_error ( " close " , name ) ;
2001-10-03 16:41:29 +04:00
return 0 ;
}
2003-04-30 19:21:10 +04:00
* size > > = BLKSIZE_SHIFT ; /* Convert to sectors */
2016-01-15 18:41:27 +03:00
dev - > size = * size ;
dev - > size_seqno = _dev_size_seqno ;
2015-03-03 17:37:17 +03:00
if ( ! dev_close ( dev ) )
2004-12-21 20:54:52 +03:00
log_sys_error ( " close " , name ) ;
2004-12-10 19:01:35 +03:00
log_very_verbose ( " %s: size is % " PRIu64 " sectors " , name , * size ) ;
2001-10-03 16:41:29 +04:00
return 1 ;
}
2009-05-20 15:09:49 +04:00
static int _dev_read_ahead_dev ( struct device * dev , uint32_t * read_ahead )
{
long read_ahead_long ;
if ( dev - > read_ahead ! = - 1 ) {
* read_ahead = ( uint32_t ) dev - > read_ahead ;
return 1 ;
}
2012-06-25 13:34:21 +04:00
if ( ! dev_open_readonly ( dev ) )
2009-05-20 15:09:49 +04:00
return_0 ;
if ( ioctl ( dev - > fd , BLKRAGET , & read_ahead_long ) < 0 ) {
log_sys_error ( " ioctl BLKRAGET " , dev_name ( dev ) ) ;
if ( ! dev_close ( dev ) )
stack ;
return 0 ;
}
* read_ahead = ( uint32_t ) read_ahead_long ;
dev - > read_ahead = read_ahead_long ;
log_very_verbose ( " %s: read_ahead is %u sectors " ,
dev_name ( dev ) , * read_ahead ) ;
2012-02-08 15:15:38 +04:00
if ( ! dev_close ( dev ) )
stack ;
2009-05-20 15:09:49 +04:00
return 1 ;
}
2011-04-13 01:59:01 +04:00
static int _dev_discard_blocks ( struct device * dev , uint64_t offset_bytes , uint64_t size_bytes )
{
uint64_t discard_range [ 2 ] ;
if ( ! dev_open ( dev ) )
return_0 ;
discard_range [ 0 ] = offset_bytes ;
discard_range [ 1 ] = size_bytes ;
2013-01-08 02:30:29 +04:00
log_debug_devs ( " Discarding % " PRIu64 " bytes offset % " PRIu64 " bytes on %s. " ,
size_bytes , offset_bytes , dev_name ( dev ) ) ;
2011-04-13 01:59:01 +04:00
if ( ioctl ( dev - > fd , BLKDISCARD , & discard_range ) < 0 ) {
log_error ( " %s: BLKDISCARD ioctl at offset % " PRIu64 " size % " PRIu64 " failed: %s. " ,
dev_name ( dev ) , offset_bytes , size_bytes , strerror ( errno ) ) ;
if ( ! dev_close ( dev ) )
stack ;
/* It doesn't matter if discard failed, so return success. */
return 1 ;
}
if ( ! dev_close ( dev ) )
stack ;
return 1 ;
}
2005-05-03 21:28:23 +04:00
/*-----------------------------------------------------------------
* Public functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2016-01-15 18:41:27 +03:00
void dev_size_seqno_inc ( void )
{
_dev_size_seqno + + ;
}
2005-05-03 21:28:23 +04:00
2015-03-03 17:37:17 +03:00
int dev_get_size ( struct device * dev , uint64_t * size )
2005-05-03 21:28:23 +04:00
{
2009-01-10 05:43:51 +03:00
if ( ! dev )
return 0 ;
2005-05-03 21:28:23 +04:00
if ( ( dev - > flags & DEV_REGULAR ) )
return _dev_get_size_file ( dev , size ) ;
2017-07-19 17:16:12 +03:00
return _dev_get_size_dev ( dev , size ) ;
2005-05-03 21:28:23 +04:00
}
2009-05-20 15:09:49 +04:00
int dev_get_read_ahead ( struct device * dev , uint32_t * read_ahead )
{
if ( ! dev )
return 0 ;
if ( dev - > flags & DEV_REGULAR ) {
* read_ahead = 0 ;
return 1 ;
}
return _dev_read_ahead_dev ( dev , read_ahead ) ;
}
2011-04-13 01:59:01 +04:00
int dev_discard_blocks ( struct device * dev , uint64_t offset_bytes , uint64_t size_bytes )
{
if ( ! dev )
return 0 ;
if ( dev - > flags & DEV_REGULAR )
return 1 ;
return _dev_discard_blocks ( dev , offset_bytes , size_bytes ) ;
}
2003-07-05 02:34:56 +04:00
void dev_flush ( struct device * dev )
2002-08-14 18:58:00 +04:00
{
2003-07-05 02:34:56 +04:00
if ( ! ( dev - > flags & DEV_REGULAR ) & & ioctl ( dev - > fd , BLKFLSBUF , 0 ) > = 0 )
2003-04-28 20:20:39 +04:00
return ;
2003-07-05 02:34:56 +04:00
if ( fsync ( dev - > fd ) > = 0 )
2003-04-28 20:20:39 +04:00
return ;
sync ( ) ;
2002-06-25 18:02:28 +04:00
}
2003-07-05 02:34:56 +04:00
int dev_open_flags ( struct device * dev , int flags , int direct , int quiet )
2001-11-14 13:01:52 +03:00
{
2002-01-23 21:55:01 +03:00
struct stat buf ;
2003-07-05 02:34:56 +04:00
const char * name ;
2005-10-04 01:10:41 +04:00
int need_excl = 0 , need_rw = 0 ;
if ( ( flags & O_ACCMODE ) = = O_RDWR )
need_rw = 1 ;
if ( ( flags & O_EXCL ) )
need_excl = 1 ;
2002-01-25 02:16:19 +03:00
2003-07-05 02:34:56 +04:00
if ( dev - > fd > = 0 ) {
2005-10-04 01:10:41 +04:00
if ( ( ( dev - > flags & DEV_OPENED_RW ) | | ! need_rw ) & &
( ( dev - > flags & DEV_OPENED_EXCL ) | | ! need_excl ) ) {
2004-12-13 00:47:14 +03:00
dev - > open_count + + ;
return 1 ;
}
2017-12-12 20:56:58 +03:00
if ( dev - > open_count & & ! need_excl )
2017-11-13 17:43:32 +03:00
log_debug_devs ( " %s: Already opened read-only. Upgrading "
2013-01-08 02:30:29 +04:00
" to read-write. " , dev_name ( dev ) ) ;
2017-12-12 20:56:58 +03:00
/* dev_close_immediate will decrement this */
dev - > open_count + + ;
2004-12-21 23:23:16 +03:00
dev_close_immediate ( dev ) ;
2013-04-19 23:16:08 +04:00
// FIXME: dev with DEV_ALLOCED is released
// but code is referencing it
2002-01-25 02:16:19 +03:00
}
2001-11-14 13:01:52 +03:00
2011-02-18 17:16:11 +03:00
if ( critical_section ( ) )
2010-04-01 18:30:51 +04:00
/* FIXME Make this log_error */
log_verbose ( " dev_open(%s) called while suspended " ,
2013-01-08 02:30:29 +04:00
dev_name ( dev ) ) ;
2003-07-05 02:34:56 +04:00
2011-11-30 14:30:33 +04:00
if ( ! ( name = dev_name_confirmed ( dev , quiet ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-11-14 13:01:52 +03:00
2003-11-06 20:14:06 +03:00
# ifdef O_DIRECT_SUPPORT
2005-04-07 16:17:46 +04:00
if ( direct ) {
if ( ! ( dev - > flags & DEV_O_DIRECT_TESTED ) )
dev - > flags | = DEV_O_DIRECT ;
if ( ( dev - > flags & DEV_O_DIRECT ) )
flags | = O_DIRECT ;
}
2003-11-06 20:14:06 +03:00
# endif
2003-07-05 02:34:56 +04:00
2004-09-15 02:23:23 +04:00
# ifdef O_NOATIME
/* Don't update atime on device inodes */
2016-05-12 03:05:52 +03:00
if ( ! ( dev - > flags & DEV_REGULAR ) & & ! ( dev - > flags & DEV_NOT_O_NOATIME ) )
2004-09-15 02:23:23 +04:00
flags | = O_NOATIME ;
# endif
2003-07-05 02:34:56 +04:00
if ( ( dev - > fd = open ( name , flags , 0777 ) ) < 0 ) {
2016-05-12 03:05:52 +03:00
# ifdef O_NOATIME
if ( ( errno = = EPERM ) & & ( flags & O_NOATIME ) ) {
flags & = ~ O_NOATIME ;
dev - > flags | = DEV_NOT_O_NOATIME ;
if ( ( dev - > fd = open ( name , flags , 0777 ) ) > = 0 ) {
log_debug_devs ( " %s: Not using O_NOATIME " , name ) ;
goto opened ;
}
}
# endif
2005-04-07 16:17:46 +04:00
# ifdef O_DIRECT_SUPPORT
if ( direct & & ! ( dev - > flags & DEV_O_DIRECT_TESTED ) ) {
flags & = ~ O_DIRECT ;
if ( ( dev - > fd = open ( name , flags , 0777 ) ) > = 0 ) {
dev - > flags & = ~ DEV_O_DIRECT ;
2013-01-08 02:30:29 +04:00
log_debug_devs ( " %s: Not using O_DIRECT " , name ) ;
2005-04-07 16:17:46 +04:00
goto opened ;
}
}
# endif
2005-03-04 00:54:35 +03:00
if ( quiet )
log_sys_debug ( " open " , name ) ;
else
log_sys_error ( " open " , name ) ;
2016-03-17 15:45:14 +03:00
dev - > flags | = DEV_OPEN_FAILURE ;
2001-11-14 13:01:52 +03:00
return 0 ;
}
2005-04-07 16:17:46 +04:00
# ifdef O_DIRECT_SUPPORT
2005-04-07 16:25:33 +04:00
opened :
2005-04-07 16:17:46 +04:00
if ( direct )
dev - > flags | = DEV_O_DIRECT_TESTED ;
# endif
2005-04-07 16:25:33 +04:00
dev - > open_count + + ;
dev - > flags & = ~ DEV_ACCESSED_W ;
2005-10-04 01:10:41 +04:00
if ( need_rw )
2004-12-10 19:01:35 +03:00
dev - > flags | = DEV_OPENED_RW ;
else
dev - > flags & = ~ DEV_OPENED_RW ;
2003-07-05 02:34:56 +04:00
2005-10-04 01:10:41 +04:00
if ( need_excl )
dev - > flags | = DEV_OPENED_EXCL ;
else
dev - > flags & = ~ DEV_OPENED_EXCL ;
2003-07-05 02:34:56 +04:00
if ( ! ( dev - > flags & DEV_REGULAR ) & &
( ( fstat ( dev - > fd , & buf ) < 0 ) | | ( buf . st_rdev ! = dev - > dev ) ) ) {
2002-01-23 21:55:01 +03:00
log_error ( " %s: fstat failed: Has device name changed? " , name ) ;
2004-12-21 23:23:16 +03:00
dev_close_immediate ( dev ) ;
2002-01-23 21:55:01 +03:00
return 0 ;
}
2003-11-06 20:14:06 +03:00
# ifndef O_DIRECT_SUPPORT
2003-07-05 02:34:56 +04:00
if ( ! ( dev - > flags & DEV_REGULAR ) )
dev_flush ( dev ) ;
# endif
2004-12-10 19:01:35 +03:00
if ( ( flags & O_CREAT ) & & ! ( flags & O_TRUNC ) )
2003-07-05 02:34:56 +04:00
dev - > end = lseek ( dev - > fd , ( off_t ) 0 , SEEK_END ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & _open_devices , & dev - > open_list ) ;
2004-12-10 19:01:35 +03:00
2013-01-08 02:30:29 +04:00
log_debug_devs ( " Opened %s %s%s%s " , dev_name ( dev ) ,
dev - > flags & DEV_OPENED_RW ? " RW " : " RO " ,
dev - > flags & DEV_OPENED_EXCL ? " O_EXCL " : " " ,
dev - > flags & DEV_O_DIRECT ? " O_DIRECT " : " " ) ;
2002-04-24 22:20:51 +04:00
2016-03-17 15:45:14 +03:00
dev - > flags & = ~ DEV_OPEN_FAILURE ;
2001-11-14 13:01:52 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
int dev_open_quiet ( struct device * dev )
{
2011-05-28 13:48:14 +04:00
return dev_open_flags ( dev , O_RDWR , 1 , 1 ) ;
2003-07-05 02:34:56 +04:00
}
int dev_open ( struct device * dev )
{
2011-05-28 13:48:14 +04:00
return dev_open_flags ( dev , O_RDWR , 1 , 0 ) ;
2003-07-05 02:34:56 +04:00
}
2011-05-24 17:36:57 +04:00
int dev_open_readonly ( struct device * dev )
{
return dev_open_flags ( dev , O_RDONLY , 1 , 0 ) ;
}
int dev_open_readonly_buffered ( struct device * dev )
{
return dev_open_flags ( dev , O_RDONLY , 0 , 0 ) ;
}
int dev_open_readonly_quiet ( struct device * dev )
{
return dev_open_flags ( dev , O_RDONLY , 1 , 1 ) ;
}
2005-10-04 01:10:41 +04:00
int dev_test_excl ( struct device * dev )
{
int flags ;
int r ;
flags = vg_write_lock_held ( ) ? O_RDWR : O_RDONLY ;
flags | = O_EXCL ;
r = dev_open_flags ( dev , flags , 1 , 1 ) ;
if ( r )
dev_close_immediate ( dev ) ;
return r ;
}
2003-07-05 02:34:56 +04:00
static void _close ( struct device * dev )
{
if ( close ( dev - > fd ) )
log_sys_error ( " close " , dev_name ( dev ) ) ;
dev - > fd = - 1 ;
2013-12-12 14:26:35 +04:00
dev - > phys_block_size = - 1 ;
2004-12-10 19:01:35 +03:00
dev - > block_size = - 1 ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & dev - > open_list ) ;
2018-01-10 15:03:31 +03:00
devbufs_release ( dev ) ;
2003-07-05 02:34:56 +04:00
2013-01-08 02:30:29 +04:00
log_debug_devs ( " Closed %s " , dev_name ( dev ) ) ;
2003-07-05 02:34:56 +04:00
2015-08-17 14:57:01 +03:00
if ( dev - > flags & DEV_ALLOCED )
dev_destroy_file ( dev ) ;
2003-07-05 02:34:56 +04:00
}
2003-11-14 20:55:39 +03:00
static int _dev_close ( struct device * dev , int immediate )
2001-11-14 13:01:52 +03:00
{
2005-10-27 21:44:55 +04:00
2001-11-14 13:01:52 +03:00
if ( dev - > fd < 0 ) {
2001-11-14 16:52:38 +03:00
log_error ( " Attempt to close device '%s' "
" which is not open. " , dev_name ( dev ) ) ;
2001-11-14 13:01:52 +03:00
return 0 ;
}
2003-11-06 20:14:06 +03:00
# ifndef O_DIRECT_SUPPORT
2002-08-14 18:58:00 +04:00
if ( dev - > flags & DEV_ACCESSED_W )
2003-07-05 02:34:56 +04:00
dev_flush ( dev ) ;
# endif
2001-11-14 16:52:38 +03:00
2004-12-21 23:23:16 +03:00
if ( dev - > open_count > 0 )
dev - > open_count - - ;
2005-11-23 19:07:40 +03:00
if ( immediate & & dev - > open_count )
2013-01-08 02:30:29 +04:00
log_debug_devs ( " %s: Immediate close attempt while still referenced " ,
dev_name ( dev ) ) ;
2005-10-04 01:10:41 +04:00
2005-10-27 21:44:55 +04:00
/* Close unless device is known to belong to a locked VG */
if ( immediate | |
2012-02-10 05:28:27 +04:00
( dev - > open_count < 1 & & ! lvmcache_pvid_is_locked ( dev - > pvid ) ) )
2003-07-05 02:34:56 +04:00
_close ( dev ) ;
2001-11-14 13:01:52 +03:00
return 1 ;
}
2003-11-14 20:55:39 +03:00
int dev_close ( struct device * dev )
{
return _dev_close ( dev , 0 ) ;
}
int dev_close_immediate ( struct device * dev )
{
return _dev_close ( dev , 1 ) ;
}
2003-07-05 02:34:56 +04:00
void dev_close_all ( void )
2001-10-08 20:08:16 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * doh , * doht ;
2003-07-05 02:34:56 +04:00
struct device * dev ;
2002-12-20 02:25:55 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( doh , doht , & _open_devices ) {
dev = dm_list_struct_base ( doh , struct device , open_list ) ;
2003-07-05 02:34:56 +04:00
if ( dev - > open_count < 1 )
_close ( dev ) ;
2001-10-08 20:08:16 +04:00
}
}
2010-10-13 19:40:38 +04:00
static inline int _dev_is_valid ( struct device * dev )
{
return ( dev - > max_error_count = = NO_DEV_ERROR_COUNT_LIMIT | |
dev - > error_count < dev - > max_error_count ) ;
}
static void _dev_inc_error_count ( struct device * dev )
{
if ( + + dev - > error_count = = dev - > max_error_count )
log_warn ( " WARNING: Error counts reached a limit of %d. "
" Device %s was disabled " ,
dev - > max_error_count , dev_name ( dev ) ) ;
}
2018-01-10 16:18:56 +03:00
/*
2018-01-15 22:32:59 +03:00
* Data is returned ( read - only ) at DEV_DEVBUF_DATA ( dev , reason )
2018-01-10 16:18:56 +03:00
*/
static int _dev_read ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason )
2001-10-03 16:41:29 +04:00
{
2003-07-05 02:34:56 +04:00
struct device_area where ;
2018-01-10 16:19:12 +03:00
struct device_buffer * devbuf ;
uint64_t buf_end ;
2010-10-13 19:40:38 +04:00
int ret ;
2001-10-08 20:08:16 +04:00
2018-01-10 16:19:12 +03:00
if ( ! dev - > open_count ) {
log_error ( INTERNAL_ERROR " Attempt to access device %s while closed. " , dev_name ( dev ) ) ;
return 0 ;
}
2001-10-08 20:08:16 +04:00
2010-10-13 19:40:38 +04:00
if ( ! _dev_is_valid ( dev ) )
return 0 ;
2018-01-10 16:19:12 +03:00
/*
* Can we satisfy this from data we stored last time we read ?
*/
if ( ( devbuf = DEV_DEVBUF ( dev , reason ) ) & & devbuf - > malloc_address ) {
buf_end = devbuf - > where . start + devbuf - > where . size - 1 ;
if ( offset > = devbuf - > where . start & & offset < = buf_end & & offset + len - 1 < = buf_end ) {
/* Reuse this buffer */
2018-01-15 22:32:59 +03:00
devbuf - > data_offset = offset - devbuf - > where . start ;
2018-01-10 16:19:12 +03:00
log_debug_io ( " Cached read for % " PRIu64 " bytes at % " PRIu64 " on %s (for %s) " ,
2018-01-10 21:48:01 +03:00
( uint64_t ) len , ( uint64_t ) offset , dev_name ( dev ) , _reason_text ( reason ) ) ;
2018-01-10 16:19:12 +03:00
return 1 ;
}
}
2003-07-05 02:34:56 +04:00
where . dev = dev ;
where . start = offset ;
where . size = len ;
2001-10-08 20:08:16 +04:00
2018-01-10 16:18:56 +03:00
ret = _aligned_io ( & where , NULL , 0 , reason ) ;
2010-10-13 19:40:38 +04:00
if ( ! ret )
_dev_inc_error_count ( dev ) ;
return ret ;
2001-10-03 16:41:29 +04:00
}
2018-01-10 21:48:01 +03:00
/* Returns pointer to read-only buffer. Caller does not free it. */
2018-01-10 22:50:53 +03:00
const char * dev_read ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason )
2017-12-19 04:12:18 +03:00
{
2018-01-10 16:18:56 +03:00
if ( ! _dev_read ( dev , offset , len , reason ) ) {
2017-12-19 04:12:18 +03:00
log_error ( " Read from %s failed " , dev_name ( dev ) ) ;
return NULL ;
}
2018-01-15 22:32:59 +03:00
return DEV_DEVBUF_DATA ( dev , reason ) ;
2017-12-19 04:12:18 +03:00
}
2018-01-10 21:48:01 +03:00
/* Obtains data requested then passes it (read-only) to dev_read_callback_fn() */
2018-01-06 03:33:09 +03:00
int dev_read_callback ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason ,
lvm_callback_fn_t dev_read_callback_fn , void * callback_context )
{
int r = 0 ;
2018-01-10 16:18:56 +03:00
if ( ! _dev_read ( dev , offset , len , reason ) ) {
2018-01-06 03:33:09 +03:00
log_error ( " Read from %s failed " , dev_name ( dev ) ) ;
goto out ;
}
r = 1 ;
out :
if ( dev_read_callback_fn )
2018-01-15 22:32:59 +03:00
dev_read_callback_fn ( ! r , callback_context , DEV_DEVBUF_DATA ( dev , reason ) ) ;
2018-01-06 03:33:09 +03:00
return r ;
}
2018-01-10 21:48:01 +03:00
/* Read into supplied retbuf owned by the caller. */
2017-12-19 04:12:18 +03:00
int dev_read_buf ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason , void * retbuf )
{
2018-01-10 21:48:01 +03:00
if ( ! _dev_read ( dev , offset , len , reason ) ) {
log_error ( " Read from %s failed " , dev_name ( dev ) ) ;
return 0 ;
}
2017-12-19 04:12:18 +03:00
2018-01-15 22:32:59 +03:00
memcpy ( retbuf , DEV_DEVBUF_DATA ( dev , reason ) , len ) ;
2017-12-19 04:12:18 +03:00
return 1 ;
}
2007-04-19 06:10:42 +04:00
/*
2017-12-16 01:34:26 +03:00
* Read from ' dev ' in 2 distinct regions , denoted by ( offset , len ) and ( offset2 , len2 ) .
* Caller is responsible for dm_free ( ) .
2007-04-19 06:10:42 +04:00
*/
2018-01-10 22:50:53 +03:00
const char * dev_read_circular ( struct device * dev , uint64_t offset , size_t len ,
2017-12-16 01:34:26 +03:00
uint64_t offset2 , size_t len2 , dev_io_reason_t reason )
2007-04-19 06:10:42 +04:00
{
2017-12-16 01:34:26 +03:00
char * buf = NULL ;
if ( ! ( buf = dm_malloc ( len + len2 ) ) ) {
log_error ( " Buffer allocation failed for split metadata. " ) ;
return NULL ;
}
2018-01-10 21:48:01 +03:00
if ( ! dev_read_buf ( dev , offset , len , reason , buf ) ) {
2007-04-19 06:10:42 +04:00
log_error ( " Read from %s failed " , dev_name ( dev ) ) ;
2017-12-16 01:34:26 +03:00
dm_free ( buf ) ;
return NULL ;
2007-04-19 06:10:42 +04:00
}
2018-01-10 21:48:01 +03:00
if ( ! dev_read_buf ( dev , offset2 , len2 , reason , buf + len ) ) {
2017-12-16 01:34:26 +03:00
log_error ( " Circular read from %s failed " , dev_name ( dev ) ) ;
dm_free ( buf ) ;
return NULL ;
2007-04-19 06:10:42 +04:00
}
2017-12-16 01:34:26 +03:00
return buf ;
2007-04-19 06:10:42 +04:00
}
2003-07-05 02:34:56 +04:00
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
* But fails if concurrent processes writing
*/
2001-11-28 21:03:11 +03:00
2003-07-05 02:34:56 +04:00
/* FIXME pre-extend the file */
2017-12-05 02:18:56 +03:00
int dev_append ( struct device * dev , size_t len , dev_io_reason_t reason , char * buffer )
2003-07-05 02:34:56 +04:00
{
int r ;
2001-10-10 17:03:10 +04:00
2008-01-30 16:19:47 +03:00
if ( ! dev - > open_count )
return_0 ;
2001-10-10 17:03:10 +04:00
2017-12-05 02:18:56 +03:00
r = dev_write ( dev , dev - > end , len , reason , buffer ) ;
2003-07-05 02:34:56 +04:00
dev - > end + = ( uint64_t ) len ;
2001-10-10 17:03:10 +04:00
2003-11-06 20:14:06 +03:00
# ifndef O_DIRECT_SUPPORT
2003-07-05 02:34:56 +04:00
dev_flush ( dev ) ;
# endif
return r ;
2001-10-10 17:03:10 +04:00
}
2017-12-05 02:18:56 +03:00
int dev_write ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason , void * buffer )
2001-10-03 16:41:29 +04:00
{
2003-07-05 02:34:56 +04:00
struct device_area where ;
2010-10-13 19:40:38 +04:00
int ret ;
2001-10-10 17:03:10 +04:00
2008-01-30 16:19:47 +03:00
if ( ! dev - > open_count )
return_0 ;
2001-10-10 17:03:10 +04:00
2010-10-13 19:40:38 +04:00
if ( ! _dev_is_valid ( dev ) )
return 0 ;
2017-12-12 15:57:25 +03:00
if ( ! len ) {
log_error ( INTERNAL_ERROR " Attempted to write 0 bytes to %s at " FMTu64 , dev_name ( dev ) , offset ) ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
where . dev = dev ;
where . start = offset ;
where . size = len ;
2001-10-10 17:03:10 +04:00
2002-04-24 22:20:51 +04:00
dev - > flags | = DEV_ACCESSED_W ;
2017-12-05 02:18:56 +03:00
ret = _aligned_io ( & where , buffer , 1 , reason ) ;
2010-10-13 19:40:38 +04:00
if ( ! ret )
_dev_inc_error_count ( dev ) ;
return ret ;
2001-10-03 16:41:29 +04:00
}
2001-11-13 21:52:52 +03:00
2017-12-05 02:18:56 +03:00
int dev_set ( struct device * dev , uint64_t offset , size_t len , dev_io_reason_t reason , int value )
2001-11-13 21:52:52 +03:00
{
2002-12-20 02:25:55 +03:00
size_t s ;
2018-01-09 23:25:43 +03:00
char buffer [ 4096 ] __attribute__ ( ( aligned ( 4096 ) ) ) ;
2002-11-18 17:01:16 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( dev ) )
return_0 ;
2001-11-13 21:52:52 +03:00
2002-11-18 17:01:16 +03:00
if ( ( offset % SECTOR_SIZE ) | | ( len % SECTOR_SIZE ) )
2013-01-08 02:30:29 +04:00
log_debug_devs ( " Wiping %s at % " PRIu64 " length % " PRIsize_t ,
dev_name ( dev ) , offset , len ) ;
2002-11-18 17:01:16 +03:00
else
2013-01-08 02:30:29 +04:00
log_debug_devs ( " Wiping %s at sector % " PRIu64 " length % " PRIsize_t
" sectors " , dev_name ( dev ) , offset > > SECTOR_SHIFT ,
len > > SECTOR_SHIFT ) ;
2002-11-18 17:01:16 +03:00
2006-05-11 22:39:24 +04:00
memset ( buffer , value , sizeof ( buffer ) ) ;
2001-11-13 21:52:52 +03:00
while ( 1 ) {
2002-08-14 18:58:00 +04:00
s = len > sizeof ( buffer ) ? sizeof ( buffer ) : len ;
2017-12-05 02:18:56 +03:00
if ( ! dev_write ( dev , offset , s , reason , buffer ) )
2001-11-13 21:52:52 +03:00
break ;
2003-07-05 02:34:56 +04:00
len - = s ;
if ( ! len )
2001-11-13 21:52:52 +03:00
break ;
2003-11-14 02:55:03 +03:00
offset + = s ;
2001-11-13 21:52:52 +03:00
}
2002-04-24 22:20:51 +04:00
dev - > flags | = DEV_ACCESSED_W ;
2003-07-05 02:34:56 +04:00
if ( ! dev_close ( dev ) )
2002-11-18 17:01:16 +03:00
stack ;
2001-11-14 13:01:52 +03:00
return ( len = = 0 ) ;
2001-11-13 21:52:52 +03:00
}