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