2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
# include "xfs_fs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# include "xfs_log.h"
2005-11-02 06:38:42 +03:00
# include "xfs_inum.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans.h"
# include "xfs_sb.h"
2005-11-02 06:38:42 +03:00
# include "xfs_ag.h"
2005-04-17 02:20:36 +04:00
# include "xfs_dir2.h"
# include "xfs_alloc.h"
# include "xfs_dmapi.h"
# include "xfs_mount.h"
# include "xfs_bmap_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_alloc_btree.h"
2005-04-17 02:20:36 +04:00
# include "xfs_ialloc_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_attr_sf.h"
2005-04-17 02:20:36 +04:00
# include "xfs_dir2_sf.h"
# include "xfs_dinode.h"
# include "xfs_inode.h"
2005-11-02 06:38:42 +03:00
# include "xfs_btree.h"
# include "xfs_ialloc.h"
2005-04-17 02:20:36 +04:00
# include "xfs_rtalloc.h"
# include "xfs_itable.h"
2005-11-02 06:38:42 +03:00
# include "xfs_error.h"
2005-04-17 02:20:36 +04:00
# include "xfs_rw.h"
# include "xfs_acl.h"
# include "xfs_cap.h"
# include "xfs_mac.h"
# include "xfs_attr.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bmap.h"
2005-04-17 02:20:36 +04:00
# include "xfs_buf_item.h"
# include "xfs_utils.h"
# include "xfs_dfrag.h"
# include "xfs_fsops.h"
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/dcache.h>
# include <linux/mount.h>
# include <linux/namei.h>
# include <linux/pagemap.h>
/*
* xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
* a file or fs handle .
*
* XFS_IOC_PATH_TO_FSHANDLE
* returns fs handle for a mount point or path within that mount point
* XFS_IOC_FD_TO_HANDLE
* returns full handle for a FD opened in user space
* XFS_IOC_PATH_TO_HANDLE
* returns full handle for a path
*/
STATIC int
xfs_find_handle (
unsigned int cmd ,
void __user * arg )
{
int hsize ;
xfs_handle_t handle ;
xfs_fsop_handlereq_t hreq ;
struct inode * inode ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & hreq , arg , sizeof ( hreq ) ) )
return - XFS_ERROR ( EFAULT ) ;
memset ( ( char * ) & handle , 0 , sizeof ( handle ) ) ;
switch ( cmd ) {
case XFS_IOC_PATH_TO_FSHANDLE :
case XFS_IOC_PATH_TO_HANDLE : {
struct nameidata nd ;
int error ;
error = user_path_walk_link ( ( const char __user * ) hreq . path , & nd ) ;
if ( error )
return error ;
ASSERT ( nd . dentry ) ;
ASSERT ( nd . dentry - > d_inode ) ;
inode = igrab ( nd . dentry - > d_inode ) ;
path_release ( & nd ) ;
break ;
}
case XFS_IOC_FD_TO_HANDLE : {
struct file * file ;
file = fget ( hreq . fd ) ;
if ( ! file )
return - EBADF ;
ASSERT ( file - > f_dentry ) ;
ASSERT ( file - > f_dentry - > d_inode ) ;
inode = igrab ( file - > f_dentry - > d_inode ) ;
fput ( file ) ;
break ;
}
default :
ASSERT ( 0 ) ;
return - XFS_ERROR ( EINVAL ) ;
}
if ( inode - > i_sb - > s_magic ! = XFS_SB_MAGIC ) {
/* we're not in XFS anymore, Toto */
iput ( inode ) ;
return - XFS_ERROR ( EINVAL ) ;
}
2005-09-02 10:46:51 +04:00
switch ( inode - > i_mode & S_IFMT ) {
case S_IFREG :
case S_IFDIR :
case S_IFLNK :
break ;
default :
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
return - XFS_ERROR ( EBADF ) ;
}
2005-09-02 10:46:51 +04:00
/* we need the vnode */
2006-03-17 09:25:36 +03:00
vp = vn_from_inode ( inode ) ;
2005-09-02 10:46:51 +04:00
2005-04-17 02:20:36 +04:00
/* now we can grab the fsid */
memcpy ( & handle . ha_fsid , vp - > v_vfsp - > vfs_altfsid , sizeof ( xfs_fsid_t ) ) ;
hsize = sizeof ( xfs_fsid_t ) ;
if ( cmd ! = XFS_IOC_PATH_TO_FSHANDLE ) {
xfs_inode_t * ip ;
int lock_mode ;
/* need to get access to the xfs_inode to read the generation */
2006-01-11 12:58:44 +03:00
ip = xfs_vtoi ( vp ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( ip ) ;
lock_mode = xfs_ilock_map_shared ( ip ) ;
/* fill in fid section of handle from inode */
handle . ha_fid . xfs_fid_len = sizeof ( xfs_fid_t ) -
sizeof ( handle . ha_fid . xfs_fid_len ) ;
handle . ha_fid . xfs_fid_pad = 0 ;
handle . ha_fid . xfs_fid_gen = ip - > i_d . di_gen ;
handle . ha_fid . xfs_fid_ino = ip - > i_ino ;
xfs_iunlock_map_shared ( ip , lock_mode ) ;
hsize = XFS_HSIZE ( handle ) ;
}
/* now copy our handle into the user buffer & write out the size */
if ( copy_to_user ( hreq . ohandle , & handle , hsize ) | |
copy_to_user ( hreq . ohandlen , & hsize , sizeof ( __s32 ) ) ) {
iput ( inode ) ;
return - XFS_ERROR ( EFAULT ) ;
}
iput ( inode ) ;
return 0 ;
}
/*
* Convert userspace handle data into vnode ( and inode ) .
* We [ ab ] use the fact that all the fsop_handlereq ioctl calls
* have a data structure argument whose first component is always
* a xfs_fsop_handlereq_t , so we can cast to and from this type .
* This allows us to optimise the copy_from_user calls and gives
* a handy , shared routine .
*
* If no error , caller must always VN_RELE the returned vp .
*/
STATIC int
xfs_vget_fsop_handlereq (
xfs_mount_t * mp ,
struct inode * parinode , /* parent inode pointer */
xfs_fsop_handlereq_t * hreq ,
2006-06-09 11:00:52 +04:00
bhv_vnode_t * * vp ,
2005-04-17 02:20:36 +04:00
struct inode * * inode )
{
void __user * hanp ;
size_t hlen ;
xfs_fid_t * xfid ;
xfs_handle_t * handlep ;
xfs_handle_t handle ;
xfs_inode_t * ip ;
struct inode * inodep ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vpp ;
2005-04-17 02:20:36 +04:00
xfs_ino_t ino ;
__u32 igen ;
int error ;
/*
* Only allow handle opens under a directory .
*/
if ( ! S_ISDIR ( parinode - > i_mode ) )
return XFS_ERROR ( ENOTDIR ) ;
hanp = hreq - > ihandle ;
hlen = hreq - > ihandlen ;
handlep = & handle ;
if ( hlen < sizeof ( handlep - > ha_fsid ) | | hlen > sizeof ( * handlep ) )
return XFS_ERROR ( EINVAL ) ;
if ( copy_from_user ( handlep , hanp , hlen ) )
return XFS_ERROR ( EFAULT ) ;
if ( hlen < sizeof ( * handlep ) )
memset ( ( ( char * ) handlep ) + hlen , 0 , sizeof ( * handlep ) - hlen ) ;
if ( hlen > sizeof ( handlep - > ha_fsid ) ) {
if ( handlep - > ha_fid . xfs_fid_len ! =
( hlen - sizeof ( handlep - > ha_fsid )
- sizeof ( handlep - > ha_fid . xfs_fid_len ) )
| | handlep - > ha_fid . xfs_fid_pad )
return XFS_ERROR ( EINVAL ) ;
}
/*
* Crack the handle , obtain the inode # & generation #
*/
xfid = ( struct xfs_fid * ) & handlep - > ha_fid ;
if ( xfid - > xfs_fid_len = = sizeof ( * xfid ) - sizeof ( xfid - > xfs_fid_len ) ) {
ino = xfid - > xfs_fid_ino ;
igen = xfid - > xfs_fid_gen ;
} else {
return XFS_ERROR ( EINVAL ) ;
}
/*
* Get the XFS inode , building a vnode to go with it .
*/
error = xfs_iget ( mp , NULL , ino , 0 , XFS_ILOCK_SHARED , & ip , 0 ) ;
if ( error )
return error ;
if ( ip = = NULL )
return XFS_ERROR ( EIO ) ;
if ( ip - > i_d . di_mode = = 0 | | ip - > i_d . di_gen ! = igen ) {
xfs_iput_new ( ip , XFS_ILOCK_SHARED ) ;
return XFS_ERROR ( ENOENT ) ;
}
vpp = XFS_ITOV ( ip ) ;
2006-03-17 09:25:36 +03:00
inodep = vn_to_inode ( vpp ) ;
2005-04-17 02:20:36 +04:00
xfs_iunlock ( ip , XFS_ILOCK_SHARED ) ;
* vp = vpp ;
* inode = inodep ;
return 0 ;
}
STATIC int
xfs_open_by_handle (
xfs_mount_t * mp ,
void __user * arg ,
struct file * parfilp ,
struct inode * parinode )
{
int error ;
int new_fd ;
int permflag ;
struct file * filp ;
struct inode * inode ;
struct dentry * dentry ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
xfs_fsop_handlereq_t hreq ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - XFS_ERROR ( EPERM ) ;
if ( copy_from_user ( & hreq , arg , sizeof ( xfs_fsop_handlereq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_vget_fsop_handlereq ( mp , parinode , & hreq , & vp , & inode ) ;
if ( error )
return - error ;
/* Restrict xfs_open_by_handle to directories & regular files. */
if ( ! ( S_ISREG ( inode - > i_mode ) | | S_ISDIR ( inode - > i_mode ) ) ) {
iput ( inode ) ;
return - XFS_ERROR ( EINVAL ) ;
}
# if BITS_PER_LONG != 32
hreq . oflags | = O_LARGEFILE ;
# endif
/* Put open permission in namei format. */
permflag = hreq . oflags ;
if ( ( permflag + 1 ) & O_ACCMODE )
permflag + + ;
if ( permflag & O_TRUNC )
permflag | = 2 ;
if ( ( ! ( permflag & O_APPEND ) | | ( permflag & O_TRUNC ) ) & &
( permflag & FMODE_WRITE ) & & IS_APPEND ( inode ) ) {
iput ( inode ) ;
return - XFS_ERROR ( EPERM ) ;
}
if ( ( permflag & FMODE_WRITE ) & & IS_IMMUTABLE ( inode ) ) {
iput ( inode ) ;
return - XFS_ERROR ( EACCES ) ;
}
/* Can't write directories. */
if ( S_ISDIR ( inode - > i_mode ) & & ( permflag & FMODE_WRITE ) ) {
iput ( inode ) ;
return - XFS_ERROR ( EISDIR ) ;
}
if ( ( new_fd = get_unused_fd ( ) ) < 0 ) {
iput ( inode ) ;
return new_fd ;
}
dentry = d_alloc_anon ( inode ) ;
if ( dentry = = NULL ) {
iput ( inode ) ;
put_unused_fd ( new_fd ) ;
return - XFS_ERROR ( ENOMEM ) ;
}
/* Ensure umount returns EBUSY on umounts while this file is open. */
mntget ( parfilp - > f_vfsmnt ) ;
/* Create file pointer. */
filp = dentry_open ( dentry , parfilp - > f_vfsmnt , hreq . oflags ) ;
if ( IS_ERR ( filp ) ) {
put_unused_fd ( new_fd ) ;
return - XFS_ERROR ( - PTR_ERR ( filp ) ) ;
}
if ( inode - > i_mode & S_IFREG )
2006-03-14 06:00:35 +03:00
filp - > f_op = & xfs_invis_file_operations ;
2005-04-17 02:20:36 +04:00
fd_install ( new_fd , filp ) ;
return new_fd ;
}
STATIC int
xfs_readlink_by_handle (
xfs_mount_t * mp ,
void __user * arg ,
struct file * parfilp ,
struct inode * parinode )
{
int error ;
struct iovec aiov ;
struct uio auio ;
struct inode * inode ;
xfs_fsop_handlereq_t hreq ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
__u32 olen ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - XFS_ERROR ( EPERM ) ;
if ( copy_from_user ( & hreq , arg , sizeof ( xfs_fsop_handlereq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_vget_fsop_handlereq ( mp , parinode , & hreq , & vp , & inode ) ;
if ( error )
return - error ;
/* Restrict this handle operation to symlinks only. */
2005-09-02 10:46:51 +04:00
if ( ! S_ISLNK ( inode - > i_mode ) ) {
2005-04-17 02:20:36 +04:00
VN_RELE ( vp ) ;
return - XFS_ERROR ( EINVAL ) ;
}
if ( copy_from_user ( & olen , hreq . ohandlen , sizeof ( __u32 ) ) ) {
VN_RELE ( vp ) ;
return - XFS_ERROR ( EFAULT ) ;
}
aiov . iov_len = olen ;
aiov . iov_base = hreq . ohandle ;
auio . uio_iov = & aiov ;
auio . uio_iovcnt = 1 ;
auio . uio_offset = 0 ;
auio . uio_segflg = UIO_USERSPACE ;
auio . uio_resid = olen ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_readlink ( vp , & auio , IO_INVIS , NULL ) ;
2005-04-17 02:20:36 +04:00
VN_RELE ( vp ) ;
2006-06-09 11:00:52 +04:00
if ( error )
return - error ;
2005-04-17 02:20:36 +04:00
return ( olen - auio . uio_resid ) ;
}
STATIC int
xfs_fssetdm_by_handle (
xfs_mount_t * mp ,
void __user * arg ,
struct file * parfilp ,
struct inode * parinode )
{
int error ;
struct fsdmidata fsd ;
xfs_fsop_setdm_handlereq_t dmhreq ;
struct inode * inode ;
bhv_desc_t * bdp ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
if ( ! capable ( CAP_MKNOD ) )
return - XFS_ERROR ( EPERM ) ;
if ( copy_from_user ( & dmhreq , arg , sizeof ( xfs_fsop_setdm_handlereq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_vget_fsop_handlereq ( mp , parinode , & dmhreq . hreq , & vp , & inode ) ;
if ( error )
return - error ;
if ( IS_IMMUTABLE ( inode ) | | IS_APPEND ( inode ) ) {
VN_RELE ( vp ) ;
return - XFS_ERROR ( EPERM ) ;
}
if ( copy_from_user ( & fsd , dmhreq . data , sizeof ( fsd ) ) ) {
VN_RELE ( vp ) ;
return - XFS_ERROR ( EFAULT ) ;
}
bdp = bhv_base_unlocked ( VN_BHV_HEAD ( vp ) ) ;
error = xfs_set_dmattrs ( bdp , fsd . fsd_dmevmask , fsd . fsd_dmstate , NULL ) ;
VN_RELE ( vp ) ;
if ( error )
return - error ;
return 0 ;
}
STATIC int
xfs_attrlist_by_handle (
xfs_mount_t * mp ,
void __user * arg ,
struct file * parfilp ,
struct inode * parinode )
{
int error ;
attrlist_cursor_kern_t * cursor ;
xfs_fsop_attrlist_handlereq_t al_hreq ;
struct inode * inode ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
char * kbuf ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - XFS_ERROR ( EPERM ) ;
if ( copy_from_user ( & al_hreq , arg , sizeof ( xfs_fsop_attrlist_handlereq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( al_hreq . buflen > XATTR_LIST_MAX )
return - XFS_ERROR ( EINVAL ) ;
error = xfs_vget_fsop_handlereq ( mp , parinode , & al_hreq . hreq ,
& vp , & inode ) ;
if ( error )
goto out ;
kbuf = kmalloc ( al_hreq . buflen , GFP_KERNEL ) ;
if ( ! kbuf )
goto out_vn_rele ;
cursor = ( attrlist_cursor_kern_t * ) & al_hreq . pos ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_attr_list ( vp , kbuf , al_hreq . buflen , al_hreq . flags ,
cursor , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( error )
goto out_kfree ;
if ( copy_to_user ( al_hreq . buffer , kbuf , al_hreq . buflen ) )
error = - EFAULT ;
out_kfree :
kfree ( kbuf ) ;
out_vn_rele :
VN_RELE ( vp ) ;
out :
return - error ;
}
STATIC int
xfs_attrmulti_attr_get (
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
char * name ,
char __user * ubuf ,
__uint32_t * len ,
__uint32_t flags )
{
char * kbuf ;
int error = EFAULT ;
if ( * len > XATTR_SIZE_MAX )
return EINVAL ;
kbuf = kmalloc ( * len , GFP_KERNEL ) ;
if ( ! kbuf )
return ENOMEM ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_attr_get ( vp , name , kbuf , len , flags , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( error )
goto out_kfree ;
if ( copy_to_user ( ubuf , kbuf , * len ) )
error = EFAULT ;
out_kfree :
kfree ( kbuf ) ;
return error ;
}
STATIC int
xfs_attrmulti_attr_set (
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
char * name ,
const char __user * ubuf ,
__uint32_t len ,
__uint32_t flags )
{
char * kbuf ;
int error = EFAULT ;
2006-01-10 07:52:00 +03:00
if ( IS_RDONLY ( & vp - > v_inode ) )
return - EROFS ;
2005-04-17 02:20:36 +04:00
if ( IS_IMMUTABLE ( & vp - > v_inode ) | | IS_APPEND ( & vp - > v_inode ) )
return EPERM ;
if ( len > XATTR_SIZE_MAX )
return EINVAL ;
kbuf = kmalloc ( len , GFP_KERNEL ) ;
if ( ! kbuf )
return ENOMEM ;
if ( copy_from_user ( kbuf , ubuf , len ) )
goto out_kfree ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_attr_set ( vp , name , kbuf , len , flags , NULL ) ;
2005-04-17 02:20:36 +04:00
out_kfree :
kfree ( kbuf ) ;
return error ;
}
STATIC int
xfs_attrmulti_attr_remove (
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
char * name ,
__uint32_t flags )
{
2006-01-10 07:52:00 +03:00
if ( IS_RDONLY ( & vp - > v_inode ) )
return - EROFS ;
2005-04-17 02:20:36 +04:00
if ( IS_IMMUTABLE ( & vp - > v_inode ) | | IS_APPEND ( & vp - > v_inode ) )
return EPERM ;
2006-06-09 11:00:52 +04:00
return bhv_vop_attr_remove ( vp , name , flags , NULL ) ;
2005-04-17 02:20:36 +04:00
}
STATIC int
xfs_attrmulti_by_handle (
xfs_mount_t * mp ,
void __user * arg ,
struct file * parfilp ,
struct inode * parinode )
{
int error ;
xfs_attr_multiop_t * ops ;
xfs_fsop_attrmulti_handlereq_t am_hreq ;
struct inode * inode ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
unsigned int i , size ;
char * attr_name ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - XFS_ERROR ( EPERM ) ;
if ( copy_from_user ( & am_hreq , arg , sizeof ( xfs_fsop_attrmulti_handlereq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_vget_fsop_handlereq ( mp , parinode , & am_hreq . hreq , & vp , & inode ) ;
if ( error )
goto out ;
error = E2BIG ;
size = am_hreq . opcount * sizeof ( attr_multiop_t ) ;
if ( ! size | | size > 16 * PAGE_SIZE )
goto out_vn_rele ;
error = ENOMEM ;
ops = kmalloc ( size , GFP_KERNEL ) ;
if ( ! ops )
goto out_vn_rele ;
error = EFAULT ;
if ( copy_from_user ( ops , am_hreq . ops , size ) )
goto out_kfree_ops ;
attr_name = kmalloc ( MAXNAMELEN , GFP_KERNEL ) ;
if ( ! attr_name )
goto out_kfree_ops ;
error = 0 ;
for ( i = 0 ; i < am_hreq . opcount ; i + + ) {
ops [ i ] . am_error = strncpy_from_user ( attr_name ,
ops [ i ] . am_attrname , MAXNAMELEN ) ;
if ( ops [ i ] . am_error = = 0 | | ops [ i ] . am_error = = MAXNAMELEN )
error = - ERANGE ;
if ( ops [ i ] . am_error < 0 )
break ;
switch ( ops [ i ] . am_opcode ) {
case ATTR_OP_GET :
ops [ i ] . am_error = xfs_attrmulti_attr_get ( vp ,
attr_name , ops [ i ] . am_attrvalue ,
& ops [ i ] . am_length , ops [ i ] . am_flags ) ;
break ;
case ATTR_OP_SET :
ops [ i ] . am_error = xfs_attrmulti_attr_set ( vp ,
attr_name , ops [ i ] . am_attrvalue ,
ops [ i ] . am_length , ops [ i ] . am_flags ) ;
break ;
case ATTR_OP_REMOVE :
ops [ i ] . am_error = xfs_attrmulti_attr_remove ( vp ,
attr_name , ops [ i ] . am_flags ) ;
break ;
default :
ops [ i ] . am_error = EINVAL ;
}
}
if ( copy_to_user ( am_hreq . ops , ops , size ) )
error = XFS_ERROR ( EFAULT ) ;
kfree ( attr_name ) ;
out_kfree_ops :
kfree ( ops ) ;
out_vn_rele :
VN_RELE ( vp ) ;
out :
return - error ;
}
/* prototypes for a few of the stack-hungry cases that have
* their own functions . Functions are defined after their use
* so gcc doesn ' t get fancy and inline them with - 03 */
STATIC int
xfs_ioc_space (
bhv_desc_t * bdp ,
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
struct file * filp ,
int flags ,
unsigned int cmd ,
void __user * arg ) ;
STATIC int
xfs_ioc_bulkstat (
xfs_mount_t * mp ,
unsigned int cmd ,
void __user * arg ) ;
STATIC int
xfs_ioc_fsgeometry_v1 (
xfs_mount_t * mp ,
void __user * arg ) ;
STATIC int
xfs_ioc_fsgeometry (
xfs_mount_t * mp ,
void __user * arg ) ;
STATIC int
xfs_ioc_xattr (
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
xfs_inode_t * ip ,
struct file * filp ,
unsigned int cmd ,
void __user * arg ) ;
STATIC int
xfs_ioc_getbmap (
bhv_desc_t * bdp ,
struct file * filp ,
int flags ,
unsigned int cmd ,
void __user * arg ) ;
STATIC int
xfs_ioc_getbmapx (
bhv_desc_t * bdp ,
void __user * arg ) ;
int
xfs_ioctl (
bhv_desc_t * bdp ,
struct inode * inode ,
struct file * filp ,
int ioflags ,
unsigned int cmd ,
void __user * arg )
{
int error ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
xfs_inode_t * ip ;
xfs_mount_t * mp ;
2006-03-17 09:25:36 +03:00
vp = vn_from_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
vn_trace_entry ( vp , " xfs_ioctl " , ( inst_t * ) __return_address ) ;
ip = XFS_BHVTOI ( bdp ) ;
mp = ip - > i_mount ;
switch ( cmd ) {
case XFS_IOC_ALLOCSP :
case XFS_IOC_FREESP :
case XFS_IOC_RESVSP :
case XFS_IOC_UNRESVSP :
case XFS_IOC_ALLOCSP64 :
case XFS_IOC_FREESP64 :
case XFS_IOC_RESVSP64 :
case XFS_IOC_UNRESVSP64 :
/*
* Only allow the sys admin to reserve space unless
* unwritten extents are enabled .
*/
if ( ! XFS_SB_VERSION_HASEXTFLGBIT ( & mp - > m_sb ) & &
! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
return xfs_ioc_space ( bdp , vp , filp , ioflags , cmd , arg ) ;
case XFS_IOC_DIOINFO : {
struct dioattr da ;
xfs_buftarg_t * target =
( ip - > i_d . di_flags & XFS_DIFLAG_REALTIME ) ?
mp - > m_rtdev_targp : mp - > m_ddev_targp ;
2006-01-11 07:39:08 +03:00
da . d_mem = da . d_miniosz = 1 < < target - > bt_sshift ;
2006-01-11 07:33:51 +03:00
da . d_maxiosz = INT_MAX & ~ ( da . d_miniosz - 1 ) ;
2005-04-17 02:20:36 +04:00
if ( copy_to_user ( arg , & da , sizeof ( da ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
case XFS_IOC_FSBULKSTAT_SINGLE :
case XFS_IOC_FSBULKSTAT :
case XFS_IOC_FSINUMBERS :
return xfs_ioc_bulkstat ( mp , cmd , arg ) ;
case XFS_IOC_FSGEOMETRY_V1 :
return xfs_ioc_fsgeometry_v1 ( mp , arg ) ;
case XFS_IOC_FSGEOMETRY :
return xfs_ioc_fsgeometry ( mp , arg ) ;
case XFS_IOC_GETVERSION :
case XFS_IOC_GETXFLAGS :
case XFS_IOC_SETXFLAGS :
case XFS_IOC_FSGETXATTR :
case XFS_IOC_FSSETXATTR :
case XFS_IOC_FSGETXATTRA :
return xfs_ioc_xattr ( vp , ip , filp , cmd , arg ) ;
case XFS_IOC_FSSETDM : {
struct fsdmidata dmi ;
if ( copy_from_user ( & dmi , arg , sizeof ( dmi ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_set_dmattrs ( bdp , dmi . fsd_dmevmask , dmi . fsd_dmstate ,
NULL ) ;
return - error ;
}
case XFS_IOC_GETBMAP :
case XFS_IOC_GETBMAPA :
return xfs_ioc_getbmap ( bdp , filp , ioflags , cmd , arg ) ;
case XFS_IOC_GETBMAPX :
return xfs_ioc_getbmapx ( bdp , arg ) ;
case XFS_IOC_FD_TO_HANDLE :
case XFS_IOC_PATH_TO_HANDLE :
case XFS_IOC_PATH_TO_FSHANDLE :
return xfs_find_handle ( cmd , arg ) ;
case XFS_IOC_OPEN_BY_HANDLE :
return xfs_open_by_handle ( mp , arg , filp , inode ) ;
case XFS_IOC_FSSETDM_BY_HANDLE :
return xfs_fssetdm_by_handle ( mp , arg , filp , inode ) ;
case XFS_IOC_READLINK_BY_HANDLE :
return xfs_readlink_by_handle ( mp , arg , filp , inode ) ;
case XFS_IOC_ATTRLIST_BY_HANDLE :
return xfs_attrlist_by_handle ( mp , arg , filp , inode ) ;
case XFS_IOC_ATTRMULTI_BY_HANDLE :
return xfs_attrmulti_by_handle ( mp , arg , filp , inode ) ;
case XFS_IOC_SWAPEXT : {
error = xfs_swapext ( ( struct xfs_swapext __user * ) arg ) ;
return - error ;
}
case XFS_IOC_FSCOUNTS : {
xfs_fsop_counts_t out ;
error = xfs_fs_counts ( mp , & out ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & out , sizeof ( out ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
case XFS_IOC_SET_RESBLKS : {
xfs_fsop_resblks_t inout ;
__uint64_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & inout , arg , sizeof ( inout ) ) )
return - XFS_ERROR ( EFAULT ) ;
/* input parameter is passed in resblks field of structure */
in = inout . resblks ;
error = xfs_reserve_blocks ( mp , & in , & inout ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & inout , sizeof ( inout ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
case XFS_IOC_GET_RESBLKS : {
xfs_fsop_resblks_t out ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
error = xfs_reserve_blocks ( mp , NULL , & out ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & out , sizeof ( out ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
case XFS_IOC_FSGROWFSDATA : {
xfs_growfs_data_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & in , arg , sizeof ( in ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_growfs_data ( mp , & in ) ;
return - error ;
}
case XFS_IOC_FSGROWFSLOG : {
xfs_growfs_log_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & in , arg , sizeof ( in ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_growfs_log ( mp , & in ) ;
return - error ;
}
case XFS_IOC_FSGROWFSRT : {
xfs_growfs_rt_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & in , arg , sizeof ( in ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_growfs_rt ( mp , & in ) ;
return - error ;
}
case XFS_IOC_FREEZE :
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( inode - > i_sb - > s_frozen = = SB_UNFROZEN )
freeze_bdev ( inode - > i_sb - > s_bdev ) ;
return 0 ;
case XFS_IOC_THAW :
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( inode - > i_sb - > s_frozen ! = SB_UNFROZEN )
thaw_bdev ( inode - > i_sb - > s_bdev , inode - > i_sb ) ;
return 0 ;
case XFS_IOC_GOINGDOWN : {
__uint32_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( get_user ( in , ( __uint32_t __user * ) arg ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_fs_goingdown ( mp , in ) ;
return - error ;
}
case XFS_IOC_ERROR_INJECTION : {
xfs_error_injection_t in ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( copy_from_user ( & in , arg , sizeof ( in ) ) )
return - XFS_ERROR ( EFAULT ) ;
error = xfs_errortag_add ( in . errtag , mp ) ;
return - error ;
}
case XFS_IOC_ERROR_CLEARALL :
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
error = xfs_errortag_clearall ( mp ) ;
return - error ;
default :
return - ENOTTY ;
}
}
STATIC int
xfs_ioc_space (
bhv_desc_t * bdp ,
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
struct file * filp ,
int ioflags ,
unsigned int cmd ,
void __user * arg )
{
xfs_flock64_t bf ;
int attr_flags = 0 ;
int error ;
if ( vp - > v_inode . i_flags & ( S_IMMUTABLE | S_APPEND ) )
return - XFS_ERROR ( EPERM ) ;
2005-09-02 10:41:16 +04:00
if ( ! ( filp - > f_mode & FMODE_WRITE ) )
2005-04-17 02:20:36 +04:00
return - XFS_ERROR ( EBADF ) ;
2005-09-02 10:46:51 +04:00
if ( ! VN_ISREG ( vp ) )
2005-04-17 02:20:36 +04:00
return - XFS_ERROR ( EINVAL ) ;
if ( copy_from_user ( & bf , arg , sizeof ( bf ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( filp - > f_flags & ( O_NDELAY | O_NONBLOCK ) )
attr_flags | = ATTR_NONBLOCK ;
if ( ioflags & IO_INVIS )
attr_flags | = ATTR_DMI ;
error = xfs_change_file_space ( bdp , cmd , & bf , filp - > f_pos ,
NULL , attr_flags ) ;
return - error ;
}
STATIC int
xfs_ioc_bulkstat (
xfs_mount_t * mp ,
unsigned int cmd ,
void __user * arg )
{
xfs_fsop_bulkreq_t bulkreq ;
int count ; /* # of records returned */
xfs_ino_t inlast ; /* last inode number */
int done ;
int error ;
/* done = 1 if there are more stats to get and if bulkstat */
/* should be called again (unused here, but used in dmapi) */
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
if ( XFS_FORCED_SHUTDOWN ( mp ) )
return - XFS_ERROR ( EIO ) ;
if ( copy_from_user ( & bulkreq , arg , sizeof ( xfs_fsop_bulkreq_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( copy_from_user ( & inlast , bulkreq . lastip , sizeof ( __s64 ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( ( count = bulkreq . icount ) < = 0 )
return - XFS_ERROR ( EINVAL ) ;
if ( cmd = = XFS_IOC_FSINUMBERS )
error = xfs_inumbers ( mp , & inlast , & count ,
bulkreq . ubuffer ) ;
else if ( cmd = = XFS_IOC_FSBULKSTAT_SINGLE )
error = xfs_bulkstat_single ( mp , & inlast ,
bulkreq . ubuffer , & done ) ;
else { /* XFS_IOC_FSBULKSTAT */
if ( count = = 1 & & inlast ! = 0 ) {
inlast + + ;
error = xfs_bulkstat_single ( mp , & inlast ,
bulkreq . ubuffer , & done ) ;
} else {
error = xfs_bulkstat ( mp , & inlast , & count ,
( bulkstat_one_pf ) xfs_bulkstat_one , NULL ,
sizeof ( xfs_bstat_t ) , bulkreq . ubuffer ,
BULKSTAT_FG_QUICK , & done ) ;
}
}
if ( error )
return - error ;
if ( bulkreq . ocount ! = NULL ) {
if ( copy_to_user ( bulkreq . lastip , & inlast ,
sizeof ( xfs_ino_t ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( copy_to_user ( bulkreq . ocount , & count , sizeof ( count ) ) )
return - XFS_ERROR ( EFAULT ) ;
}
return 0 ;
}
STATIC int
xfs_ioc_fsgeometry_v1 (
xfs_mount_t * mp ,
void __user * arg )
{
xfs_fsop_geom_v1_t fsgeo ;
int error ;
error = xfs_fs_geometry ( mp , ( xfs_fsop_geom_t * ) & fsgeo , 3 ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & fsgeo , sizeof ( fsgeo ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
STATIC int
xfs_ioc_fsgeometry (
xfs_mount_t * mp ,
void __user * arg )
{
xfs_fsop_geom_t fsgeo ;
int error ;
error = xfs_fs_geometry ( mp , & fsgeo , 4 ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & fsgeo , sizeof ( fsgeo ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
/*
* Linux extended inode flags interface .
*/
# define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */
# define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */
# define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */
# define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */
# define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */
STATIC unsigned int
xfs_merge_ioc_xflags (
unsigned int flags ,
unsigned int start )
{
unsigned int xflags = start ;
if ( flags & LINUX_XFLAG_IMMUTABLE )
xflags | = XFS_XFLAG_IMMUTABLE ;
else
xflags & = ~ XFS_XFLAG_IMMUTABLE ;
if ( flags & LINUX_XFLAG_APPEND )
xflags | = XFS_XFLAG_APPEND ;
else
xflags & = ~ XFS_XFLAG_APPEND ;
if ( flags & LINUX_XFLAG_SYNC )
xflags | = XFS_XFLAG_SYNC ;
else
xflags & = ~ XFS_XFLAG_SYNC ;
if ( flags & LINUX_XFLAG_NOATIME )
xflags | = XFS_XFLAG_NOATIME ;
else
xflags & = ~ XFS_XFLAG_NOATIME ;
if ( flags & LINUX_XFLAG_NODUMP )
xflags | = XFS_XFLAG_NODUMP ;
else
xflags & = ~ XFS_XFLAG_NODUMP ;
return xflags ;
}
STATIC unsigned int
xfs_di2lxflags (
__uint16_t di_flags )
{
unsigned int flags = 0 ;
if ( di_flags & XFS_DIFLAG_IMMUTABLE )
flags | = LINUX_XFLAG_IMMUTABLE ;
if ( di_flags & XFS_DIFLAG_APPEND )
flags | = LINUX_XFLAG_APPEND ;
if ( di_flags & XFS_DIFLAG_SYNC )
flags | = LINUX_XFLAG_SYNC ;
if ( di_flags & XFS_DIFLAG_NOATIME )
flags | = LINUX_XFLAG_NOATIME ;
if ( di_flags & XFS_DIFLAG_NODUMP )
flags | = LINUX_XFLAG_NODUMP ;
return flags ;
}
STATIC int
xfs_ioc_xattr (
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ,
2005-04-17 02:20:36 +04:00
xfs_inode_t * ip ,
struct file * filp ,
unsigned int cmd ,
void __user * arg )
{
struct fsxattr fa ;
2006-06-09 11:07:12 +04:00
struct bhv_vattr * vattr ;
2006-03-14 05:33:36 +03:00
int error = 0 ;
2005-04-17 02:20:36 +04:00
int attr_flags ;
unsigned int flags ;
2006-03-14 05:33:36 +03:00
vattr = kmalloc ( sizeof ( * vattr ) , GFP_KERNEL ) ;
if ( unlikely ( ! vattr ) )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
switch ( cmd ) {
case XFS_IOC_FSGETXATTR : {
2006-03-14 05:33:36 +03:00
vattr - > va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
XFS_AT_NEXTENTS | XFS_AT_PROJID ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_getattr ( vp , vattr , 0 , NULL ) ;
2006-03-14 05:33:36 +03:00
if ( unlikely ( error ) ) {
error = - error ;
break ;
}
2005-04-17 02:20:36 +04:00
2006-03-14 05:33:36 +03:00
fa . fsx_xflags = vattr - > va_xflags ;
fa . fsx_extsize = vattr - > va_extsize ;
fa . fsx_nextents = vattr - > va_nextents ;
fa . fsx_projid = vattr - > va_projid ;
2005-04-17 02:20:36 +04:00
2006-03-14 05:33:36 +03:00
if ( copy_to_user ( arg , & fa , sizeof ( fa ) ) ) {
error = - EFAULT ;
break ;
}
break ;
2005-04-17 02:20:36 +04:00
}
case XFS_IOC_FSSETXATTR : {
2006-03-14 05:33:36 +03:00
if ( copy_from_user ( & fa , arg , sizeof ( fa ) ) ) {
error = - EFAULT ;
break ;
}
2005-04-17 02:20:36 +04:00
attr_flags = 0 ;
if ( filp - > f_flags & ( O_NDELAY | O_NONBLOCK ) )
attr_flags | = ATTR_NONBLOCK ;
2006-03-14 05:33:36 +03:00
vattr - > va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID ;
vattr - > va_xflags = fa . fsx_xflags ;
vattr - > va_extsize = fa . fsx_extsize ;
vattr - > va_projid = fa . fsx_projid ;
2005-04-17 02:20:36 +04:00
2006-06-09 11:00:52 +04:00
error = bhv_vop_setattr ( vp , vattr , attr_flags , NULL ) ;
2006-03-14 05:33:36 +03:00
if ( likely ( ! error ) )
__vn_revalidate ( vp , vattr ) ; /* update flags */
error = - error ;
break ;
2005-04-17 02:20:36 +04:00
}
case XFS_IOC_FSGETXATTRA : {
2006-03-14 05:33:36 +03:00
vattr - > va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
XFS_AT_ANEXTENTS | XFS_AT_PROJID ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_getattr ( vp , vattr , 0 , NULL ) ;
2006-03-14 05:33:36 +03:00
if ( unlikely ( error ) ) {
error = - error ;
break ;
}
2005-04-17 02:20:36 +04:00
2006-03-14 05:33:36 +03:00
fa . fsx_xflags = vattr - > va_xflags ;
fa . fsx_extsize = vattr - > va_extsize ;
fa . fsx_nextents = vattr - > va_anextents ;
fa . fsx_projid = vattr - > va_projid ;
2005-04-17 02:20:36 +04:00
2006-03-14 05:33:36 +03:00
if ( copy_to_user ( arg , & fa , sizeof ( fa ) ) ) {
error = - EFAULT ;
break ;
}
break ;
2005-04-17 02:20:36 +04:00
}
case XFS_IOC_GETXFLAGS : {
flags = xfs_di2lxflags ( ip - > i_d . di_flags ) ;
if ( copy_to_user ( arg , & flags , sizeof ( flags ) ) )
2006-03-14 05:33:36 +03:00
error = - EFAULT ;
break ;
2005-04-17 02:20:36 +04:00
}
case XFS_IOC_SETXFLAGS : {
2006-03-14 05:33:36 +03:00
if ( copy_from_user ( & flags , arg , sizeof ( flags ) ) ) {
error = - EFAULT ;
break ;
}
2005-04-17 02:20:36 +04:00
if ( flags & ~ ( LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \
LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \
2006-03-14 05:33:36 +03:00
LINUX_XFLAG_SYNC ) ) {
error = - EOPNOTSUPP ;
break ;
}
2005-04-17 02:20:36 +04:00
attr_flags = 0 ;
if ( filp - > f_flags & ( O_NDELAY | O_NONBLOCK ) )
attr_flags | = ATTR_NONBLOCK ;
2006-03-14 05:33:36 +03:00
vattr - > va_mask = XFS_AT_XFLAGS ;
vattr - > va_xflags = xfs_merge_ioc_xflags ( flags ,
xfs_ip2xflags ( ip ) ) ;
2005-04-17 02:20:36 +04:00
2006-06-09 11:00:52 +04:00
error = bhv_vop_setattr ( vp , vattr , attr_flags , NULL ) ;
2006-03-14 05:33:36 +03:00
if ( likely ( ! error ) )
__vn_revalidate ( vp , vattr ) ; /* update flags */
error = - error ;
break ;
2005-04-17 02:20:36 +04:00
}
case XFS_IOC_GETVERSION : {
2006-03-17 09:25:36 +03:00
flags = vn_to_inode ( vp ) - > i_generation ;
2005-04-17 02:20:36 +04:00
if ( copy_to_user ( arg , & flags , sizeof ( flags ) ) )
2006-03-14 05:33:36 +03:00
error = - EFAULT ;
break ;
2005-04-17 02:20:36 +04:00
}
default :
2006-03-14 05:33:36 +03:00
error = - ENOTTY ;
break ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 05:33:36 +03:00
kfree ( vattr ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
STATIC int
xfs_ioc_getbmap (
bhv_desc_t * bdp ,
struct file * filp ,
int ioflags ,
unsigned int cmd ,
void __user * arg )
{
struct getbmap bm ;
int iflags ;
int error ;
if ( copy_from_user ( & bm , arg , sizeof ( bm ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( bm . bmv_count < 2 )
return - XFS_ERROR ( EINVAL ) ;
iflags = ( cmd = = XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0 ) ;
if ( ioflags & IO_INVIS )
iflags | = BMV_IF_NO_DMAPI_READ ;
error = xfs_getbmap ( bdp , & bm , ( struct getbmap __user * ) arg + 1 , iflags ) ;
if ( error )
return - error ;
if ( copy_to_user ( arg , & bm , sizeof ( bm ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}
STATIC int
xfs_ioc_getbmapx (
bhv_desc_t * bdp ,
void __user * arg )
{
struct getbmapx bmx ;
struct getbmap bm ;
int iflags ;
int error ;
if ( copy_from_user ( & bmx , arg , sizeof ( bmx ) ) )
return - XFS_ERROR ( EFAULT ) ;
if ( bmx . bmv_count < 2 )
return - XFS_ERROR ( EINVAL ) ;
/*
* Map input getbmapx structure to a getbmap
* structure for xfs_getbmap .
*/
GETBMAP_CONVERT ( bmx , bm ) ;
iflags = bmx . bmv_iflags ;
if ( iflags & ( ~ BMV_IF_VALID ) )
return - XFS_ERROR ( EINVAL ) ;
iflags | = BMV_IF_EXTENDED ;
error = xfs_getbmap ( bdp , & bm , ( struct getbmapx __user * ) arg + 1 , iflags ) ;
if ( error )
return - error ;
GETBMAP_CONVERT ( bm , bmx ) ;
if ( copy_to_user ( arg , & bmx , sizeof ( bmx ) ) )
return - XFS_ERROR ( EFAULT ) ;
return 0 ;
}