2006-07-04 04:27:12 +04:00
/*
* linux / fs / ocfs2 / ioctl . c
*
* Copyright ( C ) 2006 Herbert Poetzl
* adapted from Remy Card ' s ext2 / ioctl . c
*/
# include <linux/fs.h>
# include <linux/mount.h>
# define MLOG_MASK_PREFIX ML_INODE
# include <cluster/masklog.h>
# include "ocfs2.h"
# include "alloc.h"
# include "dlmglue.h"
2007-03-10 03:53:21 +03:00
# include "file.h"
2006-07-04 04:27:12 +04:00
# include "inode.h"
# include "journal.h"
# include "ocfs2_fs.h"
2006-07-10 03:32:51 +04:00
# include "ioctl.h"
2007-12-18 10:47:03 +03:00
# include "resize.h"
2006-07-10 03:32:51 +04:00
2006-07-04 04:27:12 +04:00
# include <linux/ext2_fs.h>
static int ocfs2_get_inode_attr ( struct inode * inode , unsigned * flags )
{
int status ;
2007-10-19 02:30:42 +04:00
status = ocfs2_inode_lock ( inode , NULL , 0 ) ;
2006-07-04 04:27:12 +04:00
if ( status < 0 ) {
mlog_errno ( status ) ;
return status ;
}
2007-04-27 22:08:01 +04:00
ocfs2_get_inode_flags ( OCFS2_I ( inode ) ) ;
2006-07-04 04:27:12 +04:00
* flags = OCFS2_I ( inode ) - > ip_attr ;
2007-10-19 02:30:42 +04:00
ocfs2_inode_unlock ( inode , 0 ) ;
2006-07-04 04:27:12 +04:00
mlog_exit ( status ) ;
return status ;
}
static int ocfs2_set_inode_attr ( struct inode * inode , unsigned flags ,
unsigned mask )
{
struct ocfs2_inode_info * ocfs2_inode = OCFS2_I ( inode ) ;
struct ocfs2_super * osb = OCFS2_SB ( inode - > i_sb ) ;
2006-10-10 05:11:45 +04:00
handle_t * handle = NULL ;
2006-07-04 04:27:12 +04:00
struct buffer_head * bh = NULL ;
unsigned oldflags ;
int status ;
mutex_lock ( & inode - > i_mutex ) ;
2007-10-19 02:30:42 +04:00
status = ocfs2_inode_lock ( inode , & bh , 1 ) ;
2006-07-04 04:27:12 +04:00
if ( status < 0 ) {
mlog_errno ( status ) ;
goto bail ;
}
status = - EROFS ;
if ( IS_RDONLY ( inode ) )
goto bail_unlock ;
status = - EACCES ;
2007-07-17 13:30:08 +04:00
if ( ! is_owner_or_cap ( inode ) )
2006-07-04 04:27:12 +04:00
goto bail_unlock ;
if ( ! S_ISDIR ( inode - > i_mode ) )
flags & = ~ OCFS2_DIRSYNC_FL ;
2006-10-10 04:26:22 +04:00
handle = ocfs2_start_trans ( osb , OCFS2_INODE_UPDATE_CREDITS ) ;
2006-07-04 04:27:12 +04:00
if ( IS_ERR ( handle ) ) {
status = PTR_ERR ( handle ) ;
mlog_errno ( status ) ;
goto bail_unlock ;
}
oldflags = ocfs2_inode - > ip_attr ;
flags = flags & mask ;
flags | = oldflags & ~ mask ;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the relevant capability .
*/
status = - EPERM ;
if ( ( oldflags & OCFS2_IMMUTABLE_FL ) | | ( ( flags ^ oldflags ) &
( OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL ) ) ) {
if ( ! capable ( CAP_LINUX_IMMUTABLE ) )
goto bail_unlock ;
}
ocfs2_inode - > ip_attr = flags ;
ocfs2_set_inode_flags ( inode ) ;
status = ocfs2_mark_inode_dirty ( handle , inode , bh ) ;
if ( status < 0 )
mlog_errno ( status ) ;
2006-10-10 03:48:10 +04:00
ocfs2_commit_trans ( osb , handle ) ;
2006-07-04 04:27:12 +04:00
bail_unlock :
2007-10-19 02:30:42 +04:00
ocfs2_inode_unlock ( inode , 1 ) ;
2006-07-04 04:27:12 +04:00
bail :
mutex_unlock ( & inode - > i_mutex ) ;
if ( bh )
brelse ( bh ) ;
mlog_exit ( status ) ;
return status ;
}
int ocfs2_ioctl ( struct inode * inode , struct file * filp ,
unsigned int cmd , unsigned long arg )
{
unsigned int flags ;
2007-12-18 10:47:03 +03:00
int new_clusters ;
2006-07-04 04:27:12 +04:00
int status ;
2007-03-10 03:53:21 +03:00
struct ocfs2_space_resv sr ;
2007-12-18 10:47:25 +03:00
struct ocfs2_new_group_input input ;
2006-07-04 04:27:12 +04:00
switch ( cmd ) {
case OCFS2_IOC_GETFLAGS :
status = ocfs2_get_inode_attr ( inode , & flags ) ;
if ( status < 0 )
return status ;
flags & = OCFS2_FL_VISIBLE ;
return put_user ( flags , ( int __user * ) arg ) ;
case OCFS2_IOC_SETFLAGS :
if ( get_user ( flags , ( int __user * ) arg ) )
return - EFAULT ;
return ocfs2_set_inode_attr ( inode , flags ,
OCFS2_FL_MODIFIABLE ) ;
2007-03-10 03:53:21 +03:00
case OCFS2_IOC_RESVSP :
case OCFS2_IOC_RESVSP64 :
case OCFS2_IOC_UNRESVSP :
case OCFS2_IOC_UNRESVSP64 :
if ( copy_from_user ( & sr , ( int __user * ) arg , sizeof ( sr ) ) )
return - EFAULT ;
return ocfs2_change_file_space ( filp , cmd , & sr ) ;
2007-12-18 10:47:03 +03:00
case OCFS2_IOC_GROUP_EXTEND :
2007-12-19 05:58:18 +03:00
if ( ! capable ( CAP_SYS_RESOURCE ) )
return - EPERM ;
2007-12-18 10:47:03 +03:00
if ( get_user ( new_clusters , ( int __user * ) arg ) )
return - EFAULT ;
return ocfs2_group_extend ( inode , new_clusters ) ;
2007-12-18 10:47:25 +03:00
case OCFS2_IOC_GROUP_ADD :
case OCFS2_IOC_GROUP_ADD64 :
2007-12-19 05:58:18 +03:00
if ( ! capable ( CAP_SYS_RESOURCE ) )
return - EPERM ;
2007-12-18 10:47:25 +03:00
if ( copy_from_user ( & input , ( int __user * ) arg , sizeof ( input ) ) )
return - EFAULT ;
return ocfs2_group_add ( inode , & input ) ;
2006-07-04 04:27:12 +04:00
default :
return - ENOTTY ;
}
}
2007-03-10 02:56:28 +03:00
# ifdef CONFIG_COMPAT
long ocfs2_compat_ioctl ( struct file * file , unsigned cmd , unsigned long arg )
{
struct inode * inode = file - > f_path . dentry - > d_inode ;
int ret ;
switch ( cmd ) {
case OCFS2_IOC32_GETFLAGS :
cmd = OCFS2_IOC_GETFLAGS ;
break ;
case OCFS2_IOC32_SETFLAGS :
cmd = OCFS2_IOC_SETFLAGS ;
break ;
2007-03-10 03:53:21 +03:00
case OCFS2_IOC_RESVSP :
case OCFS2_IOC_RESVSP64 :
case OCFS2_IOC_UNRESVSP :
case OCFS2_IOC_UNRESVSP64 :
2007-12-18 10:47:03 +03:00
case OCFS2_IOC_GROUP_EXTEND :
2007-12-18 10:47:25 +03:00
case OCFS2_IOC_GROUP_ADD :
case OCFS2_IOC_GROUP_ADD64 :
2007-03-10 03:53:21 +03:00
break ;
2007-03-10 02:56:28 +03:00
default :
return - ENOIOCTLCMD ;
}
lock_kernel ( ) ;
ret = ocfs2_ioctl ( inode , file , cmd , arg ) ;
unlock_kernel ( ) ;
return ret ;
}
# endif