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