1 /* 2 * linux/fs/ext2/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 "ext2.h" 11 #include <linux/capability.h> 12 #include <linux/time.h> 13 #include <linux/sched.h> 14 #include <linux/compat.h> 15 #include <linux/mount.h> 16 #include <asm/current.h> 17 #include <linux/uaccess.h> 18 19 20 long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 21 { 22 struct inode *inode = file_inode(filp); 23 struct ext2_inode_info *ei = EXT2_I(inode); 24 unsigned int flags; 25 unsigned short rsv_window_size; 26 int ret; 27 28 ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 29 30 switch (cmd) { 31 case EXT2_IOC_GETFLAGS: 32 flags = ei->i_flags & EXT2_FL_USER_VISIBLE; 33 return put_user(flags, (int __user *) arg); 34 case EXT2_IOC_SETFLAGS: { 35 unsigned int oldflags; 36 37 ret = mnt_want_write_file(filp); 38 if (ret) 39 return ret; 40 41 if (!inode_owner_or_capable(inode)) { 42 ret = -EACCES; 43 goto setflags_out; 44 } 45 46 if (get_user(flags, (int __user *) arg)) { 47 ret = -EFAULT; 48 goto setflags_out; 49 } 50 51 flags = ext2_mask_flags(inode->i_mode, flags); 52 53 inode_lock(inode); 54 /* Is it quota file? Do not allow user to mess with it */ 55 if (IS_NOQUOTA(inode)) { 56 inode_unlock(inode); 57 ret = -EPERM; 58 goto setflags_out; 59 } 60 oldflags = ei->i_flags; 61 62 /* 63 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 64 * the relevant capability. 65 * 66 * This test looks nicer. Thanks to Pauline Middelink 67 */ 68 if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { 69 if (!capable(CAP_LINUX_IMMUTABLE)) { 70 inode_unlock(inode); 71 ret = -EPERM; 72 goto setflags_out; 73 } 74 } 75 76 flags = flags & EXT2_FL_USER_MODIFIABLE; 77 flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; 78 ei->i_flags = flags; 79 80 ext2_set_inode_flags(inode); 81 inode->i_ctime = current_time(inode); 82 inode_unlock(inode); 83 84 mark_inode_dirty(inode); 85 setflags_out: 86 mnt_drop_write_file(filp); 87 return ret; 88 } 89 case EXT2_IOC_GETVERSION: 90 return put_user(inode->i_generation, (int __user *) arg); 91 case EXT2_IOC_SETVERSION: { 92 __u32 generation; 93 94 if (!inode_owner_or_capable(inode)) 95 return -EPERM; 96 ret = mnt_want_write_file(filp); 97 if (ret) 98 return ret; 99 if (get_user(generation, (int __user *) arg)) { 100 ret = -EFAULT; 101 goto setversion_out; 102 } 103 104 inode_lock(inode); 105 inode->i_ctime = current_time(inode); 106 inode->i_generation = generation; 107 inode_unlock(inode); 108 109 mark_inode_dirty(inode); 110 setversion_out: 111 mnt_drop_write_file(filp); 112 return ret; 113 } 114 case EXT2_IOC_GETRSVSZ: 115 if (test_opt(inode->i_sb, RESERVATION) 116 && S_ISREG(inode->i_mode) 117 && ei->i_block_alloc_info) { 118 rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 119 return put_user(rsv_window_size, (int __user *)arg); 120 } 121 return -ENOTTY; 122 case EXT2_IOC_SETRSVSZ: { 123 124 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 125 return -ENOTTY; 126 127 if (!inode_owner_or_capable(inode)) 128 return -EACCES; 129 130 if (get_user(rsv_window_size, (int __user *)arg)) 131 return -EFAULT; 132 133 ret = mnt_want_write_file(filp); 134 if (ret) 135 return ret; 136 137 if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) 138 rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; 139 140 /* 141 * need to allocate reservation structure for this inode 142 * before set the window size 143 */ 144 /* 145 * XXX What lock should protect the rsv_goal_size? 146 * Accessed in ext2_get_block only. ext3 uses i_truncate. 147 */ 148 mutex_lock(&ei->truncate_mutex); 149 if (!ei->i_block_alloc_info) 150 ext2_init_block_alloc_info(inode); 151 152 if (ei->i_block_alloc_info){ 153 struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 154 rsv->rsv_goal_size = rsv_window_size; 155 } 156 mutex_unlock(&ei->truncate_mutex); 157 mnt_drop_write_file(filp); 158 return 0; 159 } 160 default: 161 return -ENOTTY; 162 } 163 } 164 165 #ifdef CONFIG_COMPAT 166 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 167 { 168 /* These are just misnamed, they actually get/put from/to user an int */ 169 switch (cmd) { 170 case EXT2_IOC32_GETFLAGS: 171 cmd = EXT2_IOC_GETFLAGS; 172 break; 173 case EXT2_IOC32_SETFLAGS: 174 cmd = EXT2_IOC_SETFLAGS; 175 break; 176 case EXT2_IOC32_GETVERSION: 177 cmd = EXT2_IOC_GETVERSION; 178 break; 179 case EXT2_IOC32_SETVERSION: 180 cmd = EXT2_IOC_SETVERSION; 181 break; 182 default: 183 return -ENOIOCTLCMD; 184 } 185 return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 186 } 187 #endif 188