2009-10-06 22:31:14 +04:00
# include <linux/in.h>
# include "super.h"
2010-04-07 02:14:15 +04:00
# include "mds_client.h"
# include <linux/ceph/ceph_debug.h>
# include "ioctl.h"
2009-10-06 22:31:14 +04:00
/*
* ioctls
*/
/*
* get and set the file layout
*/
static long ceph_ioctl_get_layout ( struct file * file , void __user * arg )
{
struct ceph_inode_info * ci = ceph_inode ( file - > f_dentry - > d_inode ) ;
struct ceph_ioctl_layout l ;
int err ;
err = ceph_do_getattr ( file - > f_dentry - > d_inode , CEPH_STAT_CAP_LAYOUT ) ;
if ( ! err ) {
l . stripe_unit = ceph_file_layout_su ( ci - > i_layout ) ;
l . stripe_count = ceph_file_layout_stripe_count ( ci - > i_layout ) ;
l . object_size = ceph_file_layout_object_size ( ci - > i_layout ) ;
l . data_pool = le32_to_cpu ( ci - > i_layout . fl_pg_pool ) ;
2009-12-03 01:42:39 +03:00
l . preferred_osd =
( s32 ) le32_to_cpu ( ci - > i_layout . fl_pg_preferred ) ;
2009-10-06 22:31:14 +04:00
if ( copy_to_user ( arg , & l , sizeof ( l ) ) )
return - EFAULT ;
}
return err ;
}
static long ceph_ioctl_set_layout ( struct file * file , void __user * arg )
{
struct inode * inode = file - > f_dentry - > d_inode ;
2011-07-26 22:30:29 +04:00
struct inode * parent_inode ;
2010-04-07 02:14:15 +04:00
struct ceph_mds_client * mdsc = ceph_sb_to_client ( inode - > i_sb ) - > mdsc ;
2009-10-06 22:31:14 +04:00
struct ceph_mds_request * req ;
struct ceph_ioctl_layout l ;
2011-08-25 23:43:06 +04:00
struct ceph_inode_info * ci = ceph_inode ( file - > f_dentry - > d_inode ) ;
struct ceph_ioctl_layout nl ;
2009-10-06 22:31:14 +04:00
int err , i ;
if ( copy_from_user ( & l , arg , sizeof ( l ) ) )
return - EFAULT ;
2011-08-25 23:43:06 +04:00
/* validate changed params against current layout */
err = ceph_do_getattr ( file - > f_dentry - > d_inode , CEPH_STAT_CAP_LAYOUT ) ;
if ( ! err ) {
nl . stripe_unit = ceph_file_layout_su ( ci - > i_layout ) ;
nl . stripe_count = ceph_file_layout_stripe_count ( ci - > i_layout ) ;
nl . object_size = ceph_file_layout_object_size ( ci - > i_layout ) ;
nl . data_pool = le32_to_cpu ( ci - > i_layout . fl_pg_pool ) ;
nl . preferred_osd =
( s32 ) le32_to_cpu ( ci - > i_layout . fl_pg_preferred ) ;
} else
return err ;
if ( l . stripe_count )
nl . stripe_count = l . stripe_count ;
if ( l . stripe_unit )
nl . stripe_unit = l . stripe_unit ;
if ( l . object_size )
nl . object_size = l . object_size ;
if ( l . data_pool )
nl . data_pool = l . data_pool ;
if ( l . preferred_osd )
nl . preferred_osd = l . preferred_osd ;
if ( ( nl . object_size & ~ PAGE_MASK ) | |
( nl . stripe_unit & ~ PAGE_MASK ) | |
( ( unsigned ) nl . object_size % ( unsigned ) nl . stripe_unit ) )
2009-10-06 22:31:14 +04:00
return - EINVAL ;
/* make sure it's a valid data pool */
if ( l . data_pool > 0 ) {
mutex_lock ( & mdsc - > mutex ) ;
err = - EINVAL ;
for ( i = 0 ; i < mdsc - > mdsmap - > m_num_data_pg_pools ; i + + )
if ( mdsc - > mdsmap - > m_data_pg_pools [ i ] = = l . data_pool ) {
err = 0 ;
break ;
}
mutex_unlock ( & mdsc - > mutex ) ;
if ( err )
return err ;
}
req = ceph_mdsc_create_request ( mdsc , CEPH_MDS_OP_SETLAYOUT ,
USE_AUTH_MDS ) ;
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2011-05-27 20:24:26 +04:00
req - > r_inode = inode ;
ihold ( inode ) ;
2009-10-06 22:31:14 +04:00
req - > r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL ;
req - > r_args . setlayout . layout . fl_stripe_unit =
cpu_to_le32 ( l . stripe_unit ) ;
req - > r_args . setlayout . layout . fl_stripe_count =
cpu_to_le32 ( l . stripe_count ) ;
req - > r_args . setlayout . layout . fl_object_size =
cpu_to_le32 ( l . object_size ) ;
req - > r_args . setlayout . layout . fl_pg_pool = cpu_to_le32 ( l . data_pool ) ;
2009-12-03 01:42:39 +03:00
req - > r_args . setlayout . layout . fl_pg_preferred =
cpu_to_le32 ( l . preferred_osd ) ;
2009-10-06 22:31:14 +04:00
2011-07-26 22:30:29 +04:00
parent_inode = ceph_get_dentry_parent_inode ( file - > f_dentry ) ;
2009-10-06 22:31:14 +04:00
err = ceph_mdsc_do_request ( mdsc , parent_inode , req ) ;
2011-07-26 22:30:29 +04:00
iput ( parent_inode ) ;
2009-10-06 22:31:14 +04:00
ceph_mdsc_put_request ( req ) ;
return err ;
}
2010-09-25 01:56:40 +04:00
/*
* Set a layout policy on a directory inode . All items in the tree
* rooted at this inode will inherit this layout on creation ,
* ( It doesn ' t apply retroactively )
* unless a subdirectory has its own layout policy .
*/
static long ceph_ioctl_set_layout_policy ( struct file * file , void __user * arg )
{
struct inode * inode = file - > f_dentry - > d_inode ;
struct ceph_mds_request * req ;
struct ceph_ioctl_layout l ;
int err , i ;
struct ceph_mds_client * mdsc = ceph_sb_to_client ( inode - > i_sb ) - > mdsc ;
/* copy and validate */
if ( copy_from_user ( & l , arg , sizeof ( l ) ) )
return - EFAULT ;
if ( ( l . object_size & ~ PAGE_MASK ) | |
( l . stripe_unit & ~ PAGE_MASK ) | |
! l . stripe_unit | |
( l . object_size & &
( unsigned ) l . object_size % ( unsigned ) l . stripe_unit ) )
return - EINVAL ;
/* make sure it's a valid data pool */
if ( l . data_pool > 0 ) {
mutex_lock ( & mdsc - > mutex ) ;
err = - EINVAL ;
for ( i = 0 ; i < mdsc - > mdsmap - > m_num_data_pg_pools ; i + + )
if ( mdsc - > mdsmap - > m_data_pg_pools [ i ] = = l . data_pool ) {
err = 0 ;
break ;
}
mutex_unlock ( & mdsc - > mutex ) ;
if ( err )
return err ;
}
req = ceph_mdsc_create_request ( mdsc , CEPH_MDS_OP_SETDIRLAYOUT ,
USE_AUTH_MDS ) ;
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
2011-05-27 20:24:26 +04:00
req - > r_inode = inode ;
ihold ( inode ) ;
2010-09-25 01:56:40 +04:00
req - > r_args . setlayout . layout . fl_stripe_unit =
cpu_to_le32 ( l . stripe_unit ) ;
req - > r_args . setlayout . layout . fl_stripe_count =
cpu_to_le32 ( l . stripe_count ) ;
req - > r_args . setlayout . layout . fl_object_size =
cpu_to_le32 ( l . object_size ) ;
req - > r_args . setlayout . layout . fl_pg_pool =
cpu_to_le32 ( l . data_pool ) ;
req - > r_args . setlayout . layout . fl_pg_preferred =
cpu_to_le32 ( l . preferred_osd ) ;
err = ceph_mdsc_do_request ( mdsc , inode , req ) ;
ceph_mdsc_put_request ( req ) ;
return err ;
}
2009-10-06 22:31:14 +04:00
/*
* Return object name , size / offset information , and location ( OSD
* number , network address ) for a given file offset .
*/
static long ceph_ioctl_get_dataloc ( struct file * file , void __user * arg )
{
struct ceph_ioctl_dataloc dl ;
struct inode * inode = file - > f_dentry - > d_inode ;
struct ceph_inode_info * ci = ceph_inode ( inode ) ;
2010-04-07 02:14:15 +04:00
struct ceph_osd_client * osdc =
& ceph_sb_to_client ( inode - > i_sb ) - > client - > osdc ;
2009-10-06 22:31:14 +04:00
u64 len = 1 , olen ;
u64 tmp ;
struct ceph_object_layout ol ;
2009-11-04 22:39:12 +03:00
struct ceph_pg pgid ;
2009-10-06 22:31:14 +04:00
/* copy and validate */
if ( copy_from_user ( & dl , arg , sizeof ( dl ) ) )
return - EFAULT ;
down_read ( & osdc - > map_sem ) ;
ceph_calc_file_object_mapping ( & ci - > i_layout , dl . file_offset , & len ,
& dl . object_no , & dl . object_offset , & olen ) ;
dl . file_offset - = dl . object_offset ;
dl . object_size = ceph_file_layout_object_size ( ci - > i_layout ) ;
dl . block_size = ceph_file_layout_su ( ci - > i_layout ) ;
/* block_offset = object_offset % block_size */
tmp = dl . object_offset ;
dl . block_offset = do_div ( tmp , dl . block_size ) ;
snprintf ( dl . object_name , sizeof ( dl . object_name ) , " %llx.%08llx " ,
ceph_ino ( inode ) , dl . object_no ) ;
ceph_calc_object_layout ( & ol , dl . object_name , & ci - > i_layout ,
osdc - > osdmap ) ;
2009-11-04 22:39:12 +03:00
pgid = ol . ol_pgid ;
2009-10-06 22:31:14 +04:00
dl . osd = ceph_calc_pg_primary ( osdc - > osdmap , pgid ) ;
if ( dl . osd > = 0 ) {
struct ceph_entity_addr * a =
ceph_osd_addr ( osdc - > osdmap , dl . osd ) ;
if ( a )
memcpy ( & dl . osd_addr , & a - > in_addr , sizeof ( dl . osd_addr ) ) ;
} else {
memset ( & dl . osd_addr , 0 , sizeof ( dl . osd_addr ) ) ;
}
up_read ( & osdc - > map_sem ) ;
/* send result back to user */
if ( copy_to_user ( arg , & dl , sizeof ( dl ) ) )
return - EFAULT ;
return 0 ;
}
2010-04-16 20:53:43 +04:00
static long ceph_ioctl_lazyio ( struct file * file )
{
struct ceph_file_info * fi = file - > private_data ;
struct inode * inode = file - > f_dentry - > d_inode ;
struct ceph_inode_info * ci = ceph_inode ( inode ) ;
if ( ( fi - > fmode & CEPH_FILE_MODE_LAZY ) = = 0 ) {
2011-11-30 21:47:09 +04:00
spin_lock ( & ci - > i_ceph_lock ) ;
2010-04-16 20:53:43 +04:00
ci - > i_nr_by_mode [ fi - > fmode ] - - ;
fi - > fmode | = CEPH_FILE_MODE_LAZY ;
ci - > i_nr_by_mode [ fi - > fmode ] + + ;
2011-11-30 21:47:09 +04:00
spin_unlock ( & ci - > i_ceph_lock ) ;
2010-04-16 20:53:43 +04:00
dout ( " ioctl_layzio: file %p marked lazy \n " , file ) ;
ceph_check_caps ( ci , 0 , NULL ) ;
} else {
dout ( " ioctl_layzio: file %p already lazy \n " , file ) ;
}
return 0 ;
}
2011-07-26 22:26:07 +04:00
static long ceph_ioctl_syncio ( struct file * file )
{
struct ceph_file_info * fi = file - > private_data ;
fi - > flags | = CEPH_F_SYNC ;
return 0 ;
}
2009-10-06 22:31:14 +04:00
long ceph_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
dout ( " ioctl file %p cmd %u arg %lu \n " , file , cmd , arg ) ;
switch ( cmd ) {
case CEPH_IOC_GET_LAYOUT :
return ceph_ioctl_get_layout ( file , ( void __user * ) arg ) ;
case CEPH_IOC_SET_LAYOUT :
return ceph_ioctl_set_layout ( file , ( void __user * ) arg ) ;
2010-09-25 01:56:40 +04:00
case CEPH_IOC_SET_LAYOUT_POLICY :
return ceph_ioctl_set_layout_policy ( file , ( void __user * ) arg ) ;
2009-10-06 22:31:14 +04:00
case CEPH_IOC_GET_DATALOC :
return ceph_ioctl_get_dataloc ( file , ( void __user * ) arg ) ;
2010-04-16 20:53:43 +04:00
case CEPH_IOC_LAZYIO :
return ceph_ioctl_lazyio ( file ) ;
2011-07-26 22:26:07 +04:00
case CEPH_IOC_SYNCIO :
return ceph_ioctl_syncio ( file ) ;
2009-10-06 22:31:14 +04:00
}
2010-09-25 01:56:40 +04:00
2009-10-06 22:31:14 +04:00
return - ENOTTY ;
}