1 /* 2 * linux/fs/jfs/ioctl.c 3 * 4 * Copyright (C) 2006 Herbert Poetzl 5 * adapted from Remy Card's ext2/ioctl.c 6 */ 7 8 #include <linux/fs.h> 9 #include <linux/ctype.h> 10 #include <linux/capability.h> 11 #include <linux/mount.h> 12 #include <linux/time.h> 13 #include <linux/sched.h> 14 #include <linux/blkdev.h> 15 #include <asm/current.h> 16 #include <linux/uaccess.h> 17 18 #include "jfs_filsys.h" 19 #include "jfs_debug.h" 20 #include "jfs_incore.h" 21 #include "jfs_dinode.h" 22 #include "jfs_inode.h" 23 #include "jfs_dmap.h" 24 #include "jfs_discard.h" 25 26 static struct { 27 long jfs_flag; 28 long ext2_flag; 29 } jfs_map[] = { 30 {JFS_NOATIME_FL, FS_NOATIME_FL}, 31 {JFS_DIRSYNC_FL, FS_DIRSYNC_FL}, 32 {JFS_SYNC_FL, FS_SYNC_FL}, 33 {JFS_SECRM_FL, FS_SECRM_FL}, 34 {JFS_UNRM_FL, FS_UNRM_FL}, 35 {JFS_APPEND_FL, FS_APPEND_FL}, 36 {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL}, 37 {0, 0}, 38 }; 39 40 static long jfs_map_ext2(unsigned long flags, int from) 41 { 42 int index=0; 43 long mapped=0; 44 45 while (jfs_map[index].jfs_flag) { 46 if (from) { 47 if (jfs_map[index].ext2_flag & flags) 48 mapped |= jfs_map[index].jfs_flag; 49 } else { 50 if (jfs_map[index].jfs_flag & flags) 51 mapped |= jfs_map[index].ext2_flag; 52 } 53 index++; 54 } 55 return mapped; 56 } 57 58 59 long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 60 { 61 struct inode *inode = file_inode(filp); 62 struct jfs_inode_info *jfs_inode = JFS_IP(inode); 63 unsigned int flags; 64 65 switch (cmd) { 66 case JFS_IOC_GETFLAGS: 67 flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; 68 flags = jfs_map_ext2(flags, 0); 69 return put_user(flags, (int __user *) arg); 70 case JFS_IOC_SETFLAGS: { 71 unsigned int oldflags; 72 int err; 73 74 err = mnt_want_write_file(filp); 75 if (err) 76 return err; 77 78 if (!inode_owner_or_capable(inode)) { 79 err = -EACCES; 80 goto setflags_out; 81 } 82 if (get_user(flags, (int __user *) arg)) { 83 err = -EFAULT; 84 goto setflags_out; 85 } 86 87 flags = jfs_map_ext2(flags, 1); 88 if (!S_ISDIR(inode->i_mode)) 89 flags &= ~JFS_DIRSYNC_FL; 90 91 /* Is it quota file? Do not allow user to mess with it */ 92 if (IS_NOQUOTA(inode)) { 93 err = -EPERM; 94 goto setflags_out; 95 } 96 97 /* Lock against other parallel changes of flags */ 98 inode_lock(inode); 99 100 oldflags = jfs_inode->mode2; 101 102 /* 103 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 104 * the relevant capability. 105 */ 106 if ((oldflags & JFS_IMMUTABLE_FL) || 107 ((flags ^ oldflags) & 108 (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { 109 if (!capable(CAP_LINUX_IMMUTABLE)) { 110 inode_unlock(inode); 111 err = -EPERM; 112 goto setflags_out; 113 } 114 } 115 116 flags = flags & JFS_FL_USER_MODIFIABLE; 117 flags |= oldflags & ~JFS_FL_USER_MODIFIABLE; 118 jfs_inode->mode2 = flags; 119 120 jfs_set_inode_flags(inode); 121 inode_unlock(inode); 122 inode->i_ctime = current_time(inode); 123 mark_inode_dirty(inode); 124 setflags_out: 125 mnt_drop_write_file(filp); 126 return err; 127 } 128 129 case FITRIM: 130 { 131 struct super_block *sb = inode->i_sb; 132 struct request_queue *q = bdev_get_queue(sb->s_bdev); 133 struct fstrim_range range; 134 s64 ret = 0; 135 136 if (!capable(CAP_SYS_ADMIN)) 137 return -EPERM; 138 139 if (!blk_queue_discard(q)) { 140 jfs_warn("FITRIM not supported on device"); 141 return -EOPNOTSUPP; 142 } 143 144 if (copy_from_user(&range, (struct fstrim_range __user *)arg, 145 sizeof(range))) 146 return -EFAULT; 147 148 range.minlen = max_t(unsigned int, range.minlen, 149 q->limits.discard_granularity); 150 151 ret = jfs_ioc_trim(inode, &range); 152 if (ret < 0) 153 return ret; 154 155 if (copy_to_user((struct fstrim_range __user *)arg, &range, 156 sizeof(range))) 157 return -EFAULT; 158 159 return 0; 160 } 161 162 default: 163 return -ENOTTY; 164 } 165 } 166 167 #ifdef CONFIG_COMPAT 168 long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 169 { 170 /* While these ioctl numbers defined with 'long' and have different 171 * numbers than the 64bit ABI, 172 * the actual implementation only deals with ints and is compatible. 173 */ 174 switch (cmd) { 175 case JFS_IOC_GETFLAGS32: 176 cmd = JFS_IOC_GETFLAGS; 177 break; 178 case JFS_IOC_SETFLAGS32: 179 cmd = JFS_IOC_SETFLAGS; 180 break; 181 } 182 return jfs_ioctl(filp, cmd, arg); 183 } 184 #endif 185