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