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> 13617ba13bSMingming Cao #include <linux/ext4_fs.h> 14dab291afSMingming Cao #include <linux/ext4_jbd2.h> 15ac27a0ecSDave Kleikamp #include <linux/time.h> 16ac27a0ecSDave Kleikamp #include <linux/compat.h> 17ac27a0ecSDave Kleikamp #include <linux/smp_lock.h> 18ac27a0ecSDave Kleikamp #include <asm/uaccess.h> 19ac27a0ecSDave Kleikamp 20617ba13bSMingming Cao int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 21ac27a0ecSDave Kleikamp unsigned long arg) 22ac27a0ecSDave Kleikamp { 23617ba13bSMingming Cao struct ext4_inode_info *ei = EXT4_I(inode); 24ac27a0ecSDave Kleikamp unsigned int flags; 25ac27a0ecSDave Kleikamp unsigned short rsv_window_size; 26ac27a0ecSDave Kleikamp 27617ba13bSMingming Cao ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg); 28ac27a0ecSDave Kleikamp 29ac27a0ecSDave Kleikamp switch (cmd) { 30617ba13bSMingming Cao case EXT4_IOC_GETFLAGS: 31617ba13bSMingming Cao flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 32ac27a0ecSDave Kleikamp return put_user(flags, (int __user *) arg); 33617ba13bSMingming Cao case EXT4_IOC_SETFLAGS: { 34ac27a0ecSDave Kleikamp handle_t *handle = NULL; 35ac27a0ecSDave Kleikamp int err; 36617ba13bSMingming Cao struct ext4_iloc iloc; 37ac27a0ecSDave Kleikamp unsigned int oldflags; 38ac27a0ecSDave Kleikamp unsigned int jflag; 39ac27a0ecSDave Kleikamp 40ac27a0ecSDave Kleikamp if (IS_RDONLY(inode)) 41ac27a0ecSDave Kleikamp return -EROFS; 42ac27a0ecSDave Kleikamp 43ac27a0ecSDave Kleikamp if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 44ac27a0ecSDave Kleikamp return -EACCES; 45ac27a0ecSDave Kleikamp 46ac27a0ecSDave Kleikamp if (get_user(flags, (int __user *) arg)) 47ac27a0ecSDave Kleikamp return -EFAULT; 48ac27a0ecSDave Kleikamp 49ac27a0ecSDave Kleikamp if (!S_ISDIR(inode->i_mode)) 50617ba13bSMingming Cao flags &= ~EXT4_DIRSYNC_FL; 51ac27a0ecSDave Kleikamp 52ac27a0ecSDave Kleikamp mutex_lock(&inode->i_mutex); 53ac27a0ecSDave Kleikamp oldflags = ei->i_flags; 54ac27a0ecSDave Kleikamp 55ac27a0ecSDave Kleikamp /* The JOURNAL_DATA flag is modifiable only by root */ 56617ba13bSMingming Cao jflag = flags & EXT4_JOURNAL_DATA_FL; 57ac27a0ecSDave Kleikamp 58ac27a0ecSDave Kleikamp /* 59ac27a0ecSDave Kleikamp * The IMMUTABLE and APPEND_ONLY flags can only be changed by 60ac27a0ecSDave Kleikamp * the relevant capability. 61ac27a0ecSDave Kleikamp * 62ac27a0ecSDave Kleikamp * This test looks nicer. Thanks to Pauline Middelink 63ac27a0ecSDave Kleikamp */ 64617ba13bSMingming Cao if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 65ac27a0ecSDave Kleikamp if (!capable(CAP_LINUX_IMMUTABLE)) { 66ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 67ac27a0ecSDave Kleikamp return -EPERM; 68ac27a0ecSDave Kleikamp } 69ac27a0ecSDave Kleikamp } 70ac27a0ecSDave Kleikamp 71ac27a0ecSDave Kleikamp /* 72ac27a0ecSDave Kleikamp * The JOURNAL_DATA flag can only be changed by 73ac27a0ecSDave Kleikamp * the relevant capability. 74ac27a0ecSDave Kleikamp */ 75617ba13bSMingming Cao if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 76ac27a0ecSDave Kleikamp if (!capable(CAP_SYS_RESOURCE)) { 77ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 78ac27a0ecSDave Kleikamp return -EPERM; 79ac27a0ecSDave Kleikamp } 80ac27a0ecSDave Kleikamp } 81ac27a0ecSDave Kleikamp 82ac27a0ecSDave Kleikamp 83617ba13bSMingming Cao handle = ext4_journal_start(inode, 1); 84ac27a0ecSDave Kleikamp if (IS_ERR(handle)) { 85ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 86ac27a0ecSDave Kleikamp return PTR_ERR(handle); 87ac27a0ecSDave Kleikamp } 88ac27a0ecSDave Kleikamp if (IS_SYNC(inode)) 89ac27a0ecSDave Kleikamp handle->h_sync = 1; 90617ba13bSMingming Cao err = ext4_reserve_inode_write(handle, inode, &iloc); 91ac27a0ecSDave Kleikamp if (err) 92ac27a0ecSDave Kleikamp goto flags_err; 93ac27a0ecSDave Kleikamp 94617ba13bSMingming Cao flags = flags & EXT4_FL_USER_MODIFIABLE; 95617ba13bSMingming Cao flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 96ac27a0ecSDave Kleikamp ei->i_flags = flags; 97ac27a0ecSDave Kleikamp 98617ba13bSMingming Cao ext4_set_inode_flags(inode); 99ac27a0ecSDave Kleikamp inode->i_ctime = CURRENT_TIME_SEC; 100ac27a0ecSDave Kleikamp 101617ba13bSMingming Cao err = ext4_mark_iloc_dirty(handle, inode, &iloc); 102ac27a0ecSDave Kleikamp flags_err: 103617ba13bSMingming Cao ext4_journal_stop(handle); 104ac27a0ecSDave Kleikamp if (err) { 105ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 106ac27a0ecSDave Kleikamp return err; 107ac27a0ecSDave Kleikamp } 108ac27a0ecSDave Kleikamp 109617ba13bSMingming Cao if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 110617ba13bSMingming Cao err = ext4_change_inode_journal_flag(inode, jflag); 111ac27a0ecSDave Kleikamp mutex_unlock(&inode->i_mutex); 112ac27a0ecSDave Kleikamp return err; 113ac27a0ecSDave Kleikamp } 114617ba13bSMingming Cao case EXT4_IOC_GETVERSION: 115617ba13bSMingming Cao case EXT4_IOC_GETVERSION_OLD: 116ac27a0ecSDave Kleikamp return put_user(inode->i_generation, (int __user *) arg); 117617ba13bSMingming Cao case EXT4_IOC_SETVERSION: 118617ba13bSMingming Cao case EXT4_IOC_SETVERSION_OLD: { 119ac27a0ecSDave Kleikamp handle_t *handle; 120617ba13bSMingming Cao struct ext4_iloc iloc; 121ac27a0ecSDave Kleikamp __u32 generation; 122ac27a0ecSDave Kleikamp int err; 123ac27a0ecSDave Kleikamp 124ac27a0ecSDave Kleikamp if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 125ac27a0ecSDave Kleikamp return -EPERM; 126ac27a0ecSDave Kleikamp if (IS_RDONLY(inode)) 127ac27a0ecSDave Kleikamp return -EROFS; 128ac27a0ecSDave Kleikamp if (get_user(generation, (int __user *) arg)) 129ac27a0ecSDave Kleikamp return -EFAULT; 130ac27a0ecSDave Kleikamp 131617ba13bSMingming Cao handle = ext4_journal_start(inode, 1); 132ac27a0ecSDave Kleikamp if (IS_ERR(handle)) 133ac27a0ecSDave Kleikamp return PTR_ERR(handle); 134617ba13bSMingming Cao err = ext4_reserve_inode_write(handle, inode, &iloc); 135ac27a0ecSDave Kleikamp if (err == 0) { 136ac27a0ecSDave Kleikamp inode->i_ctime = CURRENT_TIME_SEC; 137ac27a0ecSDave Kleikamp inode->i_generation = generation; 138617ba13bSMingming Cao err = ext4_mark_iloc_dirty(handle, inode, &iloc); 139ac27a0ecSDave Kleikamp } 140617ba13bSMingming Cao ext4_journal_stop(handle); 141ac27a0ecSDave Kleikamp return err; 142ac27a0ecSDave Kleikamp } 143ac27a0ecSDave Kleikamp #ifdef CONFIG_JBD_DEBUG 144617ba13bSMingming Cao case EXT4_IOC_WAIT_FOR_READONLY: 145ac27a0ecSDave Kleikamp /* 146ac27a0ecSDave Kleikamp * This is racy - by the time we're woken up and running, 147ac27a0ecSDave Kleikamp * the superblock could be released. And the module could 148ac27a0ecSDave Kleikamp * have been unloaded. So sue me. 149ac27a0ecSDave Kleikamp * 150ac27a0ecSDave Kleikamp * Returns 1 if it slept, else zero. 151ac27a0ecSDave Kleikamp */ 152ac27a0ecSDave Kleikamp { 153ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 154ac27a0ecSDave Kleikamp DECLARE_WAITQUEUE(wait, current); 155ac27a0ecSDave Kleikamp int ret = 0; 156ac27a0ecSDave Kleikamp 157ac27a0ecSDave Kleikamp set_current_state(TASK_INTERRUPTIBLE); 158617ba13bSMingming Cao add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 159617ba13bSMingming Cao if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { 160ac27a0ecSDave Kleikamp schedule(); 161ac27a0ecSDave Kleikamp ret = 1; 162ac27a0ecSDave Kleikamp } 163617ba13bSMingming Cao remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); 164ac27a0ecSDave Kleikamp return ret; 165ac27a0ecSDave Kleikamp } 166ac27a0ecSDave Kleikamp #endif 167617ba13bSMingming Cao case EXT4_IOC_GETRSVSZ: 168ac27a0ecSDave Kleikamp if (test_opt(inode->i_sb, RESERVATION) 169ac27a0ecSDave Kleikamp && S_ISREG(inode->i_mode) 170ac27a0ecSDave Kleikamp && ei->i_block_alloc_info) { 171ac27a0ecSDave Kleikamp rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 172ac27a0ecSDave Kleikamp return put_user(rsv_window_size, (int __user *)arg); 173ac27a0ecSDave Kleikamp } 174ac27a0ecSDave Kleikamp return -ENOTTY; 175617ba13bSMingming Cao case EXT4_IOC_SETRSVSZ: { 176ac27a0ecSDave Kleikamp 177ac27a0ecSDave Kleikamp if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 178ac27a0ecSDave Kleikamp return -ENOTTY; 179ac27a0ecSDave Kleikamp 180ac27a0ecSDave Kleikamp if (IS_RDONLY(inode)) 181ac27a0ecSDave Kleikamp return -EROFS; 182ac27a0ecSDave Kleikamp 183ac27a0ecSDave Kleikamp if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 184ac27a0ecSDave Kleikamp return -EACCES; 185ac27a0ecSDave Kleikamp 186ac27a0ecSDave Kleikamp if (get_user(rsv_window_size, (int __user *)arg)) 187ac27a0ecSDave Kleikamp return -EFAULT; 188ac27a0ecSDave Kleikamp 189617ba13bSMingming Cao if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) 190617ba13bSMingming Cao rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; 191ac27a0ecSDave Kleikamp 192ac27a0ecSDave Kleikamp /* 193ac27a0ecSDave Kleikamp * need to allocate reservation structure for this inode 194ac27a0ecSDave Kleikamp * before set the window size 195ac27a0ecSDave Kleikamp */ 196ac27a0ecSDave Kleikamp mutex_lock(&ei->truncate_mutex); 197ac27a0ecSDave Kleikamp if (!ei->i_block_alloc_info) 198617ba13bSMingming Cao ext4_init_block_alloc_info(inode); 199ac27a0ecSDave Kleikamp 200ac27a0ecSDave Kleikamp if (ei->i_block_alloc_info){ 201617ba13bSMingming Cao struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 202ac27a0ecSDave Kleikamp rsv->rsv_goal_size = rsv_window_size; 203ac27a0ecSDave Kleikamp } 204ac27a0ecSDave Kleikamp mutex_unlock(&ei->truncate_mutex); 205ac27a0ecSDave Kleikamp return 0; 206ac27a0ecSDave Kleikamp } 207617ba13bSMingming Cao case EXT4_IOC_GROUP_EXTEND: { 208617ba13bSMingming Cao ext4_fsblk_t n_blocks_count; 209ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 210ac27a0ecSDave Kleikamp int err; 211ac27a0ecSDave Kleikamp 212ac27a0ecSDave Kleikamp if (!capable(CAP_SYS_RESOURCE)) 213ac27a0ecSDave Kleikamp return -EPERM; 214ac27a0ecSDave Kleikamp 215ac27a0ecSDave Kleikamp if (IS_RDONLY(inode)) 216ac27a0ecSDave Kleikamp return -EROFS; 217ac27a0ecSDave Kleikamp 218ac27a0ecSDave Kleikamp if (get_user(n_blocks_count, (__u32 __user *)arg)) 219ac27a0ecSDave Kleikamp return -EFAULT; 220ac27a0ecSDave Kleikamp 221617ba13bSMingming Cao err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 222dab291afSMingming Cao jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 223dab291afSMingming Cao jbd2_journal_flush(EXT4_SB(sb)->s_journal); 224dab291afSMingming Cao jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 225ac27a0ecSDave Kleikamp 226ac27a0ecSDave Kleikamp return err; 227ac27a0ecSDave Kleikamp } 228617ba13bSMingming Cao case EXT4_IOC_GROUP_ADD: { 229617ba13bSMingming Cao struct ext4_new_group_data input; 230ac27a0ecSDave Kleikamp struct super_block *sb = inode->i_sb; 231ac27a0ecSDave Kleikamp int err; 232ac27a0ecSDave Kleikamp 233ac27a0ecSDave Kleikamp if (!capable(CAP_SYS_RESOURCE)) 234ac27a0ecSDave Kleikamp return -EPERM; 235ac27a0ecSDave Kleikamp 236ac27a0ecSDave Kleikamp if (IS_RDONLY(inode)) 237ac27a0ecSDave Kleikamp return -EROFS; 238ac27a0ecSDave Kleikamp 239617ba13bSMingming Cao if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 240ac27a0ecSDave Kleikamp sizeof(input))) 241ac27a0ecSDave Kleikamp return -EFAULT; 242ac27a0ecSDave Kleikamp 243617ba13bSMingming Cao err = ext4_group_add(sb, &input); 244dab291afSMingming Cao jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 245dab291afSMingming Cao jbd2_journal_flush(EXT4_SB(sb)->s_journal); 246dab291afSMingming Cao jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 247ac27a0ecSDave Kleikamp 248ac27a0ecSDave Kleikamp return err; 249ac27a0ecSDave Kleikamp } 250ac27a0ecSDave Kleikamp 251ac27a0ecSDave Kleikamp 252ac27a0ecSDave Kleikamp default: 253ac27a0ecSDave Kleikamp return -ENOTTY; 254ac27a0ecSDave Kleikamp } 255ac27a0ecSDave Kleikamp } 256ac27a0ecSDave Kleikamp 257ac27a0ecSDave Kleikamp #ifdef CONFIG_COMPAT 258617ba13bSMingming Cao long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 259ac27a0ecSDave Kleikamp { 260ac27a0ecSDave Kleikamp struct inode *inode = file->f_dentry->d_inode; 261ac27a0ecSDave Kleikamp int ret; 262ac27a0ecSDave Kleikamp 263ac27a0ecSDave Kleikamp /* These are just misnamed, they actually get/put from/to user an int */ 264ac27a0ecSDave Kleikamp switch (cmd) { 265617ba13bSMingming Cao case EXT4_IOC32_GETFLAGS: 266617ba13bSMingming Cao cmd = EXT4_IOC_GETFLAGS; 267ac27a0ecSDave Kleikamp break; 268617ba13bSMingming Cao case EXT4_IOC32_SETFLAGS: 269617ba13bSMingming Cao cmd = EXT4_IOC_SETFLAGS; 270ac27a0ecSDave Kleikamp break; 271617ba13bSMingming Cao case EXT4_IOC32_GETVERSION: 272617ba13bSMingming Cao cmd = EXT4_IOC_GETVERSION; 273ac27a0ecSDave Kleikamp break; 274617ba13bSMingming Cao case EXT4_IOC32_SETVERSION: 275617ba13bSMingming Cao cmd = EXT4_IOC_SETVERSION; 276ac27a0ecSDave Kleikamp break; 277617ba13bSMingming Cao case EXT4_IOC32_GROUP_EXTEND: 278617ba13bSMingming Cao cmd = EXT4_IOC_GROUP_EXTEND; 279ac27a0ecSDave Kleikamp break; 280617ba13bSMingming Cao case EXT4_IOC32_GETVERSION_OLD: 281617ba13bSMingming Cao cmd = EXT4_IOC_GETVERSION_OLD; 282ac27a0ecSDave Kleikamp break; 283617ba13bSMingming Cao case EXT4_IOC32_SETVERSION_OLD: 284617ba13bSMingming Cao cmd = EXT4_IOC_SETVERSION_OLD; 285ac27a0ecSDave Kleikamp break; 286ac27a0ecSDave Kleikamp #ifdef CONFIG_JBD_DEBUG 287617ba13bSMingming Cao case EXT4_IOC32_WAIT_FOR_READONLY: 288617ba13bSMingming Cao cmd = EXT4_IOC_WAIT_FOR_READONLY; 289ac27a0ecSDave Kleikamp break; 290ac27a0ecSDave Kleikamp #endif 291617ba13bSMingming Cao case EXT4_IOC32_GETRSVSZ: 292617ba13bSMingming Cao cmd = EXT4_IOC_GETRSVSZ; 293ac27a0ecSDave Kleikamp break; 294617ba13bSMingming Cao case EXT4_IOC32_SETRSVSZ: 295617ba13bSMingming Cao cmd = EXT4_IOC_SETRSVSZ; 296ac27a0ecSDave Kleikamp break; 297617ba13bSMingming Cao case EXT4_IOC_GROUP_ADD: 298ac27a0ecSDave Kleikamp break; 299ac27a0ecSDave Kleikamp default: 300ac27a0ecSDave Kleikamp return -ENOIOCTLCMD; 301ac27a0ecSDave Kleikamp } 302ac27a0ecSDave Kleikamp lock_kernel(); 303617ba13bSMingming Cao ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); 304ac27a0ecSDave Kleikamp unlock_kernel(); 305ac27a0ecSDave Kleikamp return ret; 306ac27a0ecSDave Kleikamp } 307ac27a0ecSDave Kleikamp #endif 308