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 ext4_get_inode_flags(ei); 32 flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 33 return put_user(flags, (int __user *) arg); 34 case EXT4_IOC_SETFLAGS: { 35 handle_t *handle = NULL; 36 int err; 37 struct ext4_iloc iloc; 38 unsigned int oldflags; 39 unsigned int jflag; 40 41 if (IS_RDONLY(inode)) 42 return -EROFS; 43 44 if (!is_owner_or_cap(inode)) 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 &= ~EXT4_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 & EXT4_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) & (EXT4_APPEND_FL | EXT4_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) & (EXT4_JOURNAL_DATA_FL)) { 77 if (!capable(CAP_SYS_RESOURCE)) { 78 mutex_unlock(&inode->i_mutex); 79 return -EPERM; 80 } 81 } 82 83 84 handle = ext4_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 = ext4_reserve_inode_write(handle, inode, &iloc); 92 if (err) 93 goto flags_err; 94 95 flags = flags & EXT4_FL_USER_MODIFIABLE; 96 flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 97 ei->i_flags = flags; 98 99 ext4_set_inode_flags(inode); 100 inode->i_ctime = ext4_current_time(inode); 101 102 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 103 flags_err: 104 ext4_journal_stop(handle); 105 if (err) { 106 mutex_unlock(&inode->i_mutex); 107 return err; 108 } 109 110 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 111 err = ext4_change_inode_journal_flag(inode, jflag); 112 mutex_unlock(&inode->i_mutex); 113 return err; 114 } 115 case EXT4_IOC_GETVERSION: 116 case EXT4_IOC_GETVERSION_OLD: 117 return put_user(inode->i_generation, (int __user *) arg); 118 case EXT4_IOC_SETVERSION: 119 case EXT4_IOC_SETVERSION_OLD: { 120 handle_t *handle; 121 struct ext4_iloc iloc; 122 __u32 generation; 123 int err; 124 125 if (!is_owner_or_cap(inode)) 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 = ext4_journal_start(inode, 1); 133 if (IS_ERR(handle)) 134 return PTR_ERR(handle); 135 err = ext4_reserve_inode_write(handle, inode, &iloc); 136 if (err == 0) { 137 inode->i_ctime = ext4_current_time(inode); 138 inode->i_generation = generation; 139 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 140 } 141 ext4_journal_stop(handle); 142 return err; 143 } 144 #ifdef CONFIG_JBD2_DEBUG 145 case EXT4_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(&EXT4_SB(sb)->ro_wait_queue, &wait); 160 if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { 161 schedule(); 162 ret = 1; 163 } 164 remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 165 return ret; 166 } 167 #endif 168 case EXT4_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 EXT4_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 (!is_owner_or_cap(inode)) 185 return -EACCES; 186 187 if (get_user(rsv_window_size, (int __user *)arg)) 188 return -EFAULT; 189 190 if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) 191 rsv_window_size = EXT4_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 ext4_init_block_alloc_info(inode); 200 201 if (ei->i_block_alloc_info){ 202 struct ext4_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 EXT4_IOC_GROUP_EXTEND: { 209 ext4_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 = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 223 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 224 jbd2_journal_flush(EXT4_SB(sb)->s_journal); 225 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 226 227 return err; 228 } 229 case EXT4_IOC_GROUP_ADD: { 230 struct ext4_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 ext4_new_group_input __user *)arg, 241 sizeof(input))) 242 return -EFAULT; 243 244 err = ext4_group_add(sb, &input); 245 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 246 jbd2_journal_flush(EXT4_SB(sb)->s_journal); 247 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 248 249 return err; 250 } 251 252 default: 253 return -ENOTTY; 254 } 255 } 256 257 #ifdef CONFIG_COMPAT 258 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 259 { 260 struct inode *inode = file->f_path.dentry->d_inode; 261 int ret; 262 263 /* These are just misnamed, they actually get/put from/to user an int */ 264 switch (cmd) { 265 case EXT4_IOC32_GETFLAGS: 266 cmd = EXT4_IOC_GETFLAGS; 267 break; 268 case EXT4_IOC32_SETFLAGS: 269 cmd = EXT4_IOC_SETFLAGS; 270 break; 271 case EXT4_IOC32_GETVERSION: 272 cmd = EXT4_IOC_GETVERSION; 273 break; 274 case EXT4_IOC32_SETVERSION: 275 cmd = EXT4_IOC_SETVERSION; 276 break; 277 case EXT4_IOC32_GROUP_EXTEND: 278 cmd = EXT4_IOC_GROUP_EXTEND; 279 break; 280 case EXT4_IOC32_GETVERSION_OLD: 281 cmd = EXT4_IOC_GETVERSION_OLD; 282 break; 283 case EXT4_IOC32_SETVERSION_OLD: 284 cmd = EXT4_IOC_SETVERSION_OLD; 285 break; 286 #ifdef CONFIG_JBD2_DEBUG 287 case EXT4_IOC32_WAIT_FOR_READONLY: 288 cmd = EXT4_IOC_WAIT_FOR_READONLY; 289 break; 290 #endif 291 case EXT4_IOC32_GETRSVSZ: 292 cmd = EXT4_IOC_GETRSVSZ; 293 break; 294 case EXT4_IOC32_SETRSVSZ: 295 cmd = EXT4_IOC_SETRSVSZ; 296 break; 297 case EXT4_IOC_GROUP_ADD: 298 break; 299 default: 300 return -ENOIOCTLCMD; 301 } 302 lock_kernel(); 303 ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); 304 unlock_kernel(); 305 return ret; 306 } 307 #endif 308