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/mount.h> 16 #include <linux/file.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 super_block *sb = inode->i_sb; 25 struct ext4_inode_info *ei = EXT4_I(inode); 26 unsigned int flags; 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, migrate = 0; 38 struct ext4_iloc iloc; 39 unsigned int oldflags; 40 unsigned int jflag; 41 42 if (!inode_owner_or_capable(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 flags = ext4_mask_flags(inode->i_mode, flags); 53 54 err = -EPERM; 55 mutex_lock(&inode->i_mutex); 56 /* Is it quota file? Do not allow user to mess with it */ 57 if (IS_NOQUOTA(inode)) 58 goto flags_out; 59 60 oldflags = ei->i_flags; 61 62 /* The JOURNAL_DATA flag is modifiable only by root */ 63 jflag = flags & EXT4_JOURNAL_DATA_FL; 64 65 /* 66 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 67 * the relevant capability. 68 * 69 * This test looks nicer. Thanks to Pauline Middelink 70 */ 71 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 72 if (!capable(CAP_LINUX_IMMUTABLE)) 73 goto flags_out; 74 } 75 76 /* 77 * The JOURNAL_DATA flag can only be changed by 78 * the relevant capability. 79 */ 80 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 81 if (!capable(CAP_SYS_RESOURCE)) 82 goto flags_out; 83 } 84 if (oldflags & EXT4_EXTENTS_FL) { 85 /* We don't support clearning extent flags */ 86 if (!(flags & EXT4_EXTENTS_FL)) { 87 err = -EOPNOTSUPP; 88 goto flags_out; 89 } 90 } else if (flags & EXT4_EXTENTS_FL) { 91 /* migrate the file */ 92 migrate = 1; 93 flags &= ~EXT4_EXTENTS_FL; 94 } 95 96 if (flags & EXT4_EOFBLOCKS_FL) { 97 /* we don't support adding EOFBLOCKS flag */ 98 if (!(oldflags & EXT4_EOFBLOCKS_FL)) { 99 err = -EOPNOTSUPP; 100 goto flags_out; 101 } 102 } else if (oldflags & EXT4_EOFBLOCKS_FL) 103 ext4_truncate(inode); 104 105 handle = ext4_journal_start(inode, 1); 106 if (IS_ERR(handle)) { 107 err = PTR_ERR(handle); 108 goto flags_out; 109 } 110 if (IS_SYNC(inode)) 111 ext4_handle_sync(handle); 112 err = ext4_reserve_inode_write(handle, inode, &iloc); 113 if (err) 114 goto flags_err; 115 116 flags = flags & EXT4_FL_USER_MODIFIABLE; 117 flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 118 ei->i_flags = flags; 119 120 ext4_set_inode_flags(inode); 121 inode->i_ctime = ext4_current_time(inode); 122 123 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 124 flags_err: 125 ext4_journal_stop(handle); 126 if (err) 127 goto flags_out; 128 129 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 130 err = ext4_change_inode_journal_flag(inode, jflag); 131 if (err) 132 goto flags_out; 133 if (migrate) 134 err = ext4_ext_migrate(inode); 135 flags_out: 136 mutex_unlock(&inode->i_mutex); 137 mnt_drop_write(filp->f_path.mnt); 138 return err; 139 } 140 case EXT4_IOC_GETVERSION: 141 case EXT4_IOC_GETVERSION_OLD: 142 return put_user(inode->i_generation, (int __user *) arg); 143 case EXT4_IOC_SETVERSION: 144 case EXT4_IOC_SETVERSION_OLD: { 145 handle_t *handle; 146 struct ext4_iloc iloc; 147 __u32 generation; 148 int err; 149 150 if (!inode_owner_or_capable(inode)) 151 return -EPERM; 152 153 err = mnt_want_write(filp->f_path.mnt); 154 if (err) 155 return err; 156 if (get_user(generation, (int __user *) arg)) { 157 err = -EFAULT; 158 goto setversion_out; 159 } 160 161 mutex_lock(&inode->i_mutex); 162 handle = ext4_journal_start(inode, 1); 163 if (IS_ERR(handle)) { 164 err = PTR_ERR(handle); 165 goto unlock_out; 166 } 167 err = ext4_reserve_inode_write(handle, inode, &iloc); 168 if (err == 0) { 169 inode->i_ctime = ext4_current_time(inode); 170 inode->i_generation = generation; 171 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 172 } 173 ext4_journal_stop(handle); 174 175 unlock_out: 176 mutex_unlock(&inode->i_mutex); 177 setversion_out: 178 mnt_drop_write(filp->f_path.mnt); 179 return err; 180 } 181 case EXT4_IOC_GROUP_EXTEND: { 182 ext4_fsblk_t n_blocks_count; 183 int err, err2=0; 184 185 err = ext4_resize_begin(sb); 186 if (err) 187 return err; 188 189 if (get_user(n_blocks_count, (__u32 __user *)arg)) 190 return -EFAULT; 191 192 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 193 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 194 ext4_msg(sb, KERN_ERR, 195 "Online resizing not supported with bigalloc"); 196 return -EOPNOTSUPP; 197 } 198 199 err = mnt_want_write(filp->f_path.mnt); 200 if (err) 201 return err; 202 203 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 204 if (EXT4_SB(sb)->s_journal) { 205 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 206 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 207 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 208 } 209 if (err == 0) 210 err = err2; 211 mnt_drop_write(filp->f_path.mnt); 212 ext4_resize_end(sb); 213 214 return err; 215 } 216 217 case EXT4_IOC_MOVE_EXT: { 218 struct move_extent me; 219 struct file *donor_filp; 220 int err; 221 222 if (!(filp->f_mode & FMODE_READ) || 223 !(filp->f_mode & FMODE_WRITE)) 224 return -EBADF; 225 226 if (copy_from_user(&me, 227 (struct move_extent __user *)arg, sizeof(me))) 228 return -EFAULT; 229 me.moved_len = 0; 230 231 donor_filp = fget(me.donor_fd); 232 if (!donor_filp) 233 return -EBADF; 234 235 if (!(donor_filp->f_mode & FMODE_WRITE)) { 236 err = -EBADF; 237 goto mext_out; 238 } 239 240 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 241 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 242 ext4_msg(sb, KERN_ERR, 243 "Online defrag not supported with bigalloc"); 244 return -EOPNOTSUPP; 245 } 246 247 err = mnt_want_write(filp->f_path.mnt); 248 if (err) 249 goto mext_out; 250 251 err = ext4_move_extents(filp, donor_filp, me.orig_start, 252 me.donor_start, me.len, &me.moved_len); 253 mnt_drop_write(filp->f_path.mnt); 254 if (me.moved_len > 0) 255 file_remove_suid(donor_filp); 256 257 if (copy_to_user((struct move_extent __user *)arg, 258 &me, sizeof(me))) 259 err = -EFAULT; 260 mext_out: 261 fput(donor_filp); 262 return err; 263 } 264 265 case EXT4_IOC_GROUP_ADD: { 266 struct ext4_new_group_data input; 267 int err, err2=0; 268 269 err = ext4_resize_begin(sb); 270 if (err) 271 return err; 272 273 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 274 sizeof(input))) 275 return -EFAULT; 276 277 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 278 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 279 ext4_msg(sb, KERN_ERR, 280 "Online resizing not supported with bigalloc"); 281 return -EOPNOTSUPP; 282 } 283 284 err = mnt_want_write(filp->f_path.mnt); 285 if (err) 286 return err; 287 288 err = ext4_group_add(sb, &input); 289 if (EXT4_SB(sb)->s_journal) { 290 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 291 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 292 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 293 } 294 if (err == 0) 295 err = err2; 296 mnt_drop_write(filp->f_path.mnt); 297 ext4_resize_end(sb); 298 299 return err; 300 } 301 302 case EXT4_IOC_MIGRATE: 303 { 304 int err; 305 if (!inode_owner_or_capable(inode)) 306 return -EACCES; 307 308 err = mnt_want_write(filp->f_path.mnt); 309 if (err) 310 return err; 311 /* 312 * inode_mutex prevent write and truncate on the file. 313 * Read still goes through. We take i_data_sem in 314 * ext4_ext_swap_inode_data before we switch the 315 * inode format to prevent read. 316 */ 317 mutex_lock(&(inode->i_mutex)); 318 err = ext4_ext_migrate(inode); 319 mutex_unlock(&(inode->i_mutex)); 320 mnt_drop_write(filp->f_path.mnt); 321 return err; 322 } 323 324 case EXT4_IOC_ALLOC_DA_BLKS: 325 { 326 int err; 327 if (!inode_owner_or_capable(inode)) 328 return -EACCES; 329 330 err = mnt_want_write(filp->f_path.mnt); 331 if (err) 332 return err; 333 err = ext4_alloc_da_blocks(inode); 334 mnt_drop_write(filp->f_path.mnt); 335 return err; 336 } 337 338 case FITRIM: 339 { 340 struct request_queue *q = bdev_get_queue(sb->s_bdev); 341 struct fstrim_range range; 342 int ret = 0; 343 344 if (!capable(CAP_SYS_ADMIN)) 345 return -EPERM; 346 347 if (!blk_queue_discard(q)) 348 return -EOPNOTSUPP; 349 350 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 351 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 352 ext4_msg(sb, KERN_ERR, 353 "FITRIM not supported with bigalloc"); 354 return -EOPNOTSUPP; 355 } 356 357 if (copy_from_user(&range, (struct fstrim_range __user *)arg, 358 sizeof(range))) 359 return -EFAULT; 360 361 range.minlen = max((unsigned int)range.minlen, 362 q->limits.discard_granularity); 363 ret = ext4_trim_fs(sb, &range); 364 if (ret < 0) 365 return ret; 366 367 if (copy_to_user((struct fstrim_range __user *)arg, &range, 368 sizeof(range))) 369 return -EFAULT; 370 371 return 0; 372 } 373 374 default: 375 return -ENOTTY; 376 } 377 } 378 379 #ifdef CONFIG_COMPAT 380 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 381 { 382 /* These are just misnamed, they actually get/put from/to user an int */ 383 switch (cmd) { 384 case EXT4_IOC32_GETFLAGS: 385 cmd = EXT4_IOC_GETFLAGS; 386 break; 387 case EXT4_IOC32_SETFLAGS: 388 cmd = EXT4_IOC_SETFLAGS; 389 break; 390 case EXT4_IOC32_GETVERSION: 391 cmd = EXT4_IOC_GETVERSION; 392 break; 393 case EXT4_IOC32_SETVERSION: 394 cmd = EXT4_IOC_SETVERSION; 395 break; 396 case EXT4_IOC32_GROUP_EXTEND: 397 cmd = EXT4_IOC_GROUP_EXTEND; 398 break; 399 case EXT4_IOC32_GETVERSION_OLD: 400 cmd = EXT4_IOC_GETVERSION_OLD; 401 break; 402 case EXT4_IOC32_SETVERSION_OLD: 403 cmd = EXT4_IOC_SETVERSION_OLD; 404 break; 405 case EXT4_IOC32_GETRSVSZ: 406 cmd = EXT4_IOC_GETRSVSZ; 407 break; 408 case EXT4_IOC32_SETRSVSZ: 409 cmd = EXT4_IOC_SETRSVSZ; 410 break; 411 case EXT4_IOC32_GROUP_ADD: { 412 struct compat_ext4_new_group_input __user *uinput; 413 struct ext4_new_group_input input; 414 mm_segment_t old_fs; 415 int err; 416 417 uinput = compat_ptr(arg); 418 err = get_user(input.group, &uinput->group); 419 err |= get_user(input.block_bitmap, &uinput->block_bitmap); 420 err |= get_user(input.inode_bitmap, &uinput->inode_bitmap); 421 err |= get_user(input.inode_table, &uinput->inode_table); 422 err |= get_user(input.blocks_count, &uinput->blocks_count); 423 err |= get_user(input.reserved_blocks, 424 &uinput->reserved_blocks); 425 if (err) 426 return -EFAULT; 427 old_fs = get_fs(); 428 set_fs(KERNEL_DS); 429 err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD, 430 (unsigned long) &input); 431 set_fs(old_fs); 432 return err; 433 } 434 case EXT4_IOC_MOVE_EXT: 435 case FITRIM: 436 break; 437 default: 438 return -ENOIOCTLCMD; 439 } 440 return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 441 } 442 #endif 443