1ac27a0ecSDave Kleikamp /* 2617ba13bSMingming Cao * linux/fs/ext4/ioctl.c 3ac27a0ecSDave Kleikamp * 4ac27a0ecSDave Kleikamp * Copyright (C) 1993, 1994, 1995 5ac27a0ecSDave Kleikamp * Remy Card (card@masi.ibp.fr) 6ac27a0ecSDave Kleikamp * Laboratoire MASI - Institut Blaise Pascal 7ac27a0ecSDave Kleikamp * Universite Pierre et Marie Curie (Paris VI) 8ac27a0ecSDave Kleikamp */ 9ac27a0ecSDave Kleikamp 10ac27a0ecSDave Kleikamp #include <linux/fs.h> 11dab291afSMingming Cao #include <linux/jbd2.h> 12ac27a0ecSDave Kleikamp #include <linux/capability.h> 13ac27a0ecSDave Kleikamp #include <linux/time.h> 14ac27a0ecSDave Kleikamp #include <linux/compat.h> 15ac27a0ecSDave Kleikamp #include <linux/smp_lock.h> 1642a74f20SDave Hansen #include <linux/mount.h> 17ac27a0ecSDave Kleikamp #include <asm/uaccess.h> 183dcf5451SChristoph Hellwig #include "ext4_jbd2.h" 193dcf5451SChristoph Hellwig #include "ext4.h" 20ac27a0ecSDave Kleikamp 215cdd7b2dSAndi Kleen long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 22ac27a0ecSDave Kleikamp { 235cdd7b2dSAndi Kleen struct inode *inode = filp->f_dentry->d_inode; 24617ba13bSMingming Cao struct ext4_inode_info *ei = EXT4_I(inode); 25ac27a0ecSDave Kleikamp unsigned int flags; 26ac27a0ecSDave Kleikamp unsigned short rsv_window_size; 27ac27a0ecSDave Kleikamp 28617ba13bSMingming Cao ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); 29ac27a0ecSDave Kleikamp 30ac27a0ecSDave Kleikamp switch (cmd) { 31617ba13bSMingming Cao case EXT4_IOC_GETFLAGS: 32ff9ddf7eSJan Kara ext4_get_inode_flags(ei); 33617ba13bSMingming Cao flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 34ac27a0ecSDave Kleikamp return put_user(flags, (int __user *) arg); 35617ba13bSMingming Cao case EXT4_IOC_SETFLAGS: { 36ac27a0ecSDave Kleikamp handle_t *handle = NULL; 37ac27a0ecSDave Kleikamp int err; 38617ba13bSMingming Cao struct ext4_iloc iloc; 39ac27a0ecSDave Kleikamp unsigned int oldflags; 40ac27a0ecSDave Kleikamp unsigned int jflag; 41ac27a0ecSDave Kleikamp 423bd858abSSatyam Sharma if (!is_owner_or_cap(inode)) 43ac27a0ecSDave Kleikamp return -EACCES; 44ac27a0ecSDave Kleikamp 45ac27a0ecSDave Kleikamp if (get_user(flags, (int __user *) arg)) 46ac27a0ecSDave Kleikamp return -EFAULT; 47ac27a0ecSDave Kleikamp 4842a74f20SDave Hansen err = mnt_want_write(filp->f_path.mnt); 4942a74f20SDave Hansen if (err) 5042a74f20SDave Hansen return err; 5142a74f20SDave Hansen 52ac27a0ecSDave Kleikamp if (!S_ISDIR(inode->i_mode)) 53617ba13bSMingming Cao flags &= ~EXT4_DIRSYNC_FL; 54ac27a0ecSDave Kleikamp 5542a74f20SDave Hansen err = -EPERM; 56ac27a0ecSDave Kleikamp mutex_lock(&inode->i_mutex); 57e47776a0SJan Kara /* Is it quota file? Do not allow user to mess with it */ 5842a74f20SDave Hansen if (IS_NOQUOTA(inode)) 5942a74f20SDave Hansen goto flags_out; 6042a74f20SDave Hansen 61ac27a0ecSDave Kleikamp oldflags = ei->i_flags; 62ac27a0ecSDave Kleikamp 63ac27a0ecSDave Kleikamp /* The JOURNAL_DATA flag is modifiable only by root */ 64617ba13bSMingming Cao jflag = flags & EXT4_JOURNAL_DATA_FL; 65ac27a0ecSDave Kleikamp 66ac27a0ecSDave Kleikamp /* 67ac27a0ecSDave Kleikamp * The IMMUTABLE and APPEND_ONLY flags can only be changed by 68ac27a0ecSDave Kleikamp * the relevant capability. 69ac27a0ecSDave Kleikamp * 70ac27a0ecSDave Kleikamp * This test looks nicer. Thanks to Pauline Middelink 71ac27a0ecSDave Kleikamp */ 72617ba13bSMingming Cao if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 7342a74f20SDave Hansen if (!capable(CAP_LINUX_IMMUTABLE)) 7442a74f20SDave Hansen goto flags_out; 75ac27a0ecSDave Kleikamp } 76ac27a0ecSDave Kleikamp 77ac27a0ecSDave Kleikamp /* 78ac27a0ecSDave Kleikamp * The JOURNAL_DATA flag can only be changed by 79ac27a0ecSDave Kleikamp * the relevant capability. 80ac27a0ecSDave Kleikamp */ 81617ba13bSMingming Cao if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 8242a74f20SDave Hansen if (!capable(CAP_SYS_RESOURCE)) 8342a74f20SDave Hansen goto flags_out; 84ac27a0ecSDave Kleikamp } 85ac27a0ecSDave Kleikamp 86617ba13bSMingming Cao handle = ext4_journal_start(inode, 1); 87ac27a0ecSDave Kleikamp if (IS_ERR(handle)) { 8842a74f20SDave Hansen err = PTR_ERR(handle); 8942a74f20SDave Hansen goto flags_out; 90ac27a0ecSDave Kleikamp } 91ac27a0ecSDave Kleikamp if (IS_SYNC(inode)) 92ac27a0ecSDave Kleikamp handle->h_sync = 1; 93617ba13bSMingming Cao err = ext4_reserve_inode_write(handle, inode, &iloc); 94ac27a0ecSDave Kleikamp if (err) 95ac27a0ecSDave Kleikamp goto flags_err; 96ac27a0ecSDave Kleikamp 97617ba13bSMingming Cao flags = flags & EXT4_FL_USER_MODIFIABLE; 98617ba13bSMingming Cao flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 99ac27a0ecSDave Kleikamp ei->i_flags = flags; 100ac27a0ecSDave Kleikamp 101617ba13bSMingming Cao ext4_set_inode_flags(inode); 102ef7f3835SKalpak Shah inode->i_ctime = ext4_current_time(inode); 103ac27a0ecSDave Kleikamp 104617ba13bSMingming Cao err = ext4_mark_iloc_dirty(handle, inode, &iloc); 105ac27a0ecSDave Kleikamp flags_err: 106617ba13bSMingming Cao ext4_journal_stop(handle); 10742a74f20SDave Hansen if (err) 10842a74f20SDave Hansen goto flags_out; 109ac27a0ecSDave Kleikamp 110617ba13bSMingming Cao if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 111617ba13bSMingming Cao err = ext4_change_inode_journal_flag(inode, jflag); 11242a74f20SDave Hansen flags_out: 113ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 11442a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 115ac27a0ecSDave Kleikamp return err; 116ac27a0ecSDave Kleikamp } 117617ba13bSMingming Cao case EXT4_IOC_GETVERSION: 118617ba13bSMingming Cao case EXT4_IOC_GETVERSION_OLD: 119ac27a0ecSDave Kleikamp return put_user(inode->i_generation, (int __user *) arg); 120617ba13bSMingming Cao case EXT4_IOC_SETVERSION: 121617ba13bSMingming Cao case EXT4_IOC_SETVERSION_OLD: { 122ac27a0ecSDave Kleikamp handle_t *handle; 123617ba13bSMingming Cao struct ext4_iloc iloc; 124ac27a0ecSDave Kleikamp __u32 generation; 125ac27a0ecSDave Kleikamp int err; 126ac27a0ecSDave Kleikamp 1273bd858abSSatyam Sharma if (!is_owner_or_cap(inode)) 128ac27a0ecSDave Kleikamp return -EPERM; 12942a74f20SDave Hansen 13042a74f20SDave Hansen err = mnt_want_write(filp->f_path.mnt); 13142a74f20SDave Hansen if (err) 13242a74f20SDave Hansen return err; 13342a74f20SDave Hansen if (get_user(generation, (int __user *) arg)) { 13442a74f20SDave Hansen err = -EFAULT; 13542a74f20SDave Hansen goto setversion_out; 13642a74f20SDave Hansen } 137ac27a0ecSDave Kleikamp 138617ba13bSMingming Cao handle = ext4_journal_start(inode, 1); 13942a74f20SDave Hansen if (IS_ERR(handle)) { 14042a74f20SDave Hansen err = PTR_ERR(handle); 14142a74f20SDave Hansen goto setversion_out; 14242a74f20SDave Hansen } 143617ba13bSMingming Cao err = ext4_reserve_inode_write(handle, inode, &iloc); 144ac27a0ecSDave Kleikamp if (err == 0) { 145ef7f3835SKalpak Shah inode->i_ctime = ext4_current_time(inode); 146ac27a0ecSDave Kleikamp inode->i_generation = generation; 147617ba13bSMingming Cao err = ext4_mark_iloc_dirty(handle, inode, &iloc); 148ac27a0ecSDave Kleikamp } 149617ba13bSMingming Cao ext4_journal_stop(handle); 15042a74f20SDave Hansen setversion_out: 15142a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 152ac27a0ecSDave Kleikamp return err; 153ac27a0ecSDave Kleikamp } 154e23291b9SJose R. Santos #ifdef CONFIG_JBD2_DEBUG 155617ba13bSMingming Cao case EXT4_IOC_WAIT_FOR_READONLY: 156ac27a0ecSDave Kleikamp /* 157ac27a0ecSDave Kleikamp * This is racy - by the time we're woken up and running, 158ac27a0ecSDave Kleikamp * the superblock could be released. And the module could 159ac27a0ecSDave Kleikamp * have been unloaded. So sue me. 160ac27a0ecSDave Kleikamp * 161ac27a0ecSDave Kleikamp * Returns 1 if it slept, else zero. 162ac27a0ecSDave Kleikamp */ 163ac27a0ecSDave Kleikamp { 164ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 165ac27a0ecSDave Kleikamp DECLARE_WAITQUEUE(wait, current); 166ac27a0ecSDave Kleikamp int ret = 0; 167ac27a0ecSDave Kleikamp 168ac27a0ecSDave Kleikamp set_current_state(TASK_INTERRUPTIBLE); 169617ba13bSMingming Cao add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 170617ba13bSMingming Cao if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { 171ac27a0ecSDave Kleikamp schedule(); 172ac27a0ecSDave Kleikamp ret = 1; 173ac27a0ecSDave Kleikamp } 174617ba13bSMingming Cao remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 175ac27a0ecSDave Kleikamp return ret; 176ac27a0ecSDave Kleikamp } 177ac27a0ecSDave Kleikamp #endif 178617ba13bSMingming Cao case EXT4_IOC_GETRSVSZ: 179ac27a0ecSDave Kleikamp if (test_opt(inode->i_sb, RESERVATION) 180ac27a0ecSDave Kleikamp && S_ISREG(inode->i_mode) 181ac27a0ecSDave Kleikamp && ei->i_block_alloc_info) { 182ac27a0ecSDave Kleikamp rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 183ac27a0ecSDave Kleikamp return put_user(rsv_window_size, (int __user *)arg); 184ac27a0ecSDave Kleikamp } 185ac27a0ecSDave Kleikamp return -ENOTTY; 186617ba13bSMingming Cao case EXT4_IOC_SETRSVSZ: { 18742a74f20SDave Hansen int err; 188ac27a0ecSDave Kleikamp 189ac27a0ecSDave Kleikamp if (!test_opt(inode->i_sb, RESERVATION) || !S_ISREG(inode->i_mode)) 190ac27a0ecSDave Kleikamp return -ENOTTY; 191ac27a0ecSDave Kleikamp 1923bd858abSSatyam Sharma if (!is_owner_or_cap(inode)) 193ac27a0ecSDave Kleikamp return -EACCES; 194ac27a0ecSDave Kleikamp 195ac27a0ecSDave Kleikamp if (get_user(rsv_window_size, (int __user *)arg)) 196ac27a0ecSDave Kleikamp return -EFAULT; 197ac27a0ecSDave Kleikamp 19842a74f20SDave Hansen err = mnt_want_write(filp->f_path.mnt); 19942a74f20SDave Hansen if (err) 20042a74f20SDave Hansen return err; 20142a74f20SDave Hansen 202617ba13bSMingming Cao if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) 203617ba13bSMingming Cao rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; 204ac27a0ecSDave Kleikamp 205ac27a0ecSDave Kleikamp /* 206ac27a0ecSDave Kleikamp * need to allocate reservation structure for this inode 207ac27a0ecSDave Kleikamp * before set the window size 208ac27a0ecSDave Kleikamp */ 2090e855ac8SAneesh Kumar K.V down_write(&ei->i_data_sem); 210ac27a0ecSDave Kleikamp if (!ei->i_block_alloc_info) 211617ba13bSMingming Cao ext4_init_block_alloc_info(inode); 212ac27a0ecSDave Kleikamp 213ac27a0ecSDave Kleikamp if (ei->i_block_alloc_info){ 214617ba13bSMingming Cao struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 215ac27a0ecSDave Kleikamp rsv->rsv_goal_size = rsv_window_size; 216ac27a0ecSDave Kleikamp } 2170e855ac8SAneesh Kumar K.V up_write(&ei->i_data_sem); 21842a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 219ac27a0ecSDave Kleikamp return 0; 220ac27a0ecSDave Kleikamp } 221617ba13bSMingming Cao case EXT4_IOC_GROUP_EXTEND: { 222617ba13bSMingming Cao ext4_fsblk_t n_blocks_count; 223ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 224ac27a0ecSDave Kleikamp int err; 225ac27a0ecSDave Kleikamp 226ac27a0ecSDave Kleikamp if (!capable(CAP_SYS_RESOURCE)) 227ac27a0ecSDave Kleikamp return -EPERM; 228ac27a0ecSDave Kleikamp 229ac27a0ecSDave Kleikamp if (get_user(n_blocks_count, (__u32 __user *)arg)) 230ac27a0ecSDave Kleikamp return -EFAULT; 231ac27a0ecSDave Kleikamp 23242a74f20SDave Hansen err = mnt_want_write(filp->f_path.mnt); 23342a74f20SDave Hansen if (err) 23442a74f20SDave Hansen return err; 23542a74f20SDave Hansen 236617ba13bSMingming Cao err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 237dab291afSMingming Cao jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 238dab291afSMingming Cao jbd2_journal_flush(EXT4_SB(sb)->s_journal); 239dab291afSMingming Cao jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 24042a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 241ac27a0ecSDave Kleikamp 242ac27a0ecSDave Kleikamp return err; 243ac27a0ecSDave Kleikamp } 244617ba13bSMingming Cao case EXT4_IOC_GROUP_ADD: { 245617ba13bSMingming Cao struct ext4_new_group_data input; 246ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 247ac27a0ecSDave Kleikamp int err; 248ac27a0ecSDave Kleikamp 249ac27a0ecSDave Kleikamp if (!capable(CAP_SYS_RESOURCE)) 250ac27a0ecSDave Kleikamp return -EPERM; 251ac27a0ecSDave Kleikamp 252617ba13bSMingming Cao if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 253ac27a0ecSDave Kleikamp sizeof(input))) 254ac27a0ecSDave Kleikamp return -EFAULT; 255ac27a0ecSDave Kleikamp 25642a74f20SDave Hansen err = mnt_want_write(filp->f_path.mnt); 25742a74f20SDave Hansen if (err) 25842a74f20SDave Hansen return err; 25942a74f20SDave Hansen 260617ba13bSMingming Cao err = ext4_group_add(sb, &input); 261dab291afSMingming Cao jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 262dab291afSMingming Cao jbd2_journal_flush(EXT4_SB(sb)->s_journal); 263dab291afSMingming Cao jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 26442a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 265ac27a0ecSDave Kleikamp 266ac27a0ecSDave Kleikamp return err; 267ac27a0ecSDave Kleikamp } 268ac27a0ecSDave Kleikamp 269c14c6fd5SAneesh Kumar K.V case EXT4_IOC_MIGRATE: 2702a43a878SAneesh Kumar K.V { 2712a43a878SAneesh Kumar K.V int err; 2722a43a878SAneesh Kumar K.V if (!is_owner_or_cap(inode)) 2732a43a878SAneesh Kumar K.V return -EACCES; 2742a43a878SAneesh Kumar K.V 2752a43a878SAneesh Kumar K.V err = mnt_want_write(filp->f_path.mnt); 2762a43a878SAneesh Kumar K.V if (err) 2772a43a878SAneesh Kumar K.V return err; 2782a43a878SAneesh Kumar K.V /* 2792a43a878SAneesh Kumar K.V * inode_mutex prevent write and truncate on the file. 2802a43a878SAneesh Kumar K.V * Read still goes through. We take i_data_sem in 2812a43a878SAneesh Kumar K.V * ext4_ext_swap_inode_data before we switch the 2822a43a878SAneesh Kumar K.V * inode format to prevent read. 2832a43a878SAneesh Kumar K.V */ 2842a43a878SAneesh Kumar K.V mutex_lock(&(inode->i_mutex)); 2852a43a878SAneesh Kumar K.V err = ext4_ext_migrate(inode); 2862a43a878SAneesh Kumar K.V mutex_unlock(&(inode->i_mutex)); 2872a43a878SAneesh Kumar K.V mnt_drop_write(filp->f_path.mnt); 2882a43a878SAneesh Kumar K.V return err; 2892a43a878SAneesh Kumar K.V } 290c14c6fd5SAneesh Kumar K.V 291ac27a0ecSDave Kleikamp default: 292ac27a0ecSDave Kleikamp return -ENOTTY; 293ac27a0ecSDave Kleikamp } 294ac27a0ecSDave Kleikamp } 295ac27a0ecSDave Kleikamp 296ac27a0ecSDave Kleikamp #ifdef CONFIG_COMPAT 297617ba13bSMingming Cao long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 298ac27a0ecSDave Kleikamp { 299ac27a0ecSDave Kleikamp /* These are just misnamed, they actually get/put from/to user an int */ 300ac27a0ecSDave Kleikamp switch (cmd) { 301617ba13bSMingming Cao case EXT4_IOC32_GETFLAGS: 302617ba13bSMingming Cao cmd = EXT4_IOC_GETFLAGS; 303ac27a0ecSDave Kleikamp break; 304617ba13bSMingming Cao case EXT4_IOC32_SETFLAGS: 305617ba13bSMingming Cao cmd = EXT4_IOC_SETFLAGS; 306ac27a0ecSDave Kleikamp break; 307617ba13bSMingming Cao case EXT4_IOC32_GETVERSION: 308617ba13bSMingming Cao cmd = EXT4_IOC_GETVERSION; 309ac27a0ecSDave Kleikamp break; 310617ba13bSMingming Cao case EXT4_IOC32_SETVERSION: 311617ba13bSMingming Cao cmd = EXT4_IOC_SETVERSION; 312ac27a0ecSDave Kleikamp break; 313617ba13bSMingming Cao case EXT4_IOC32_GROUP_EXTEND: 314617ba13bSMingming Cao cmd = EXT4_IOC_GROUP_EXTEND; 315ac27a0ecSDave Kleikamp break; 316617ba13bSMingming Cao case EXT4_IOC32_GETVERSION_OLD: 317617ba13bSMingming Cao cmd = EXT4_IOC_GETVERSION_OLD; 318ac27a0ecSDave Kleikamp break; 319617ba13bSMingming Cao case EXT4_IOC32_SETVERSION_OLD: 320617ba13bSMingming Cao cmd = EXT4_IOC_SETVERSION_OLD; 321ac27a0ecSDave Kleikamp break; 322e23291b9SJose R. Santos #ifdef CONFIG_JBD2_DEBUG 323617ba13bSMingming Cao case EXT4_IOC32_WAIT_FOR_READONLY: 324617ba13bSMingming Cao cmd = EXT4_IOC_WAIT_FOR_READONLY; 325ac27a0ecSDave Kleikamp break; 326ac27a0ecSDave Kleikamp #endif 327617ba13bSMingming Cao case EXT4_IOC32_GETRSVSZ: 328617ba13bSMingming Cao cmd = EXT4_IOC_GETRSVSZ; 329ac27a0ecSDave Kleikamp break; 330617ba13bSMingming Cao case EXT4_IOC32_SETRSVSZ: 331617ba13bSMingming Cao cmd = EXT4_IOC_SETRSVSZ; 332ac27a0ecSDave Kleikamp break; 333617ba13bSMingming Cao case EXT4_IOC_GROUP_ADD: 334ac27a0ecSDave Kleikamp break; 335ac27a0ecSDave Kleikamp default: 336ac27a0ecSDave Kleikamp return -ENOIOCTLCMD; 337ac27a0ecSDave Kleikamp } 3385cdd7b2dSAndi Kleen return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 339ac27a0ecSDave Kleikamp } 340ac27a0ecSDave Kleikamp #endif 341