2001-10-03 12:41:29 +00:00
/*
2004-03-30 19:35:44 +00:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2012-02-08 11:15:38 +00:00
* Copyright ( C ) 2004 - 2012 Red Hat , Inc . All rights reserved .
2001-10-03 12:41:29 +00:00
*
2004-03-30 19:35:44 +00: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-20 20:55:30 +00:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 19:35:44 +00:00
*
2007-08-20 20:55:30 +00:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 19:35:44 +00:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 11:49:46 +01:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-10-03 12:41:29 +00:00
*/
2018-05-14 10:30:20 +01:00
# include "lib/misc/lib.h"
# include "lib/device/device.h"
# include "lib/metadata/metadata.h"
# include "lib/mm/memlock.h"
2001-10-04 10:13:07 +00:00
2002-12-19 23:25:55 +00:00
# include <limits.h>
2001-10-04 10:13:07 +00:00
# include <sys/stat.h>
2002-07-22 08:10:54 +00:00
# include <fcntl.h>
2002-08-14 14:58:00 +00:00
# include <unistd.h>
2001-10-04 10:13:07 +00:00
# include <sys/ioctl.h>
2003-04-15 13:24:42 +00:00
2013-11-13 13:56:29 +00:00
# ifdef __linux__
2003-04-15 13:24:42 +00:00
# define u64 uint64_t /* Missing without __KERNEL__ */
2003-07-04 22:34:56 +00:00
# undef WNOHANG /* Avoid redefinition */
# undef WUNTRACED /* Avoid redefinition */
2003-04-15 13:24:42 +00:00
# include <linux / fs.h> /* For block ioctl definitions */
# define BLKSIZE_SHIFT SECTOR_SHIFT
2004-01-27 20:53:57 +00:00
# ifndef BLKGETSIZE64 /* fs.h out-of-date */
# define BLKGETSIZE64 _IOR(0x12, 114, size_t)
# endif /* BLKGETSIZE64 */
2011-04-12 21:59:01 +00:00
# ifndef BLKDISCARD
# define BLKDISCARD _IO(0x12,119)
# endif
2003-07-04 22:34:56 +00: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 17:14:06 +00:00
# endif
# ifdef O_DIRECT_SUPPORT
2003-07-04 22:34:56 +00:00
# ifndef O_DIRECT
2003-11-06 17:14:06 +00:00
# error O_DIRECT support configured but O_DIRECT definition not found in headers
2003-07-04 22:34:56 +00:00
# endif
2003-04-15 13:24:42 +00:00
# endif
2001-11-13 18:52:52 +00:00
2016-01-15 16:41:27 +01:00
static unsigned _dev_size_seqno = 1 ;
2003-07-04 22:34:56 +00:00
2016-01-15 16:41:27 +01:00
static int _dev_get_size_file ( struct device * dev , uint64_t * size )
2005-05-03 17:28:23 +00:00
{
const char * name = dev_name ( dev ) ;
struct stat info ;
2003-07-04 22:34:56 +00:00
2022-02-24 16:03:21 -06:00
if ( dm_list_empty ( & dev - > aliases ) )
return_0 ;
2016-01-15 16:41:27 +01: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 17:28:23 +00: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 16:41:27 +01:00
dev - > size = * size ;
dev - > size_seqno = _dev_size_seqno ;
2005-05-03 17:28:23 +00:00
log_very_verbose ( " %s: size is % " PRIu64 " sectors " , name , * size ) ;
return 1 ;
}
2015-03-03 15:37:17 +01:00
static int _dev_get_size_dev ( struct device * dev , uint64_t * size )
2001-10-03 12:41:29 +00:00
{
2001-10-25 14:04:18 +00:00
const char * name = dev_name ( dev ) ;
2018-02-13 08:58:35 -06:00
int fd = dev - > bcache_fd ;
int do_close = 0 ;
2001-10-03 12:41:29 +00:00
2020-05-13 15:47:20 -05:00
if ( dm_list_empty ( & dev - > aliases ) )
2022-02-24 16:03:21 -06:00
return_0 ;
2020-05-13 15:47:20 -05:00
2016-01-15 16:41:27 +01: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 ;
}
2018-02-13 08:58:35 -06:00
if ( fd < = 0 ) {
2020-03-12 10:18:51 -05:00
if ( ! dev_open_readonly_quiet ( dev ) )
2018-02-13 08:58:35 -06:00
return_0 ;
fd = dev_fd ( dev ) ;
do_close = 1 ;
}
2001-10-03 12:41:29 +00:00
2018-02-13 08:58:35 -06:00
if ( ioctl ( fd , BLKGETSIZE64 , size ) < 0 ) {
2021-02-07 14:06:12 +01:00
log_warn ( " WARNING: %s: ioctl BLKGETSIZE64 %s " , name , strerror ( errno ) ) ;
2018-05-11 14:25:08 -05:00
if ( do_close & & ! dev_close_immediate ( dev ) )
2020-09-29 23:48:45 +02:00
stack ;
2001-10-03 12:41:29 +00:00
return 0 ;
}
2003-04-30 15:21:10 +00:00
* size > > = BLKSIZE_SHIFT ; /* Convert to sectors */
2016-01-15 16:41:27 +01:00
dev - > size = * size ;
dev - > size_seqno = _dev_size_seqno ;
2018-05-03 17:12:07 -05:00
log_very_verbose ( " %s: size is % " PRIu64 " sectors " , name , * size ) ;
2018-05-11 14:25:08 -05:00
if ( do_close & & ! dev_close_immediate ( dev ) )
2020-09-29 23:48:45 +02:00
stack ;
2004-12-10 16:01:35 +00:00
2001-10-03 12:41:29 +00:00
return 1 ;
}
2009-05-20 11:09:49 +00:00
static int _dev_read_ahead_dev ( struct device * dev , uint32_t * read_ahead )
{
2021-03-09 15:58:48 +01:00
long read_ahead_long = 0 ;
2009-05-20 11:09:49 +00:00
if ( dev - > read_ahead ! = - 1 ) {
* read_ahead = ( uint32_t ) dev - > read_ahead ;
return 1 ;
}
2020-03-12 10:18:51 -05:00
if ( ! dev_open_readonly_quiet ( dev ) ) {
2021-02-07 14:06:12 +01:00
log_warn ( " WARNING: Failed to open %s to get readahead %s. " ,
dev_name ( dev ) , strerror ( errno ) ) ;
2020-09-29 23:48:45 +02:00
return 0 ;
2020-03-12 10:18:51 -05:00
}
2009-05-20 11:09:49 +00:00
if ( ioctl ( dev - > fd , BLKRAGET , & read_ahead_long ) < 0 ) {
2021-02-07 14:06:12 +01:00
log_warn ( " WARNING: %s: ioctl BLKRAGET %s. " , dev_name ( dev ) , strerror ( errno ) ) ;
2018-05-11 14:25:08 -05:00
if ( ! dev_close_immediate ( dev ) )
2009-05-20 11:09:49 +00:00
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 ) ;
2018-05-11 14:25:08 -05:00
if ( ! dev_close_immediate ( dev ) )
2012-02-08 11:15:38 +00:00
stack ;
2009-05-20 11:09:49 +00:00
return 1 ;
}
2011-04-12 21:59:01 +00: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 ;
2018-07-08 21:11:01 +02:00
log_debug_devs ( " Discarding % " PRIu64 " bytes offset % " PRIu64 " bytes on %s. %s " ,
size_bytes , offset_bytes , dev_name ( dev ) ,
test_mode ( ) ? " (test mode - suppressed) " : " " ) ;
if ( ! test_mode ( ) & & ioctl ( dev - > fd , BLKDISCARD , & discard_range ) < 0 ) {
2021-02-07 14:06:12 +01:00
log_warn ( " WARNING: %s: ioctl BLKDISCARD at offset % " PRIu64 " size % " PRIu64 " failed: %s. " ,
2011-04-12 21:59:01 +00:00
dev_name ( dev ) , offset_bytes , size_bytes , strerror ( errno ) ) ;
2018-05-11 14:25:08 -05:00
if ( ! dev_close_immediate ( dev ) )
2011-04-12 21:59:01 +00:00
stack ;
/* It doesn't matter if discard failed, so return success. */
return 1 ;
}
2018-05-11 14:25:08 -05:00
if ( ! dev_close_immediate ( dev ) )
2011-04-12 21:59:01 +00:00
stack ;
return 1 ;
}
2019-07-26 14:21:08 -05:00
int dev_get_direct_block_sizes ( struct device * dev , unsigned int * physical_block_size ,
unsigned int * logical_block_size )
{
int fd = dev - > bcache_fd ;
int do_close = 0 ;
unsigned int pbs = 0 ;
unsigned int lbs = 0 ;
if ( dev - > physical_block_size | | dev - > logical_block_size ) {
* physical_block_size = dev - > physical_block_size ;
* logical_block_size = dev - > logical_block_size ;
return 1 ;
}
if ( fd < = 0 ) {
2020-03-12 10:18:51 -05:00
if ( ! dev_open_readonly_quiet ( dev ) )
2019-07-26 14:21:08 -05:00
return 0 ;
fd = dev_fd ( dev ) ;
do_close = 1 ;
}
2019-08-08 15:43:09 -05:00
# ifdef BLKPBSZGET /* not defined before kernel version 2.6.32 (e.g. rhel5) */
2019-07-26 14:21:08 -05:00
/*
* BLKPBSZGET from kernel comment for blk_queue_physical_block_size :
* " the lowest possible sector size that the hardware can operate on
* without reverting to read - modify - write operations "
*/
if ( ioctl ( fd , BLKPBSZGET , & pbs ) ) {
stack ;
pbs = 0 ;
}
2019-08-08 15:43:09 -05:00
# endif
2019-07-26 14:21:08 -05:00
/*
* BLKSSZGET from kernel comment for blk_queue_logical_block_size :
* " the lowest possible block size that the storage device can address. "
*/
if ( ioctl ( fd , BLKSSZGET , & lbs ) ) {
stack ;
lbs = 0 ;
}
dev - > physical_block_size = pbs ;
dev - > logical_block_size = lbs ;
* physical_block_size = pbs ;
* logical_block_size = lbs ;
if ( do_close & & ! dev_close_immediate ( dev ) )
stack ;
return 1 ;
}
2005-05-03 17:28:23 +00:00
/*-----------------------------------------------------------------
* Public functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2016-01-15 16:41:27 +01:00
void dev_size_seqno_inc ( void )
{
_dev_size_seqno + + ;
}
2005-05-03 17:28:23 +00:00
2015-03-03 15:37:17 +01:00
int dev_get_size ( struct device * dev , uint64_t * size )
2005-05-03 17:28:23 +00:00
{
2009-01-10 02:43:51 +00:00
if ( ! dev )
return 0 ;
2005-05-03 17:28:23 +00:00
if ( ( dev - > flags & DEV_REGULAR ) )
return _dev_get_size_file ( dev , size ) ;
2017-07-19 16:16:12 +02:00
return _dev_get_size_dev ( dev , size ) ;
2005-05-03 17:28:23 +00:00
}
2009-05-20 11:09:49 +00: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-12 21:59:01 +00: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-04 22:34:56 +00:00
void dev_flush ( struct device * dev )
2002-08-14 14:58:00 +00:00
{
2003-07-04 22:34:56 +00:00
if ( ! ( dev - > flags & DEV_REGULAR ) & & ioctl ( dev - > fd , BLKFLSBUF , 0 ) > = 0 )
2003-04-28 16:20:39 +00:00
return ;
2003-07-04 22:34:56 +00:00
if ( fsync ( dev - > fd ) > = 0 )
2003-04-28 16:20:39 +00:00
return ;
sync ( ) ;
2002-06-25 14:02:28 +00:00
}
2003-07-04 22:34:56 +00:00
int dev_open_flags ( struct device * dev , int flags , int direct , int quiet )
2001-11-14 10:01:52 +00:00
{
2002-01-23 18:55:01 +00:00
struct stat buf ;
2003-07-04 22:34:56 +00:00
const char * name ;
2005-10-03 21:10:41 +00: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-24 23:16:19 +00:00
2022-02-24 16:03:21 -06:00
if ( dm_list_empty ( & dev - > aliases ) ) {
/* shouldn't happen */
log_print ( " Cannot open device %d:%d with no valid paths. " , ( int ) MAJOR ( dev - > dev ) , ( int ) MINOR ( dev - > dev ) ) ;
return 0 ;
}
name = dev_name ( dev ) ;
2003-07-04 22:34:56 +00:00
if ( dev - > fd > = 0 ) {
2005-10-03 21:10:41 +00:00
if ( ( ( dev - > flags & DEV_OPENED_RW ) | | ! need_rw ) & &
( ( dev - > flags & DEV_OPENED_EXCL ) | | ! need_excl ) ) {
2004-12-12 21:47:14 +00:00
dev - > open_count + + ;
return 1 ;
}
2017-12-12 17:56:58 +00:00
if ( dev - > open_count & & ! need_excl )
2017-11-13 14:43:32 +00:00
log_debug_devs ( " %s: Already opened read-only. Upgrading "
2022-02-24 16:03:21 -06:00
" to read-write. " , name ) ;
2017-12-12 17:56:58 +00:00
/* dev_close_immediate will decrement this */
dev - > open_count + + ;
2004-12-21 20:23:16 +00:00
2018-10-15 16:06:35 +02:00
if ( ! dev_close_immediate ( dev ) )
return_0 ;
2013-04-19 21:16:08 +02:00
// FIXME: dev with DEV_ALLOCED is released
// but code is referencing it
2002-01-24 23:16:19 +00:00
}
2001-11-14 10:01:52 +00:00
2011-02-18 14:16:11 +00:00
if ( critical_section ( ) )
2010-04-01 14:30:51 +00:00
/* FIXME Make this log_error */
2022-02-24 16:03:21 -06:00
log_verbose ( " dev_open(%s) called while suspended " , name ) ;
2001-11-14 10:01:52 +00:00
2003-11-06 17:14:06 +00:00
# ifdef O_DIRECT_SUPPORT
2005-04-07 12:17:46 +00: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 17:14:06 +00:00
# endif
2003-07-04 22:34:56 +00:00
2004-09-14 22:23:23 +00:00
# ifdef O_NOATIME
/* Don't update atime on device inodes */
2016-05-12 01:05:52 +01:00
if ( ! ( dev - > flags & DEV_REGULAR ) & & ! ( dev - > flags & DEV_NOT_O_NOATIME ) )
2004-09-14 22:23:23 +00:00
flags | = O_NOATIME ;
# endif
2003-07-04 22:34:56 +00:00
if ( ( dev - > fd = open ( name , flags , 0777 ) ) < 0 ) {
2016-05-12 01:05:52 +01: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 12:17:46 +00: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-07 22:30:29 +00:00
log_debug_devs ( " %s: Not using O_DIRECT " , name ) ;
2005-04-07 12:17:46 +00:00
goto opened ;
}
}
# endif
2005-03-03 21:54:35 +00:00
if ( quiet )
2022-02-24 16:03:21 -06:00
log_debug ( " Failed to open device path %s (%d). " , name , errno ) ;
2005-03-03 21:54:35 +00:00
else
2022-02-24 16:03:21 -06:00
log_error ( " Failed to open device path %s (%d). " , name , errno ) ;
2016-03-17 13:45:14 +01:00
dev - > flags | = DEV_OPEN_FAILURE ;
2001-11-14 10:01:52 +00:00
return 0 ;
}
2021-09-24 17:46:09 +02:00
# if defined(O_NOATIME) || defined(O_DIRECT_SUPPORT)
2005-04-07 12:25:33 +00:00
opened :
2021-09-24 17:46:09 +02:00
# endif
# ifdef O_DIRECT_SUPPORT
2005-04-07 12:17:46 +00:00
if ( direct )
dev - > flags | = DEV_O_DIRECT_TESTED ;
# endif
2005-04-07 12:25:33 +00:00
dev - > open_count + + ;
2005-10-03 21:10:41 +00:00
if ( need_rw )
2004-12-10 16:01:35 +00:00
dev - > flags | = DEV_OPENED_RW ;
else
dev - > flags & = ~ DEV_OPENED_RW ;
2003-07-04 22:34:56 +00:00
2005-10-03 21:10:41 +00:00
if ( need_excl )
dev - > flags | = DEV_OPENED_EXCL ;
else
dev - > flags & = ~ DEV_OPENED_EXCL ;
2003-07-04 22:34:56 +00:00
if ( ! ( dev - > flags & DEV_REGULAR ) & &
( ( fstat ( dev - > fd , & buf ) < 0 ) | | ( buf . st_rdev ! = dev - > dev ) ) ) {
2002-01-23 18:55:01 +00:00
log_error ( " %s: fstat failed: Has device name changed? " , name ) ;
2018-10-15 16:06:35 +02:00
if ( ! dev_close_immediate ( dev ) )
stack ;
2002-01-23 18:55:01 +00:00
return 0 ;
}
2003-11-06 17:14:06 +00:00
# ifndef O_DIRECT_SUPPORT
2003-07-04 22:34:56 +00:00
if ( ! ( dev - > flags & DEV_REGULAR ) )
dev_flush ( dev ) ;
# endif
2004-12-10 16:01:35 +00:00
if ( ( flags & O_CREAT ) & & ! ( flags & O_TRUNC ) )
2003-07-04 22:34:56 +00:00
dev - > end = lseek ( dev - > fd , ( off_t ) 0 , SEEK_END ) ;
2022-02-24 16:03:21 -06:00
if ( ! quiet ) {
log_debug_devs ( " Opened %s %s%s%s " , name ,
dev - > flags & DEV_OPENED_RW ? " RW " : " RO " ,
dev - > flags & DEV_OPENED_EXCL ? " O_EXCL " : " " ,
dev - > flags & DEV_O_DIRECT ? " O_DIRECT " : " " ) ;
}
2002-04-24 18:20:51 +00:00
2016-03-17 13:45:14 +01:00
dev - > flags & = ~ DEV_OPEN_FAILURE ;
2001-11-14 10:01:52 +00:00
return 1 ;
}
2003-07-04 22:34:56 +00:00
int dev_open_quiet ( struct device * dev )
{
2011-05-28 09:48:14 +00:00
return dev_open_flags ( dev , O_RDWR , 1 , 1 ) ;
2003-07-04 22:34:56 +00:00
}
int dev_open ( struct device * dev )
{
2011-05-28 09:48:14 +00:00
return dev_open_flags ( dev , O_RDWR , 1 , 0 ) ;
2003-07-04 22:34:56 +00:00
}
2011-05-24 13:36:57 +00: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 ) ;
}
2003-07-04 22:34:56 +00:00
static void _close ( struct device * dev )
{
if ( close ( dev - > fd ) )
2020-09-29 23:48:45 +02:00
log_sys_debug ( " close " , dev_name ( dev ) ) ;
2003-07-04 22:34:56 +00:00
dev - > fd = - 1 ;
2013-01-07 22:30:29 +00:00
log_debug_devs ( " Closed %s " , dev_name ( dev ) ) ;
2003-07-04 22:34:56 +00:00
2015-08-17 12:57:01 +01:00
if ( dev - > flags & DEV_ALLOCED )
dev_destroy_file ( dev ) ;
2003-07-04 22:34:56 +00:00
}
2003-11-14 17:55:39 +00:00
static int _dev_close ( struct device * dev , int immediate )
2001-11-14 10:01:52 +00:00
{
if ( dev - > fd < 0 ) {
2001-11-14 13:52:38 +00:00
log_error ( " Attempt to close device '%s' "
" which is not open. " , dev_name ( dev ) ) ;
2001-11-14 10:01:52 +00:00
return 0 ;
}
2003-11-06 17:14:06 +00:00
2004-12-21 20:23:16 +00:00
if ( dev - > open_count > 0 )
dev - > open_count - - ;
2005-11-23 16:07:40 +00:00
if ( immediate & & dev - > open_count )
2013-01-07 22:30:29 +00:00
log_debug_devs ( " %s: Immediate close attempt while still referenced " ,
dev_name ( dev ) ) ;
2005-10-03 21:10:41 +00:00
2018-05-11 14:28:46 -05:00
if ( immediate | | ( dev - > open_count < 1 ) )
2003-07-04 22:34:56 +00:00
_close ( dev ) ;
2001-11-14 10:01:52 +00:00
return 1 ;
}
2003-11-14 17:55:39 +00:00
int dev_close ( struct device * dev )
{
return _dev_close ( dev , 0 ) ;
}
int dev_close_immediate ( struct device * dev )
{
return _dev_close ( dev , 1 ) ;
}