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