2005-04-17 02:20:36 +04:00
/*
* linux / fs / ioctl . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*/
# include <linux/syscalls.h>
# include <linux/mm.h>
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/file.h>
# include <linux/fs.h>
# include <linux/security.h>
# include <linux/module.h>
2008-02-07 11:13:23 +03:00
# include <linux/uaccess.h>
2008-10-04 01:32:43 +04:00
# include <linux/writeback.h>
# include <linux/buffer_head.h>
2009-06-19 22:28:07 +04:00
# include <linux/falloc.h>
2005-04-17 02:20:36 +04:00
# include <asm/ioctls.h>
2008-10-09 03:44:18 +04:00
/* So that the fiemap access checks can't overflow on 32 bit machines. */
# define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent))
2008-02-07 11:13:25 +03:00
/**
* vfs_ioctl - call filesystem specific ioctl methods
2008-02-09 11:10:16 +03:00
* @ filp : open file to invoke ioctl method on
* @ cmd : ioctl command to execute
* @ arg : command - specific argument for ioctl
2008-02-07 11:13:25 +03:00
*
* Invokes filesystem specific - > unlocked_ioctl , if one exists ; otherwise
* returns - ENOTTY .
*
* Returns 0 on success , - errno on error .
*/
2008-04-29 11:58:55 +04:00
static long vfs_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
int error = - ENOTTY ;
2010-07-04 02:15:10 +04:00
if ( ! filp - > f_op | | ! filp - > f_op - > unlocked_ioctl )
2005-04-17 02:20:36 +04:00
goto out ;
2010-07-04 02:15:10 +04:00
error = filp - > f_op - > unlocked_ioctl ( filp , cmd , arg ) ;
if ( error = = - ENOIOCTLCMD )
error = - EINVAL ;
2005-04-17 02:20:36 +04:00
out :
return error ;
}
2008-02-07 11:13:25 +03:00
static int ioctl_fibmap ( struct file * filp , int __user * p )
{
struct address_space * mapping = filp - > f_mapping ;
int res , block ;
/* do we support this mess? */
if ( ! mapping - > a_ops - > bmap )
return - EINVAL ;
if ( ! capable ( CAP_SYS_RAWIO ) )
return - EPERM ;
res = get_user ( block , p ) ;
if ( res )
return res ;
res = mapping - > a_ops - > bmap ( mapping , block ) ;
return put_user ( res , p ) ;
}
2008-10-09 03:44:18 +04:00
/**
* fiemap_fill_next_extent - Fiemap helper function
* @ fieinfo : Fiemap context passed into - > fiemap
* @ logical : Extent logical start offset , in bytes
* @ phys : Extent physical start offset , in bytes
* @ len : Extent length , in bytes
* @ flags : FIEMAP_EXTENT flags that describe this extent
*
* Called from file system - > fiemap callback . Will populate extent
* info as passed in via arguments and copy to user memory . On
* success , extent count on fieinfo is incremented .
*
* Returns 0 on success , - errno on error , 1 if this was the last
* extent that will fit in user array .
*/
# define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC)
# define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED)
# define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
int fiemap_fill_next_extent ( struct fiemap_extent_info * fieinfo , u64 logical ,
u64 phys , u64 len , u32 flags )
{
struct fiemap_extent extent ;
2011-01-16 17:28:17 +03:00
struct fiemap_extent __user * dest = fieinfo - > fi_extents_start ;
2008-10-09 03:44:18 +04:00
/* only count the extents */
if ( fieinfo - > fi_extents_max = = 0 ) {
fieinfo - > fi_extents_mapped + + ;
return ( flags & FIEMAP_EXTENT_LAST ) ? 1 : 0 ;
}
if ( fieinfo - > fi_extents_mapped > = fieinfo - > fi_extents_max )
return 1 ;
if ( flags & SET_UNKNOWN_FLAGS )
flags | = FIEMAP_EXTENT_UNKNOWN ;
if ( flags & SET_NO_UNMOUNTED_IO_FLAGS )
flags | = FIEMAP_EXTENT_ENCODED ;
if ( flags & SET_NOT_ALIGNED_FLAGS )
flags | = FIEMAP_EXTENT_NOT_ALIGNED ;
memset ( & extent , 0 , sizeof ( extent ) ) ;
extent . fe_logical = logical ;
extent . fe_physical = phys ;
extent . fe_length = len ;
extent . fe_flags = flags ;
dest + = fieinfo - > fi_extents_mapped ;
if ( copy_to_user ( dest , & extent , sizeof ( extent ) ) )
return - EFAULT ;
fieinfo - > fi_extents_mapped + + ;
if ( fieinfo - > fi_extents_mapped = = fieinfo - > fi_extents_max )
return 1 ;
return ( flags & FIEMAP_EXTENT_LAST ) ? 1 : 0 ;
}
EXPORT_SYMBOL ( fiemap_fill_next_extent ) ;
/**
* fiemap_check_flags - check validity of requested flags for fiemap
* @ fieinfo : Fiemap context passed into - > fiemap
* @ fs_flags : Set of fiemap flags that the file system understands
*
* Called from file system - > fiemap callback . This will compute the
* intersection of valid fiemap flags and those that the fs supports . That
* value is then compared against the user supplied flags . In case of bad user
* flags , the invalid values will be written into the fieinfo structure , and
* - EBADR is returned , which tells ioctl_fiemap ( ) to return those values to
* userspace . For this reason , a return code of - EBADR should be preserved .
*
* Returns 0 on success , - EBADR on bad flags .
*/
int fiemap_check_flags ( struct fiemap_extent_info * fieinfo , u32 fs_flags )
{
u32 incompat_flags ;
incompat_flags = fieinfo - > fi_flags & ~ ( FIEMAP_FLAGS_COMPAT & fs_flags ) ;
if ( incompat_flags ) {
fieinfo - > fi_flags = incompat_flags ;
return - EBADR ;
}
return 0 ;
}
EXPORT_SYMBOL ( fiemap_check_flags ) ;
static int fiemap_check_ranges ( struct super_block * sb ,
u64 start , u64 len , u64 * new_len )
{
2009-09-19 00:05:50 +04:00
u64 maxbytes = ( u64 ) sb - > s_maxbytes ;
2008-10-09 03:44:18 +04:00
* new_len = len ;
if ( len = = 0 )
return - EINVAL ;
2009-09-19 00:05:50 +04:00
if ( start > maxbytes )
2008-10-09 03:44:18 +04:00
return - EFBIG ;
/*
* Shrink request scope to what the fs can actually handle .
*/
2009-09-19 00:05:50 +04:00
if ( len > maxbytes | | ( maxbytes - len ) < start )
* new_len = maxbytes - start ;
2008-10-09 03:44:18 +04:00
return 0 ;
}
static int ioctl_fiemap ( struct file * filp , unsigned long arg )
{
struct fiemap fiemap ;
2011-01-16 17:28:17 +03:00
struct fiemap __user * ufiemap = ( struct fiemap __user * ) arg ;
2008-10-09 03:44:18 +04:00
struct fiemap_extent_info fieinfo = { 0 , } ;
struct inode * inode = filp - > f_path . dentry - > d_inode ;
struct super_block * sb = inode - > i_sb ;
u64 len ;
int error ;
if ( ! inode - > i_op - > fiemap )
return - EOPNOTSUPP ;
2011-01-16 17:28:17 +03:00
if ( copy_from_user ( & fiemap , ufiemap , sizeof ( fiemap ) ) )
2008-10-09 03:44:18 +04:00
return - EFAULT ;
if ( fiemap . fm_extent_count > FIEMAP_MAX_EXTENTS )
return - EINVAL ;
error = fiemap_check_ranges ( sb , fiemap . fm_start , fiemap . fm_length ,
& len ) ;
if ( error )
return error ;
fieinfo . fi_flags = fiemap . fm_flags ;
fieinfo . fi_extents_max = fiemap . fm_extent_count ;
2011-01-16 17:28:17 +03:00
fieinfo . fi_extents_start = ufiemap - > fm_extents ;
2008-10-09 03:44:18 +04:00
if ( fiemap . fm_extent_count ! = 0 & &
! access_ok ( VERIFY_WRITE , fieinfo . fi_extents_start ,
fieinfo . fi_extents_max * sizeof ( struct fiemap_extent ) ) )
return - EFAULT ;
if ( fieinfo . fi_flags & FIEMAP_FLAG_SYNC )
filemap_write_and_wait ( inode - > i_mapping ) ;
error = inode - > i_op - > fiemap ( inode , & fieinfo , fiemap . fm_start , len ) ;
fiemap . fm_flags = fieinfo . fi_flags ;
fiemap . fm_mapped_extents = fieinfo . fi_extents_mapped ;
2011-01-16 17:28:17 +03:00
if ( copy_to_user ( ufiemap , & fiemap , sizeof ( fiemap ) ) )
2008-10-09 03:44:18 +04:00
error = - EFAULT ;
return error ;
}
2008-10-12 08:15:19 +04:00
# ifdef CONFIG_BLOCK
2010-04-23 20:17:17 +04:00
static inline sector_t logical_to_blk ( struct inode * inode , loff_t offset )
{
return ( offset > > inode - > i_blkbits ) ;
}
static inline loff_t blk_to_logical ( struct inode * inode , sector_t blk )
{
return ( blk < < inode - > i_blkbits ) ;
}
2008-10-04 01:32:43 +04:00
2008-10-14 17:43:29 +04:00
/**
* __generic_block_fiemap - FIEMAP for block based inodes ( no locking )
2010-04-23 20:17:17 +04:00
* @ inode : the inode to map
* @ fieinfo : the fiemap info struct that will be passed back to userspace
* @ start : where to start mapping in the inode
* @ len : how much space to map
* @ get_block : the fs ' s get_block function
2008-10-04 01:32:43 +04:00
*
* This does FIEMAP for block based inodes . Basically it will just loop
* through get_block until we hit the number of extents we want to map , or we
* go past the end of the file and hit a hole .
*
* If it is possible to have data blocks beyond a hole past @ inode - > i_size , then
* please do not use this function , it will stop at the first unmapped block
2008-10-14 17:43:29 +04:00
* beyond i_size .
*
* If you use this function directly , you need to do your own locking . Use
* generic_block_fiemap if you want the locking done for you .
2008-10-04 01:32:43 +04:00
*/
2008-10-14 17:43:29 +04:00
int __generic_block_fiemap ( struct inode * inode ,
2010-04-23 20:17:17 +04:00
struct fiemap_extent_info * fieinfo , loff_t start ,
loff_t len , get_block_t * get_block )
2008-10-04 01:32:43 +04:00
{
2010-04-23 20:17:17 +04:00
struct buffer_head map_bh ;
sector_t start_blk , last_blk ;
loff_t isize = i_size_read ( inode ) ;
2008-10-04 01:32:43 +04:00
u64 logical = 0 , phys = 0 , size = 0 ;
u32 flags = FIEMAP_EXTENT_MERGED ;
2010-04-23 20:17:17 +04:00
bool past_eof = false , whole_file = false ;
int ret = 0 ;
2008-10-04 01:32:43 +04:00
2010-04-23 20:17:17 +04:00
ret = fiemap_check_flags ( fieinfo , FIEMAP_FLAG_SYNC ) ;
if ( ret )
2008-10-04 01:32:43 +04:00
return ret ;
2010-04-23 20:17:17 +04:00
/*
* Either the i_mutex or other appropriate locking needs to be held
* since we expect isize to not change at all through the duration of
* this call .
*/
if ( len > = isize ) {
whole_file = true ;
len = isize ;
}
2009-05-07 03:02:53 +04:00
2011-02-02 02:52:47 +03:00
/*
* Some filesystems can ' t deal with being asked to map less than
* blocksize , so make sure our len is at least block length .
*/
if ( logical_to_blk ( inode , len ) = = 0 )
len = blk_to_logical ( inode , 1 ) ;
2010-04-23 20:17:17 +04:00
start_blk = logical_to_blk ( inode , start ) ;
last_blk = logical_to_blk ( inode , start + len - 1 ) ;
2008-10-04 01:32:43 +04:00
do {
/*
* we set b_size to the total size we want so it will map as
* many contiguous blocks as possible at once
*/
2010-04-23 20:17:17 +04:00
memset ( & map_bh , 0 , sizeof ( struct buffer_head ) ) ;
map_bh . b_size = len ;
2008-10-04 01:32:43 +04:00
2010-04-23 20:17:17 +04:00
ret = get_block ( inode , start_blk , & map_bh , 0 ) ;
2008-10-04 01:32:43 +04:00
if ( ret )
break ;
/* HOLE */
2010-04-23 20:17:17 +04:00
if ( ! buffer_mapped ( & map_bh ) ) {
2009-05-07 03:02:53 +04:00
start_blk + + ;
/*
2010-04-23 20:17:17 +04:00
* We want to handle the case where there is an
2009-05-07 03:02:53 +04:00
* allocated block at the front of the file , and then
* nothing but holes up to the end of the file properly ,
* to make sure that extent at the front gets properly
* marked with FIEMAP_EXTENT_LAST
*/
if ( ! past_eof & &
2010-04-23 20:17:17 +04:00
blk_to_logical ( inode , start_blk ) > = isize )
2009-05-07 03:02:53 +04:00
past_eof = 1 ;
2008-10-04 01:32:43 +04:00
/*
2010-04-23 20:17:17 +04:00
* First hole after going past the EOF , this is our
2008-10-04 01:32:43 +04:00
* last extent
*/
2009-05-07 03:02:53 +04:00
if ( past_eof & & size ) {
2008-10-04 01:32:43 +04:00
flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_LAST ;
ret = fiemap_fill_next_extent ( fieinfo , logical ,
phys , size ,
flags ) ;
2010-04-23 20:17:17 +04:00
} else if ( size ) {
ret = fiemap_fill_next_extent ( fieinfo , logical ,
phys , size , flags ) ;
size = 0 ;
2008-10-04 01:32:43 +04:00
}
/* if we have holes up to/past EOF then we're done */
2010-04-23 20:17:17 +04:00
if ( start_blk > last_blk | | past_eof | | ret )
2008-10-04 01:32:43 +04:00
break ;
} else {
2009-05-07 03:02:53 +04:00
/*
2010-04-23 20:17:17 +04:00
* We have gone over the length of what we wanted to
2009-05-07 03:02:53 +04:00
* map , and it wasn ' t the entire file , so add the extent
* we got last time and exit .
*
* This is for the case where say we want to map all the
* way up to the second to the last block in a file , but
* the last block is a hole , making the second to last
* block FIEMAP_EXTENT_LAST . In this case we want to
* see if there is a hole after the second to last block
* so we can mark it properly . If we found data after
* we exceeded the length we were requesting , then we
* are good to go , just add the extent to the fieinfo
* and break
*/
2010-04-23 20:17:17 +04:00
if ( start_blk > last_blk & & ! whole_file ) {
2009-05-07 03:02:53 +04:00
ret = fiemap_fill_next_extent ( fieinfo , logical ,
phys , size ,
flags ) ;
break ;
}
/*
* if size ! = 0 then we know we already have an extent
* to add , so add it .
*/
if ( size ) {
2008-10-04 01:32:43 +04:00
ret = fiemap_fill_next_extent ( fieinfo , logical ,
phys , size ,
flags ) ;
if ( ret )
break ;
}
logical = blk_to_logical ( inode , start_blk ) ;
2010-04-23 20:17:17 +04:00
phys = blk_to_logical ( inode , map_bh . b_blocknr ) ;
size = map_bh . b_size ;
2008-10-04 01:32:43 +04:00
flags = FIEMAP_EXTENT_MERGED ;
start_blk + = logical_to_blk ( inode , size ) ;
/*
2009-05-07 03:02:53 +04:00
* If we are past the EOF , then we need to make sure as
* soon as we find a hole that the last extent we found
* is marked with FIEMAP_EXTENT_LAST
2008-10-04 01:32:43 +04:00
*/
2010-04-23 20:17:17 +04:00
if ( ! past_eof & & logical + size > = isize )
past_eof = true ;
2008-10-04 01:32:43 +04:00
}
cond_resched ( ) ;
} while ( 1 ) ;
2010-04-23 20:17:17 +04:00
/* If ret is 1 then we just hit the end of the extent array */
2008-10-04 01:32:43 +04:00
if ( ret = = 1 )
ret = 0 ;
return ret ;
}
2008-10-14 17:43:29 +04:00
EXPORT_SYMBOL ( __generic_block_fiemap ) ;
/**
* generic_block_fiemap - FIEMAP for block based inodes
* @ inode : The inode to map
* @ fieinfo : The mapping information
* @ start : The initial block to map
* @ len : The length of the extect to attempt to map
* @ get_block : The block mapping function for the fs
*
* Calls __generic_block_fiemap to map the inode , after taking
* the inode ' s mutex lock .
*/
int generic_block_fiemap ( struct inode * inode ,
struct fiemap_extent_info * fieinfo , u64 start ,
u64 len , get_block_t * get_block )
{
int ret ;
mutex_lock ( & inode - > i_mutex ) ;
ret = __generic_block_fiemap ( inode , fieinfo , start , len , get_block ) ;
mutex_unlock ( & inode - > i_mutex ) ;
return ret ;
}
2008-10-04 01:32:43 +04:00
EXPORT_SYMBOL ( generic_block_fiemap ) ;
2008-10-12 08:15:19 +04:00
# endif /* CONFIG_BLOCK */
2009-06-19 22:28:07 +04:00
/*
* This provides compatibility with legacy XFS pre - allocation ioctls
* which predate the fallocate syscall .
*
* Only the l_start , l_len and l_whence fields of the ' struct space_resv '
* are used here , rest are ignored .
*/
int ioctl_preallocate ( struct file * filp , void __user * argp )
{
struct inode * inode = filp - > f_path . dentry - > d_inode ;
struct space_resv sr ;
if ( copy_from_user ( & sr , argp , sizeof ( sr ) ) )
return - EFAULT ;
switch ( sr . l_whence ) {
case SEEK_SET :
break ;
case SEEK_CUR :
sr . l_start + = filp - > f_pos ;
break ;
case SEEK_END :
sr . l_start + = i_size_read ( inode ) ;
break ;
default :
return - EINVAL ;
}
return do_fallocate ( filp , FALLOC_FL_KEEP_SIZE , sr . l_start , sr . l_len ) ;
}
2005-04-17 02:20:36 +04:00
static int file_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
{
2008-02-07 11:13:23 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
int __user * p = ( int __user * ) arg ;
switch ( cmd ) {
2008-02-07 11:13:23 +03:00
case FIBMAP :
2008-02-07 11:13:25 +03:00
return ioctl_fibmap ( filp , p ) ;
2008-02-07 11:13:23 +03:00
case FIONREAD :
return put_user ( i_size_read ( inode ) - filp - > f_pos , p ) ;
2009-06-19 22:28:07 +04:00
case FS_IOC_RESVSP :
case FS_IOC_RESVSP64 :
return ioctl_preallocate ( filp , p ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-07 11:13:25 +03:00
return vfs_ioctl ( filp , cmd , arg ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-07 11:13:25 +03:00
static int ioctl_fionbio ( struct file * filp , int __user * argp )
{
unsigned int flag ;
int on , error ;
error = get_user ( on , argp ) ;
if ( error )
return error ;
flag = O_NONBLOCK ;
# ifdef __sparc__
/* SunOS compatibility item. */
if ( O_NONBLOCK ! = O_NDELAY )
flag | = O_NDELAY ;
# endif
2009-02-07 01:25:24 +03:00
spin_lock ( & filp - > f_lock ) ;
2008-02-07 11:13:25 +03:00
if ( on )
filp - > f_flags | = flag ;
else
filp - > f_flags & = ~ flag ;
2009-02-07 01:25:24 +03:00
spin_unlock ( & filp - > f_lock ) ;
2008-02-07 11:13:25 +03:00
return error ;
}
static int ioctl_fioasync ( unsigned int fd , struct file * filp ,
int __user * argp )
{
unsigned int flag ;
int on , error ;
error = get_user ( on , argp ) ;
if ( error )
return error ;
flag = on ? FASYNC : 0 ;
/* Did FASYNC state change ? */
if ( ( flag ^ filp - > f_flags ) & FASYNC ) {
2008-12-06 02:12:48 +03:00
if ( filp - > f_op & & filp - > f_op - > fasync )
2009-02-02 00:26:59 +03:00
/* fasync() adjusts filp->f_flags */
2008-02-07 11:13:25 +03:00
error = filp - > f_op - > fasync ( fd , filp , on ) ;
2008-12-06 02:12:48 +03:00
else
2008-02-07 11:13:25 +03:00
error = - ENOTTY ;
}
2009-02-02 00:52:56 +03:00
return error < 0 ? error : 0 ;
2008-02-07 11:13:25 +03:00
}
2009-01-10 03:40:59 +03:00
static int ioctl_fsfreeze ( struct file * filp )
{
struct super_block * sb = filp - > f_path . dentry - > d_inode - > i_sb ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
/* If filesystem doesn't support freeze feature, return. */
if ( sb - > s_op - > freeze_fs = = NULL )
return - EOPNOTSUPP ;
/* Freeze */
2010-03-23 17:34:56 +03:00
return freeze_super ( sb ) ;
2009-01-10 03:40:59 +03:00
}
static int ioctl_fsthaw ( struct file * filp )
{
struct super_block * sb = filp - > f_path . dentry - > d_inode - > i_sb ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
/* Thaw */
2010-03-23 17:34:56 +03:00
return thaw_super ( sb ) ;
2009-01-10 03:40:59 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* When you add any new common ioctls to the switches above and below
* please update compat_sys_ioctl ( ) too .
*
2008-02-07 11:13:25 +03:00
* do_vfs_ioctl ( ) is not for drivers and not intended to be EXPORT_SYMBOL ( ) ' d .
2005-04-17 02:20:36 +04:00
* It ' s just a simple helper for sys_ioctl and compat_sys_ioctl .
*/
2008-02-07 11:13:25 +03:00
int do_vfs_ioctl ( struct file * filp , unsigned int fd , unsigned int cmd ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2008-02-07 11:13:25 +03:00
int error = 0 ;
int __user * argp = ( int __user * ) arg ;
2005-04-17 02:20:36 +04:00
switch ( cmd ) {
2008-02-07 11:13:23 +03:00
case FIOCLEX :
set_close_on_exec ( fd , 1 ) ;
break ;
2005-04-17 02:20:36 +04:00
2008-02-07 11:13:23 +03:00
case FIONCLEX :
set_close_on_exec ( fd , 0 ) ;
break ;
2005-04-17 02:20:36 +04:00
2008-02-07 11:13:23 +03:00
case FIONBIO :
2008-02-07 11:13:25 +03:00
error = ioctl_fionbio ( filp , argp ) ;
2008-02-07 11:13:23 +03:00
break ;
case FIOASYNC :
2008-02-07 11:13:25 +03:00
error = ioctl_fioasync ( fd , filp , argp ) ;
2008-02-07 11:13:23 +03:00
break ;
case FIOQSIZE :
if ( S_ISDIR ( filp - > f_path . dentry - > d_inode - > i_mode ) | |
S_ISREG ( filp - > f_path . dentry - > d_inode - > i_mode ) | |
S_ISLNK ( filp - > f_path . dentry - > d_inode - > i_mode ) ) {
loff_t res =
inode_get_bytes ( filp - > f_path . dentry - > d_inode ) ;
error = copy_to_user ( ( loff_t __user * ) arg , & res ,
sizeof ( res ) ) ? - EFAULT : 0 ;
} else
error = - ENOTTY ;
break ;
2009-01-10 03:40:59 +03:00
case FIFREEZE :
error = ioctl_fsfreeze ( filp ) ;
break ;
case FITHAW :
error = ioctl_fsthaw ( filp ) ;
break ;
2009-05-14 02:12:05 +04:00
case FS_IOC_FIEMAP :
return ioctl_fiemap ( filp , arg ) ;
case FIGETBSZ :
{
struct inode * inode = filp - > f_path . dentry - > d_inode ;
int __user * p = ( int __user * ) arg ;
return put_user ( inode - > i_sb - > s_blocksize , p ) ;
}
2008-02-07 11:13:23 +03:00
default :
if ( S_ISREG ( filp - > f_path . dentry - > d_inode - > i_mode ) )
error = file_ioctl ( filp , cmd , arg ) ;
else
2008-02-07 11:13:25 +03:00
error = vfs_ioctl ( filp , cmd , arg ) ;
2008-02-07 11:13:23 +03:00
break ;
2005-04-17 02:20:36 +04:00
}
return error ;
}
2009-01-14 16:14:17 +03:00
SYSCALL_DEFINE3 ( ioctl , unsigned int , fd , unsigned int , cmd , unsigned long , arg )
2005-04-17 02:20:36 +04:00
{
2008-02-07 11:13:23 +03:00
struct file * filp ;
2005-04-17 02:20:36 +04:00
int error = - EBADF ;
int fput_needed ;
filp = fget_light ( fd , & fput_needed ) ;
if ( ! filp )
goto out ;
error = security_file_ioctl ( filp , cmd , arg ) ;
if ( error )
goto out_fput ;
2008-02-07 11:13:25 +03:00
error = do_vfs_ioctl ( filp , fd , cmd , arg ) ;
2005-04-17 02:20:36 +04:00
out_fput :
fput_light ( filp , fput_needed ) ;
out :
return error ;
}