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/capability.h> 12 #include <linux/time.h> 13 #include <linux/compat.h> 14 #include <linux/mount.h> 15 #include <linux/file.h> 16 #include <linux/random.h> 17 #include <asm/uaccess.h> 18 #include "ext4_jbd2.h" 19 #include "ext4.h" 20 21 #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1) 22 23 /** 24 * Swap memory between @a and @b for @len bytes. 25 * 26 * @a: pointer to first memory area 27 * @b: pointer to second memory area 28 * @len: number of bytes to swap 29 * 30 */ 31 static void memswap(void *a, void *b, size_t len) 32 { 33 unsigned char *ap, *bp; 34 35 ap = (unsigned char *)a; 36 bp = (unsigned char *)b; 37 while (len-- > 0) { 38 swap(*ap, *bp); 39 ap++; 40 bp++; 41 } 42 } 43 44 /** 45 * Swap i_data and associated attributes between @inode1 and @inode2. 46 * This function is used for the primary swap between inode1 and inode2 47 * and also to revert this primary swap in case of errors. 48 * 49 * Therefore you have to make sure, that calling this method twice 50 * will revert all changes. 51 * 52 * @inode1: pointer to first inode 53 * @inode2: pointer to second inode 54 */ 55 static void swap_inode_data(struct inode *inode1, struct inode *inode2) 56 { 57 loff_t isize; 58 struct ext4_inode_info *ei1; 59 struct ext4_inode_info *ei2; 60 61 ei1 = EXT4_I(inode1); 62 ei2 = EXT4_I(inode2); 63 64 memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags)); 65 memswap(&inode1->i_version, &inode2->i_version, 66 sizeof(inode1->i_version)); 67 memswap(&inode1->i_blocks, &inode2->i_blocks, 68 sizeof(inode1->i_blocks)); 69 memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes)); 70 memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime)); 71 memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime)); 72 73 memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data)); 74 memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags)); 75 memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize)); 76 ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS); 77 ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS); 78 79 isize = i_size_read(inode1); 80 i_size_write(inode1, i_size_read(inode2)); 81 i_size_write(inode2, isize); 82 } 83 84 /** 85 * Swap the information from the given @inode and the inode 86 * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other 87 * important fields of the inodes. 88 * 89 * @sb: the super block of the filesystem 90 * @inode: the inode to swap with EXT4_BOOT_LOADER_INO 91 * 92 */ 93 static long swap_inode_boot_loader(struct super_block *sb, 94 struct inode *inode) 95 { 96 handle_t *handle; 97 int err; 98 struct inode *inode_bl; 99 struct ext4_inode_info *ei_bl; 100 struct ext4_sb_info *sbi = EXT4_SB(sb); 101 102 if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) 103 return -EINVAL; 104 105 if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) 106 return -EPERM; 107 108 inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); 109 if (IS_ERR(inode_bl)) 110 return PTR_ERR(inode_bl); 111 ei_bl = EXT4_I(inode_bl); 112 113 filemap_flush(inode->i_mapping); 114 filemap_flush(inode_bl->i_mapping); 115 116 /* Protect orig inodes against a truncate and make sure, 117 * that only 1 swap_inode_boot_loader is running. */ 118 lock_two_nondirectories(inode, inode_bl); 119 120 truncate_inode_pages(&inode->i_data, 0); 121 truncate_inode_pages(&inode_bl->i_data, 0); 122 123 /* Wait for all existing dio workers */ 124 ext4_inode_block_unlocked_dio(inode); 125 ext4_inode_block_unlocked_dio(inode_bl); 126 inode_dio_wait(inode); 127 inode_dio_wait(inode_bl); 128 129 handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); 130 if (IS_ERR(handle)) { 131 err = -EINVAL; 132 goto journal_err_out; 133 } 134 135 /* Protect extent tree against block allocations via delalloc */ 136 ext4_double_down_write_data_sem(inode, inode_bl); 137 138 if (inode_bl->i_nlink == 0) { 139 /* this inode has never been used as a BOOT_LOADER */ 140 set_nlink(inode_bl, 1); 141 i_uid_write(inode_bl, 0); 142 i_gid_write(inode_bl, 0); 143 inode_bl->i_flags = 0; 144 ei_bl->i_flags = 0; 145 inode_bl->i_version = 1; 146 i_size_write(inode_bl, 0); 147 inode_bl->i_mode = S_IFREG; 148 if (EXT4_HAS_INCOMPAT_FEATURE(sb, 149 EXT4_FEATURE_INCOMPAT_EXTENTS)) { 150 ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS); 151 ext4_ext_tree_init(handle, inode_bl); 152 } else 153 memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); 154 } 155 156 swap_inode_data(inode, inode_bl); 157 158 inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode); 159 160 spin_lock(&sbi->s_next_gen_lock); 161 inode->i_generation = sbi->s_next_generation++; 162 inode_bl->i_generation = sbi->s_next_generation++; 163 spin_unlock(&sbi->s_next_gen_lock); 164 165 ext4_discard_preallocations(inode); 166 167 err = ext4_mark_inode_dirty(handle, inode); 168 if (err < 0) { 169 ext4_warning(inode->i_sb, 170 "couldn't mark inode #%lu dirty (err %d)", 171 inode->i_ino, err); 172 /* Revert all changes: */ 173 swap_inode_data(inode, inode_bl); 174 } else { 175 err = ext4_mark_inode_dirty(handle, inode_bl); 176 if (err < 0) { 177 ext4_warning(inode_bl->i_sb, 178 "couldn't mark inode #%lu dirty (err %d)", 179 inode_bl->i_ino, err); 180 /* Revert all changes: */ 181 swap_inode_data(inode, inode_bl); 182 ext4_mark_inode_dirty(handle, inode); 183 } 184 } 185 ext4_journal_stop(handle); 186 ext4_double_up_write_data_sem(inode, inode_bl); 187 188 journal_err_out: 189 ext4_inode_resume_unlocked_dio(inode); 190 ext4_inode_resume_unlocked_dio(inode_bl); 191 unlock_two_nondirectories(inode, inode_bl); 192 iput(inode_bl); 193 return err; 194 } 195 196 static int uuid_is_zero(__u8 u[16]) 197 { 198 int i; 199 200 for (i = 0; i < 16; i++) 201 if (u[i]) 202 return 0; 203 return 1; 204 } 205 206 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 207 { 208 struct inode *inode = file_inode(filp); 209 struct super_block *sb = inode->i_sb; 210 struct ext4_inode_info *ei = EXT4_I(inode); 211 unsigned int flags; 212 213 ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); 214 215 switch (cmd) { 216 case EXT4_IOC_GETFLAGS: 217 ext4_get_inode_flags(ei); 218 flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 219 return put_user(flags, (int __user *) arg); 220 case EXT4_IOC_SETFLAGS: { 221 handle_t *handle = NULL; 222 int err, migrate = 0; 223 struct ext4_iloc iloc; 224 unsigned int oldflags, mask, i; 225 unsigned int jflag; 226 227 if (!inode_owner_or_capable(inode)) 228 return -EACCES; 229 230 if (get_user(flags, (int __user *) arg)) 231 return -EFAULT; 232 233 err = mnt_want_write_file(filp); 234 if (err) 235 return err; 236 237 flags = ext4_mask_flags(inode->i_mode, flags); 238 239 err = -EPERM; 240 mutex_lock(&inode->i_mutex); 241 /* Is it quota file? Do not allow user to mess with it */ 242 if (IS_NOQUOTA(inode)) 243 goto flags_out; 244 245 oldflags = ei->i_flags; 246 247 /* The JOURNAL_DATA flag is modifiable only by root */ 248 jflag = flags & EXT4_JOURNAL_DATA_FL; 249 250 /* 251 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 252 * the relevant capability. 253 * 254 * This test looks nicer. Thanks to Pauline Middelink 255 */ 256 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 257 if (!capable(CAP_LINUX_IMMUTABLE)) 258 goto flags_out; 259 } 260 261 /* 262 * The JOURNAL_DATA flag can only be changed by 263 * the relevant capability. 264 */ 265 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 266 if (!capable(CAP_SYS_RESOURCE)) 267 goto flags_out; 268 } 269 if ((flags ^ oldflags) & EXT4_EXTENTS_FL) 270 migrate = 1; 271 272 if (flags & EXT4_EOFBLOCKS_FL) { 273 /* we don't support adding EOFBLOCKS flag */ 274 if (!(oldflags & EXT4_EOFBLOCKS_FL)) { 275 err = -EOPNOTSUPP; 276 goto flags_out; 277 } 278 } else if (oldflags & EXT4_EOFBLOCKS_FL) 279 ext4_truncate(inode); 280 281 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 282 if (IS_ERR(handle)) { 283 err = PTR_ERR(handle); 284 goto flags_out; 285 } 286 if (IS_SYNC(inode)) 287 ext4_handle_sync(handle); 288 err = ext4_reserve_inode_write(handle, inode, &iloc); 289 if (err) 290 goto flags_err; 291 292 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { 293 if (!(mask & EXT4_FL_USER_MODIFIABLE)) 294 continue; 295 if (mask & flags) 296 ext4_set_inode_flag(inode, i); 297 else 298 ext4_clear_inode_flag(inode, i); 299 } 300 301 ext4_set_inode_flags(inode); 302 inode->i_ctime = ext4_current_time(inode); 303 304 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 305 flags_err: 306 ext4_journal_stop(handle); 307 if (err) 308 goto flags_out; 309 310 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 311 err = ext4_change_inode_journal_flag(inode, jflag); 312 if (err) 313 goto flags_out; 314 if (migrate) { 315 if (flags & EXT4_EXTENTS_FL) 316 err = ext4_ext_migrate(inode); 317 else 318 err = ext4_ind_migrate(inode); 319 } 320 321 flags_out: 322 mutex_unlock(&inode->i_mutex); 323 mnt_drop_write_file(filp); 324 return err; 325 } 326 case EXT4_IOC_GETVERSION: 327 case EXT4_IOC_GETVERSION_OLD: 328 return put_user(inode->i_generation, (int __user *) arg); 329 case EXT4_IOC_SETVERSION: 330 case EXT4_IOC_SETVERSION_OLD: { 331 handle_t *handle; 332 struct ext4_iloc iloc; 333 __u32 generation; 334 int err; 335 336 if (!inode_owner_or_capable(inode)) 337 return -EPERM; 338 339 if (ext4_has_metadata_csum(inode->i_sb)) { 340 ext4_warning(sb, "Setting inode version is not " 341 "supported with metadata_csum enabled."); 342 return -ENOTTY; 343 } 344 345 err = mnt_want_write_file(filp); 346 if (err) 347 return err; 348 if (get_user(generation, (int __user *) arg)) { 349 err = -EFAULT; 350 goto setversion_out; 351 } 352 353 mutex_lock(&inode->i_mutex); 354 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 355 if (IS_ERR(handle)) { 356 err = PTR_ERR(handle); 357 goto unlock_out; 358 } 359 err = ext4_reserve_inode_write(handle, inode, &iloc); 360 if (err == 0) { 361 inode->i_ctime = ext4_current_time(inode); 362 inode->i_generation = generation; 363 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 364 } 365 ext4_journal_stop(handle); 366 367 unlock_out: 368 mutex_unlock(&inode->i_mutex); 369 setversion_out: 370 mnt_drop_write_file(filp); 371 return err; 372 } 373 case EXT4_IOC_GROUP_EXTEND: { 374 ext4_fsblk_t n_blocks_count; 375 int err, err2=0; 376 377 err = ext4_resize_begin(sb); 378 if (err) 379 return err; 380 381 if (get_user(n_blocks_count, (__u32 __user *)arg)) { 382 err = -EFAULT; 383 goto group_extend_out; 384 } 385 386 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 387 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 388 ext4_msg(sb, KERN_ERR, 389 "Online resizing not supported with bigalloc"); 390 err = -EOPNOTSUPP; 391 goto group_extend_out; 392 } 393 394 err = mnt_want_write_file(filp); 395 if (err) 396 goto group_extend_out; 397 398 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 399 if (EXT4_SB(sb)->s_journal) { 400 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 401 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 402 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 403 } 404 if (err == 0) 405 err = err2; 406 mnt_drop_write_file(filp); 407 group_extend_out: 408 ext4_resize_end(sb); 409 return err; 410 } 411 412 case EXT4_IOC_MOVE_EXT: { 413 struct move_extent me; 414 struct fd donor; 415 int err; 416 417 if (!(filp->f_mode & FMODE_READ) || 418 !(filp->f_mode & FMODE_WRITE)) 419 return -EBADF; 420 421 if (copy_from_user(&me, 422 (struct move_extent __user *)arg, sizeof(me))) 423 return -EFAULT; 424 me.moved_len = 0; 425 426 donor = fdget(me.donor_fd); 427 if (!donor.file) 428 return -EBADF; 429 430 if (!(donor.file->f_mode & FMODE_WRITE)) { 431 err = -EBADF; 432 goto mext_out; 433 } 434 435 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 436 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 437 ext4_msg(sb, KERN_ERR, 438 "Online defrag not supported with bigalloc"); 439 err = -EOPNOTSUPP; 440 goto mext_out; 441 } 442 443 err = mnt_want_write_file(filp); 444 if (err) 445 goto mext_out; 446 447 err = ext4_move_extents(filp, donor.file, me.orig_start, 448 me.donor_start, me.len, &me.moved_len); 449 mnt_drop_write_file(filp); 450 451 if (copy_to_user((struct move_extent __user *)arg, 452 &me, sizeof(me))) 453 err = -EFAULT; 454 mext_out: 455 fdput(donor); 456 return err; 457 } 458 459 case EXT4_IOC_GROUP_ADD: { 460 struct ext4_new_group_data input; 461 int err, err2=0; 462 463 err = ext4_resize_begin(sb); 464 if (err) 465 return err; 466 467 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 468 sizeof(input))) { 469 err = -EFAULT; 470 goto group_add_out; 471 } 472 473 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 474 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 475 ext4_msg(sb, KERN_ERR, 476 "Online resizing not supported with bigalloc"); 477 err = -EOPNOTSUPP; 478 goto group_add_out; 479 } 480 481 err = mnt_want_write_file(filp); 482 if (err) 483 goto group_add_out; 484 485 err = ext4_group_add(sb, &input); 486 if (EXT4_SB(sb)->s_journal) { 487 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 488 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 489 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 490 } 491 if (err == 0) 492 err = err2; 493 mnt_drop_write_file(filp); 494 if (!err && ext4_has_group_desc_csum(sb) && 495 test_opt(sb, INIT_INODE_TABLE)) 496 err = ext4_register_li_request(sb, input.group); 497 group_add_out: 498 ext4_resize_end(sb); 499 return err; 500 } 501 502 case EXT4_IOC_MIGRATE: 503 { 504 int err; 505 if (!inode_owner_or_capable(inode)) 506 return -EACCES; 507 508 err = mnt_want_write_file(filp); 509 if (err) 510 return err; 511 /* 512 * inode_mutex prevent write and truncate on the file. 513 * Read still goes through. We take i_data_sem in 514 * ext4_ext_swap_inode_data before we switch the 515 * inode format to prevent read. 516 */ 517 mutex_lock(&(inode->i_mutex)); 518 err = ext4_ext_migrate(inode); 519 mutex_unlock(&(inode->i_mutex)); 520 mnt_drop_write_file(filp); 521 return err; 522 } 523 524 case EXT4_IOC_ALLOC_DA_BLKS: 525 { 526 int err; 527 if (!inode_owner_or_capable(inode)) 528 return -EACCES; 529 530 err = mnt_want_write_file(filp); 531 if (err) 532 return err; 533 err = ext4_alloc_da_blocks(inode); 534 mnt_drop_write_file(filp); 535 return err; 536 } 537 538 case EXT4_IOC_SWAP_BOOT: 539 { 540 int err; 541 if (!(filp->f_mode & FMODE_WRITE)) 542 return -EBADF; 543 err = mnt_want_write_file(filp); 544 if (err) 545 return err; 546 err = swap_inode_boot_loader(sb, inode); 547 mnt_drop_write_file(filp); 548 return err; 549 } 550 551 case EXT4_IOC_RESIZE_FS: { 552 ext4_fsblk_t n_blocks_count; 553 int err = 0, err2 = 0; 554 ext4_group_t o_group = EXT4_SB(sb)->s_groups_count; 555 556 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 557 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 558 ext4_msg(sb, KERN_ERR, 559 "Online resizing not (yet) supported with bigalloc"); 560 return -EOPNOTSUPP; 561 } 562 563 if (copy_from_user(&n_blocks_count, (__u64 __user *)arg, 564 sizeof(__u64))) { 565 return -EFAULT; 566 } 567 568 err = ext4_resize_begin(sb); 569 if (err) 570 return err; 571 572 err = mnt_want_write_file(filp); 573 if (err) 574 goto resizefs_out; 575 576 err = ext4_resize_fs(sb, n_blocks_count); 577 if (EXT4_SB(sb)->s_journal) { 578 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 579 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 580 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 581 } 582 if (err == 0) 583 err = err2; 584 mnt_drop_write_file(filp); 585 if (!err && (o_group > EXT4_SB(sb)->s_groups_count) && 586 ext4_has_group_desc_csum(sb) && 587 test_opt(sb, INIT_INODE_TABLE)) 588 err = ext4_register_li_request(sb, o_group); 589 590 resizefs_out: 591 ext4_resize_end(sb); 592 return err; 593 } 594 595 case FITRIM: 596 { 597 struct request_queue *q = bdev_get_queue(sb->s_bdev); 598 struct fstrim_range range; 599 int ret = 0; 600 601 if (!capable(CAP_SYS_ADMIN)) 602 return -EPERM; 603 604 if (!blk_queue_discard(q)) 605 return -EOPNOTSUPP; 606 607 if (copy_from_user(&range, (struct fstrim_range __user *)arg, 608 sizeof(range))) 609 return -EFAULT; 610 611 range.minlen = max((unsigned int)range.minlen, 612 q->limits.discard_granularity); 613 ret = ext4_trim_fs(sb, &range); 614 if (ret < 0) 615 return ret; 616 617 if (copy_to_user((struct fstrim_range __user *)arg, &range, 618 sizeof(range))) 619 return -EFAULT; 620 621 return 0; 622 } 623 case EXT4_IOC_PRECACHE_EXTENTS: 624 return ext4_ext_precache(inode); 625 case EXT4_IOC_SET_ENCRYPTION_POLICY: { 626 #ifdef CONFIG_EXT4_FS_ENCRYPTION 627 struct ext4_encryption_policy policy; 628 int err = 0; 629 630 if (copy_from_user(&policy, 631 (struct ext4_encryption_policy __user *)arg, 632 sizeof(policy))) { 633 err = -EFAULT; 634 goto encryption_policy_out; 635 } 636 637 err = ext4_process_policy(&policy, inode); 638 encryption_policy_out: 639 return err; 640 #else 641 return -EOPNOTSUPP; 642 #endif 643 } 644 case EXT4_IOC_GET_ENCRYPTION_PWSALT: { 645 int err, err2; 646 struct ext4_sb_info *sbi = EXT4_SB(sb); 647 handle_t *handle; 648 649 if (!ext4_sb_has_crypto(sb)) 650 return -EOPNOTSUPP; 651 if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) { 652 err = mnt_want_write_file(filp); 653 if (err) 654 return err; 655 handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); 656 if (IS_ERR(handle)) { 657 err = PTR_ERR(handle); 658 goto pwsalt_err_exit; 659 } 660 err = ext4_journal_get_write_access(handle, sbi->s_sbh); 661 if (err) 662 goto pwsalt_err_journal; 663 generate_random_uuid(sbi->s_es->s_encrypt_pw_salt); 664 err = ext4_handle_dirty_metadata(handle, NULL, 665 sbi->s_sbh); 666 pwsalt_err_journal: 667 err2 = ext4_journal_stop(handle); 668 if (err2 && !err) 669 err = err2; 670 pwsalt_err_exit: 671 mnt_drop_write_file(filp); 672 if (err) 673 return err; 674 } 675 if (copy_to_user((void __user *) arg, 676 sbi->s_es->s_encrypt_pw_salt, 16)) 677 return -EFAULT; 678 return 0; 679 } 680 case EXT4_IOC_GET_ENCRYPTION_POLICY: { 681 #ifdef CONFIG_EXT4_FS_ENCRYPTION 682 struct ext4_encryption_policy policy; 683 int err = 0; 684 685 if (!ext4_encrypted_inode(inode)) 686 return -ENOENT; 687 err = ext4_get_policy(inode, &policy); 688 if (err) 689 return err; 690 if (copy_to_user((void __user *)arg, &policy, sizeof(policy))) 691 return -EFAULT; 692 return 0; 693 #else 694 return -EOPNOTSUPP; 695 #endif 696 } 697 default: 698 return -ENOTTY; 699 } 700 } 701 702 #ifdef CONFIG_COMPAT 703 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 704 { 705 /* These are just misnamed, they actually get/put from/to user an int */ 706 switch (cmd) { 707 case EXT4_IOC32_GETFLAGS: 708 cmd = EXT4_IOC_GETFLAGS; 709 break; 710 case EXT4_IOC32_SETFLAGS: 711 cmd = EXT4_IOC_SETFLAGS; 712 break; 713 case EXT4_IOC32_GETVERSION: 714 cmd = EXT4_IOC_GETVERSION; 715 break; 716 case EXT4_IOC32_SETVERSION: 717 cmd = EXT4_IOC_SETVERSION; 718 break; 719 case EXT4_IOC32_GROUP_EXTEND: 720 cmd = EXT4_IOC_GROUP_EXTEND; 721 break; 722 case EXT4_IOC32_GETVERSION_OLD: 723 cmd = EXT4_IOC_GETVERSION_OLD; 724 break; 725 case EXT4_IOC32_SETVERSION_OLD: 726 cmd = EXT4_IOC_SETVERSION_OLD; 727 break; 728 case EXT4_IOC32_GETRSVSZ: 729 cmd = EXT4_IOC_GETRSVSZ; 730 break; 731 case EXT4_IOC32_SETRSVSZ: 732 cmd = EXT4_IOC_SETRSVSZ; 733 break; 734 case EXT4_IOC32_GROUP_ADD: { 735 struct compat_ext4_new_group_input __user *uinput; 736 struct ext4_new_group_input input; 737 mm_segment_t old_fs; 738 int err; 739 740 uinput = compat_ptr(arg); 741 err = get_user(input.group, &uinput->group); 742 err |= get_user(input.block_bitmap, &uinput->block_bitmap); 743 err |= get_user(input.inode_bitmap, &uinput->inode_bitmap); 744 err |= get_user(input.inode_table, &uinput->inode_table); 745 err |= get_user(input.blocks_count, &uinput->blocks_count); 746 err |= get_user(input.reserved_blocks, 747 &uinput->reserved_blocks); 748 if (err) 749 return -EFAULT; 750 old_fs = get_fs(); 751 set_fs(KERNEL_DS); 752 err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD, 753 (unsigned long) &input); 754 set_fs(old_fs); 755 return err; 756 } 757 case EXT4_IOC_MOVE_EXT: 758 case EXT4_IOC_RESIZE_FS: 759 case EXT4_IOC_PRECACHE_EXTENTS: 760 case EXT4_IOC_SET_ENCRYPTION_POLICY: 761 case EXT4_IOC_GET_ENCRYPTION_PWSALT: 762 case EXT4_IOC_GET_ENCRYPTION_POLICY: 763 break; 764 default: 765 return -ENOIOCTLCMD; 766 } 767 return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 768 } 769 #endif 770