1/* 2 * linux/fs/ext3/ioctl.c 3 * 4 * Copyright (C) 1993, 1994, 1995 5 * Remy Card (card@masi.ibp.fr) 6 * Laboratoire MASI - Institut Blaise Pascal 7 * Universite Pierre et Marie Curie (Paris VI) 8 */ 9 10#include <linux/fs.h> 11#include <linux/jbd.h> 12#include <linux/capability.h> 13#include <linux/ext3_fs.h> 14#include <linux/ext3_jbd.h> 15#include <linux/time.h> 16#include <linux/compat.h> 17#include <linux/smp_lock.h> 18#include <asm/uaccess.h> 19 20int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 21 unsigned long arg) 22{ 23 struct ext3_inode_info *ei = EXT3_I(inode); 24 unsigned int flags; 25 unsigned short rsv_window_size; 26 27 ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); 28 29 switch (cmd) { 30 case EXT3_IOC_GETFLAGS: 31 ext3_get_inode_flags(ei); 32 flags = ei->i_flags & EXT3_FL_USER_VISIBLE; 33 return put_user(flags, (int __user *) arg); 34 case EXT3_IOC_SETFLAGS: { 35 handle_t *handle = NULL; 36 int err; 37 struct ext3_iloc iloc; 38 unsigned int oldflags; 39 unsigned int jflag; 40 41 if (IS_RDONLY(inode)) 42 return -EROFS; 43 44 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 45 return -EACCES; 46 47 if (get_user(flags, (int __user *) arg)) 48 return -EFAULT; 49 50 if (!S_ISDIR(inode->i_mode)) 51 flags &= ~EXT3_DIRSYNC_FL; 52 53 mutex_lock(&inode->i_mutex); 54 oldflags = ei->i_flags; 55 56 /* The JOURNAL_DATA flag is modifiable only by root */ 57 jflag = flags & EXT3_JOURNAL_DATA_FL; 58 59 /* 60 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 61 * the relevant capability. 62 * 63 * This test looks nicer. Thanks to Pauline Middelink 64 */ 65 if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { 66 if (!capable(CAP_LINUX_IMMUTABLE)) { 67 mutex_unlock(&inode->i_mutex); 68 return -EPERM; 69 } 70 } 71 72 /* 73 * The JOURNAL_DATA flag can only be changed by 74 * the relevant capability. 75 */ 76 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { 77 if (!capable(CAP_SYS_RESOURCE)) { 78 mutex_unlock(&inode->i_mutex); 79 return -EPERM; 80 } 81 } 82 83 84 handle = ext3_journal_start(inode, 1); 85 if (IS_ERR(handle)) { 86 mutex_unlock(&inode->i_mutex); 87 return PTR_ERR(handle); 88 } 89 if (IS_SYNC(inode)) 90 handle->h_sync = 1; 91 err = ext3_reserve_inode_write(handle, inode, &iloc); 92 if (err) 93 goto flags_err; 94 95 flags = flags & EXT3_FL_USER_MODIFIABLE; 96 flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; 97 ei->i_flags = flags; 98 99 ext3_set_inode_flags(inode); 100 inode->i_ctime = CURRENT_TIME_SEC; 101 102 err = ext3_mark_iloc_dirty(handle, inode, &iloc); 103flags_err: 104 ext3_journal_stop(handle); 105 if (err) { 106 mutex_unlock(&inode->i_mutex); 107 return err; 108 } 109 110 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) 111 err = ext3_change_inode_journal_flag(inode, jflag); 112 mutex_unlock(&inode->i_mutex); 113 return err; 114 } 115 case EXT3_IOC_GETVERSION: 116 case EXT3_IOC_GETVERSION_OLD: 117 return put_user(inode->i_generation, (int __user *) arg); 118 case EXT3_IOC_SETVERSION: 119 case EXT3_IOC_SETVERSION_OLD: { 120 handle_t *handle; 121 struct ext3_iloc iloc; 122 __u32 generation; 123 int err; 124 125 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 126 return -EPERM; 127 if (IS_RDONLY(inode)) 128 return -EROFS; 129 if (get_user(generation, (int __user *) arg)) 130 return -EFAULT; 131 132 handle = ext3_journal_start(inode, 1); 133 if (IS_ERR(handle)) 134 return PTR_ERR(handle); 135 err = ext3_reserve_inode_write(handle, inode, &iloc); 136 if (err == 0) { 137 inode->i_ctime = CURRENT_TIME_SEC; 138 inode->i_generation = generation; 139 err = ext3_mark_iloc_dirty(handle, inode, &iloc); 140 } 141 ext3_journal_stop(handle); 142 return err; 143 } 144#ifdef CONFIG_JBD_DEBUG 145 case EXT3_IOC_WAIT_FOR_READONLY: 146 /* 147 * This is racy - by the time we're woken up and running, 148 * the superblock could be released. And the module could 149 * have been unloaded. So sue me. 150 * 151 * Returns 1 if it slept, else zero. 152 */ 153 { 154 struct super_block *sb = inode->i_sb; 155 DECLARE_WAITQUEUE(wait, current); 156 int ret = 0; 157 158 set_current_state(TASK_INTERRUPTIBLE); 159 add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); 160 if (timer_pending(&EXT3_SB(sb)->turn_ro_timer)) { 161 schedule(); 162 ret = 1; 163 } 164 remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); 165 return ret; 166 } 167#endif 168 case EXT3_IOC_GETRSVSZ: 169 if (test_opt(inode->i_sb, RESERVATION) 170 && S_ISREG(inode->i_mode) 171 && ei->i_block_alloc_info) { 172 rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 173 return put_user(rsv_window_size, (int __user *)arg); 174 } 175 return -ENOTTY; 176 case EXT3_IOC_SETRSVSZ: { 177 178 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 179 return -ENOTTY; 180 181 if (IS_RDONLY(inode)) 182 return -EROFS; 183 184 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 185 return -EACCES; 186 187 if (get_user(rsv_window_size, (int __user *)arg)) 188 return -EFAULT; 189 190 if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) 191 rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; 192 193 /* 194 * need to allocate reservation structure for this inode 195 * before set the window size 196 */ 197 mutex_lock(&ei->truncate_mutex); 198 if (!ei->i_block_alloc_info) 199 ext3_init_block_alloc_info(inode); 200 201 if (ei->i_block_alloc_info){ 202 struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 203 rsv->rsv_goal_size = rsv_window_size; 204 } 205 mutex_unlock(&ei->truncate_mutex); 206 return 0; 207 } 208 case EXT3_IOC_GROUP_EXTEND: { 209 ext3_fsblk_t n_blocks_count; 210 struct super_block *sb = inode->i_sb; 211 int err; 212 213 if (!capable(CAP_SYS_RESOURCE)) 214 return -EPERM; 215 216 if (IS_RDONLY(inode)) 217 return -EROFS; 218 219 if (get_user(n_blocks_count, (__u32 __user *)arg)) 220 return -EFAULT; 221 222 err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); 223 journal_lock_updates(EXT3_SB(sb)->s_journal); 224 journal_flush(EXT3_SB(sb)->s_journal); 225 journal_unlock_updates(EXT3_SB(sb)->s_journal); 226 227 return err; 228 } 229 case EXT3_IOC_GROUP_ADD: { 230 struct ext3_new_group_data input; 231 struct super_block *sb = inode->i_sb; 232 int err; 233 234 if (!capable(CAP_SYS_RESOURCE)) 235 return -EPERM; 236 237 if (IS_RDONLY(inode)) 238 return -EROFS; 239 240 if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, 241 sizeof(input))) 242 return -EFAULT; 243 244 err = ext3_group_add(sb, &input); 245 journal_lock_updates(EXT3_SB(sb)->s_journal); 246 journal_flush(EXT3_SB(sb)->s_journal); 247 journal_unlock_updates(EXT3_SB(sb)->s_journal); 248 249 return err; 250 } 251 252 253 default: 254 return -ENOTTY; 255 } 256} 257 258#ifdef CONFIG_COMPAT 259long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 260{ 261 struct inode *inode = file->f_path.dentry->d_inode; 262 int ret; 263 264 /* These are just misnamed, they actually get/put from/to user an int */ 265 switch (cmd) { 266 case EXT3_IOC32_GETFLAGS: 267 cmd = EXT3_IOC_GETFLAGS; 268 break; 269 case EXT3_IOC32_SETFLAGS: 270 cmd = EXT3_IOC_SETFLAGS; 271 break; 272 case EXT3_IOC32_GETVERSION: 273 cmd = EXT3_IOC_GETVERSION; 274 break; 275 case EXT3_IOC32_SETVERSION: 276 cmd = EXT3_IOC_SETVERSION; 277 break; 278 case EXT3_IOC32_GROUP_EXTEND: 279 cmd = EXT3_IOC_GROUP_EXTEND; 280 break; 281 case EXT3_IOC32_GETVERSION_OLD: 282 cmd = EXT3_IOC_GETVERSION_OLD; 283 break; 284 case EXT3_IOC32_SETVERSION_OLD: 285 cmd = EXT3_IOC_SETVERSION_OLD; 286 break; 287#ifdef CONFIG_JBD_DEBUG 288 case EXT3_IOC32_WAIT_FOR_READONLY: 289 cmd = EXT3_IOC_WAIT_FOR_READONLY; 290 break; 291#endif 292 case EXT3_IOC32_GETRSVSZ: 293 cmd = EXT3_IOC_GETRSVSZ; 294 break; 295 case EXT3_IOC32_SETRSVSZ: 296 cmd = EXT3_IOC_SETRSVSZ; 297 break; 298 case EXT3_IOC_GROUP_ADD: 299 break; 300 default: 301 return -ENOIOCTLCMD; 302 } 303 lock_kernel(); 304 ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); 305 unlock_kernel(); 306 return ret; 307} 308#endif 309