1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/ext2/ioctl.c 4 * 5 * Copyright (C) 1993, 1994, 1995 6 * Remy Card (card@masi.ibp.fr) 7 * Laboratoire MASI - Institut Blaise Pascal 8 * Universite Pierre et Marie Curie (Paris VI) 9 */ 10 11 #include "ext2.h" 12 #include <linux/capability.h> 13 #include <linux/time.h> 14 #include <linux/sched.h> 15 #include <linux/compat.h> 16 #include <linux/mount.h> 17 #include <asm/current.h> 18 #include <linux/uaccess.h> 19 #include <linux/fileattr.h> 20 21 int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa) 22 { 23 struct ext2_inode_info *ei = EXT2_I(d_inode(dentry)); 24 25 fileattr_fill_flags(fa, ei->i_flags & EXT2_FL_USER_VISIBLE); 26 27 return 0; 28 } 29 30 int ext2_fileattr_set(struct user_namespace *mnt_userns, 31 struct dentry *dentry, struct fileattr *fa) 32 { 33 struct inode *inode = d_inode(dentry); 34 struct ext2_inode_info *ei = EXT2_I(inode); 35 36 if (fileattr_has_fsx(fa)) 37 return -EOPNOTSUPP; 38 39 /* Is it quota file? Do not allow user to mess with it */ 40 if (IS_NOQUOTA(inode)) 41 return -EPERM; 42 43 ei->i_flags = (ei->i_flags & ~EXT2_FL_USER_MODIFIABLE) | 44 (fa->flags & EXT2_FL_USER_MODIFIABLE); 45 46 ext2_set_inode_flags(inode); 47 inode->i_ctime = current_time(inode); 48 mark_inode_dirty(inode); 49 50 return 0; 51 } 52 53 54 long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 55 { 56 struct inode *inode = file_inode(filp); 57 struct ext2_inode_info *ei = EXT2_I(inode); 58 unsigned short rsv_window_size; 59 int ret; 60 61 ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 62 63 switch (cmd) { 64 case EXT2_IOC_GETVERSION: 65 return put_user(inode->i_generation, (int __user *) arg); 66 case EXT2_IOC_SETVERSION: { 67 __u32 generation; 68 69 if (!inode_owner_or_capable(&init_user_ns, inode)) 70 return -EPERM; 71 ret = mnt_want_write_file(filp); 72 if (ret) 73 return ret; 74 if (get_user(generation, (int __user *) arg)) { 75 ret = -EFAULT; 76 goto setversion_out; 77 } 78 79 inode_lock(inode); 80 inode->i_ctime = current_time(inode); 81 inode->i_generation = generation; 82 inode_unlock(inode); 83 84 mark_inode_dirty(inode); 85 setversion_out: 86 mnt_drop_write_file(filp); 87 return ret; 88 } 89 case EXT2_IOC_GETRSVSZ: 90 if (test_opt(inode->i_sb, RESERVATION) 91 && S_ISREG(inode->i_mode) 92 && ei->i_block_alloc_info) { 93 rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 94 return put_user(rsv_window_size, (int __user *)arg); 95 } 96 return -ENOTTY; 97 case EXT2_IOC_SETRSVSZ: { 98 99 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 100 return -ENOTTY; 101 102 if (!inode_owner_or_capable(&init_user_ns, inode)) 103 return -EACCES; 104 105 if (get_user(rsv_window_size, (int __user *)arg)) 106 return -EFAULT; 107 108 ret = mnt_want_write_file(filp); 109 if (ret) 110 return ret; 111 112 if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) 113 rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; 114 115 /* 116 * need to allocate reservation structure for this inode 117 * before set the window size 118 */ 119 /* 120 * XXX What lock should protect the rsv_goal_size? 121 * Accessed in ext2_get_block only. ext3 uses i_truncate. 122 */ 123 mutex_lock(&ei->truncate_mutex); 124 if (!ei->i_block_alloc_info) 125 ext2_init_block_alloc_info(inode); 126 127 if (ei->i_block_alloc_info){ 128 struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 129 rsv->rsv_goal_size = rsv_window_size; 130 } else { 131 ret = -ENOMEM; 132 } 133 134 mutex_unlock(&ei->truncate_mutex); 135 mnt_drop_write_file(filp); 136 return ret; 137 } 138 default: 139 return -ENOTTY; 140 } 141 } 142 143 #ifdef CONFIG_COMPAT 144 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 145 { 146 /* These are just misnamed, they actually get/put from/to user an int */ 147 switch (cmd) { 148 case EXT2_IOC32_GETVERSION: 149 cmd = EXT2_IOC_GETVERSION; 150 break; 151 case EXT2_IOC32_SETVERSION: 152 cmd = EXT2_IOC_SETVERSION; 153 break; 154 default: 155 return -ENOIOCTLCMD; 156 } 157 return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 158 } 159 #endif 160