1 /* 2 * linux/fs/ext4/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/jbd2.h> 12 #include <linux/capability.h> 13 #include <linux/ext4_fs.h> 14 #include <linux/ext4_jbd2.h> 15 #include <linux/time.h> 16 #include <linux/compat.h> 17 #include <linux/smp_lock.h> 18 #include <asm/uaccess.h> 19 20 int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 21 unsigned long arg) 22 { 23 struct ext4_inode_info *ei = EXT4_I(inode); 24 unsigned int flags; 25 unsigned short rsv_window_size; 26 27 ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg); 28 29 switch (cmd) { 30 case EXT4_IOC_GETFLAGS: 31 flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 32 return put_user(flags, (int __user *) arg); 33 case EXT4_IOC_SETFLAGS: { 34 handle_t *handle = NULL; 35 int err; 36 struct ext4_iloc iloc; 37 unsigned int oldflags; 38 unsigned int jflag; 39 40 if (IS_RDONLY(inode)) 41 return -EROFS; 42 43 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 44 return -EACCES; 45 46 if (get_user(flags, (int __user *) arg)) 47 return -EFAULT; 48 49 if (!S_ISDIR(inode->i_mode)) 50 flags &= ~EXT4_DIRSYNC_FL; 51 52 mutex_lock(&inode->i_mutex); 53 oldflags = ei->i_flags; 54 55 /* The JOURNAL_DATA flag is modifiable only by root */ 56 jflag = flags & EXT4_JOURNAL_DATA_FL; 57 58 /* 59 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 60 * the relevant capability. 61 * 62 * This test looks nicer. Thanks to Pauline Middelink 63 */ 64 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 65 if (!capable(CAP_LINUX_IMMUTABLE)) { 66 mutex_unlock(&inode->i_mutex); 67 return -EPERM; 68 } 69 } 70 71 /* 72 * The JOURNAL_DATA flag can only be changed by 73 * the relevant capability. 74 */ 75 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 76 if (!capable(CAP_SYS_RESOURCE)) { 77 mutex_unlock(&inode->i_mutex); 78 return -EPERM; 79 } 80 } 81 82 83 handle = ext4_journal_start(inode, 1); 84 if (IS_ERR(handle)) { 85 mutex_unlock(&inode->i_mutex); 86 return PTR_ERR(handle); 87 } 88 if (IS_SYNC(inode)) 89 handle->h_sync = 1; 90 err = ext4_reserve_inode_write(handle, inode, &iloc); 91 if (err) 92 goto flags_err; 93 94 flags = flags & EXT4_FL_USER_MODIFIABLE; 95 flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 96 ei->i_flags = flags; 97 98 ext4_set_inode_flags(inode); 99 inode->i_ctime = CURRENT_TIME_SEC; 100 101 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 102 flags_err: 103 ext4_journal_stop(handle); 104 if (err) { 105 mutex_unlock(&inode->i_mutex); 106 return err; 107 } 108 109 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 110 err = ext4_change_inode_journal_flag(inode, jflag); 111 mutex_unlock(&inode->i_mutex); 112 return err; 113 } 114 case EXT4_IOC_GETVERSION: 115 case EXT4_IOC_GETVERSION_OLD: 116 return put_user(inode->i_generation, (int __user *) arg); 117 case EXT4_IOC_SETVERSION: 118 case EXT4_IOC_SETVERSION_OLD: { 119 handle_t *handle; 120 struct ext4_iloc iloc; 121 __u32 generation; 122 int err; 123 124 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 125 return -EPERM; 126 if (IS_RDONLY(inode)) 127 return -EROFS; 128 if (get_user(generation, (int __user *) arg)) 129 return -EFAULT; 130 131 handle = ext4_journal_start(inode, 1); 132 if (IS_ERR(handle)) 133 return PTR_ERR(handle); 134 err = ext4_reserve_inode_write(handle, inode, &iloc); 135 if (err == 0) { 136 inode->i_ctime = CURRENT_TIME_SEC; 137 inode->i_generation = generation; 138 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 139 } 140 ext4_journal_stop(handle); 141 return err; 142 } 143 #ifdef CONFIG_JBD_DEBUG 144 case EXT4_IOC_WAIT_FOR_READONLY: 145 /* 146 * This is racy - by the time we're woken up and running, 147 * the superblock could be released. And the module could 148 * have been unloaded. So sue me. 149 * 150 * Returns 1 if it slept, else zero. 151 */ 152 { 153 struct super_block *sb = inode->i_sb; 154 DECLARE_WAITQUEUE(wait, current); 155 int ret = 0; 156 157 set_current_state(TASK_INTERRUPTIBLE); 158 add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 159 if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { 160 schedule(); 161 ret = 1; 162 } 163 remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 164 return ret; 165 } 166 #endif 167 case EXT4_IOC_GETRSVSZ: 168 if (test_opt(inode->i_sb, RESERVATION) 169 && S_ISREG(inode->i_mode) 170 && ei->i_block_alloc_info) { 171 rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 172 return put_user(rsv_window_size, (int __user *)arg); 173 } 174 return -ENOTTY; 175 case EXT4_IOC_SETRSVSZ: { 176 177 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 178 return -ENOTTY; 179 180 if (IS_RDONLY(inode)) 181 return -EROFS; 182 183 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 184 return -EACCES; 185 186 if (get_user(rsv_window_size, (int __user *)arg)) 187 return -EFAULT; 188 189 if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) 190 rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; 191 192 /* 193 * need to allocate reservation structure for this inode 194 * before set the window size 195 */ 196 mutex_lock(&ei->truncate_mutex); 197 if (!ei->i_block_alloc_info) 198 ext4_init_block_alloc_info(inode); 199 200 if (ei->i_block_alloc_info){ 201 struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 202 rsv->rsv_goal_size = rsv_window_size; 203 } 204 mutex_unlock(&ei->truncate_mutex); 205 return 0; 206 } 207 case EXT4_IOC_GROUP_EXTEND: { 208 ext4_fsblk_t n_blocks_count; 209 struct super_block *sb = inode->i_sb; 210 int err; 211 212 if (!capable(CAP_SYS_RESOURCE)) 213 return -EPERM; 214 215 if (IS_RDONLY(inode)) 216 return -EROFS; 217 218 if (get_user(n_blocks_count, (__u32 __user *)arg)) 219 return -EFAULT; 220 221 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 222 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 223 jbd2_journal_flush(EXT4_SB(sb)->s_journal); 224 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 225 226 return err; 227 } 228 case EXT4_IOC_GROUP_ADD: { 229 struct ext4_new_group_data input; 230 struct super_block *sb = inode->i_sb; 231 int err; 232 233 if (!capable(CAP_SYS_RESOURCE)) 234 return -EPERM; 235 236 if (IS_RDONLY(inode)) 237 return -EROFS; 238 239 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 240 sizeof(input))) 241 return -EFAULT; 242 243 err = ext4_group_add(sb, &input); 244 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 245 jbd2_journal_flush(EXT4_SB(sb)->s_journal); 246 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 247 248 return err; 249 } 250 251 default: 252 return -ENOTTY; 253 } 254 } 255 256 #ifdef CONFIG_COMPAT 257 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 258 { 259 struct inode *inode = file->f_path.dentry->d_inode; 260 int ret; 261 262 /* These are just misnamed, they actually get/put from/to user an int */ 263 switch (cmd) { 264 case EXT4_IOC32_GETFLAGS: 265 cmd = EXT4_IOC_GETFLAGS; 266 break; 267 case EXT4_IOC32_SETFLAGS: 268 cmd = EXT4_IOC_SETFLAGS; 269 break; 270 case EXT4_IOC32_GETVERSION: 271 cmd = EXT4_IOC_GETVERSION; 272 break; 273 case EXT4_IOC32_SETVERSION: 274 cmd = EXT4_IOC_SETVERSION; 275 break; 276 case EXT4_IOC32_GROUP_EXTEND: 277 cmd = EXT4_IOC_GROUP_EXTEND; 278 break; 279 case EXT4_IOC32_GETVERSION_OLD: 280 cmd = EXT4_IOC_GETVERSION_OLD; 281 break; 282 case EXT4_IOC32_SETVERSION_OLD: 283 cmd = EXT4_IOC_SETVERSION_OLD; 284 break; 285 #ifdef CONFIG_JBD_DEBUG 286 case EXT4_IOC32_WAIT_FOR_READONLY: 287 cmd = EXT4_IOC_WAIT_FOR_READONLY; 288 break; 289 #endif 290 case EXT4_IOC32_GETRSVSZ: 291 cmd = EXT4_IOC_GETRSVSZ; 292 break; 293 case EXT4_IOC32_SETRSVSZ: 294 cmd = EXT4_IOC_SETRSVSZ; 295 break; 296 case EXT4_IOC_GROUP_ADD: 297 break; 298 default: 299 return -ENOIOCTLCMD; 300 } 301 lock_kernel(); 302 ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); 303 unlock_kernel(); 304 return ret; 305 } 306 #endif 307