1 /* 2 * linux/fs/ocfs2/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/mount.h> 10 11 #define MLOG_MASK_PREFIX ML_INODE 12 #include <cluster/masklog.h> 13 14 #include "ocfs2.h" 15 #include "alloc.h" 16 #include "dlmglue.h" 17 #include "file.h" 18 #include "inode.h" 19 #include "journal.h" 20 21 #include "ocfs2_fs.h" 22 #include "ioctl.h" 23 #include "resize.h" 24 25 #include <linux/ext2_fs.h> 26 27 static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) 28 { 29 int status; 30 31 status = ocfs2_inode_lock(inode, NULL, 0); 32 if (status < 0) { 33 mlog_errno(status); 34 return status; 35 } 36 ocfs2_get_inode_flags(OCFS2_I(inode)); 37 *flags = OCFS2_I(inode)->ip_attr; 38 ocfs2_inode_unlock(inode, 0); 39 40 mlog_exit(status); 41 return status; 42 } 43 44 static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, 45 unsigned mask) 46 { 47 struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); 48 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 49 handle_t *handle = NULL; 50 struct buffer_head *bh = NULL; 51 unsigned oldflags; 52 int status; 53 54 mutex_lock(&inode->i_mutex); 55 56 status = ocfs2_inode_lock(inode, &bh, 1); 57 if (status < 0) { 58 mlog_errno(status); 59 goto bail; 60 } 61 62 status = -EROFS; 63 if (IS_RDONLY(inode)) 64 goto bail_unlock; 65 66 status = -EACCES; 67 if (!is_owner_or_cap(inode)) 68 goto bail_unlock; 69 70 if (!S_ISDIR(inode->i_mode)) 71 flags &= ~OCFS2_DIRSYNC_FL; 72 73 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 74 if (IS_ERR(handle)) { 75 status = PTR_ERR(handle); 76 mlog_errno(status); 77 goto bail_unlock; 78 } 79 80 oldflags = ocfs2_inode->ip_attr; 81 flags = flags & mask; 82 flags |= oldflags & ~mask; 83 84 /* 85 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 86 * the relevant capability. 87 */ 88 status = -EPERM; 89 if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) & 90 (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) { 91 if (!capable(CAP_LINUX_IMMUTABLE)) 92 goto bail_unlock; 93 } 94 95 ocfs2_inode->ip_attr = flags; 96 ocfs2_set_inode_flags(inode); 97 98 status = ocfs2_mark_inode_dirty(handle, inode, bh); 99 if (status < 0) 100 mlog_errno(status); 101 102 ocfs2_commit_trans(osb, handle); 103 bail_unlock: 104 ocfs2_inode_unlock(inode, 1); 105 bail: 106 mutex_unlock(&inode->i_mutex); 107 108 if (bh) 109 brelse(bh); 110 111 mlog_exit(status); 112 return status; 113 } 114 115 int ocfs2_ioctl(struct inode * inode, struct file * filp, 116 unsigned int cmd, unsigned long arg) 117 { 118 unsigned int flags; 119 int new_clusters; 120 int status; 121 struct ocfs2_space_resv sr; 122 struct ocfs2_new_group_input input; 123 124 switch (cmd) { 125 case OCFS2_IOC_GETFLAGS: 126 status = ocfs2_get_inode_attr(inode, &flags); 127 if (status < 0) 128 return status; 129 130 flags &= OCFS2_FL_VISIBLE; 131 return put_user(flags, (int __user *) arg); 132 case OCFS2_IOC_SETFLAGS: 133 if (get_user(flags, (int __user *) arg)) 134 return -EFAULT; 135 136 return ocfs2_set_inode_attr(inode, flags, 137 OCFS2_FL_MODIFIABLE); 138 case OCFS2_IOC_RESVSP: 139 case OCFS2_IOC_RESVSP64: 140 case OCFS2_IOC_UNRESVSP: 141 case OCFS2_IOC_UNRESVSP64: 142 if (copy_from_user(&sr, (int __user *) arg, sizeof(sr))) 143 return -EFAULT; 144 145 return ocfs2_change_file_space(filp, cmd, &sr); 146 case OCFS2_IOC_GROUP_EXTEND: 147 if (!capable(CAP_SYS_RESOURCE)) 148 return -EPERM; 149 150 if (get_user(new_clusters, (int __user *)arg)) 151 return -EFAULT; 152 153 return ocfs2_group_extend(inode, new_clusters); 154 case OCFS2_IOC_GROUP_ADD: 155 case OCFS2_IOC_GROUP_ADD64: 156 if (!capable(CAP_SYS_RESOURCE)) 157 return -EPERM; 158 159 if (copy_from_user(&input, (int __user *) arg, sizeof(input))) 160 return -EFAULT; 161 162 return ocfs2_group_add(inode, &input); 163 default: 164 return -ENOTTY; 165 } 166 } 167 168 #ifdef CONFIG_COMPAT 169 long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) 170 { 171 struct inode *inode = file->f_path.dentry->d_inode; 172 int ret; 173 174 switch (cmd) { 175 case OCFS2_IOC32_GETFLAGS: 176 cmd = OCFS2_IOC_GETFLAGS; 177 break; 178 case OCFS2_IOC32_SETFLAGS: 179 cmd = OCFS2_IOC_SETFLAGS; 180 break; 181 case OCFS2_IOC_RESVSP: 182 case OCFS2_IOC_RESVSP64: 183 case OCFS2_IOC_UNRESVSP: 184 case OCFS2_IOC_UNRESVSP64: 185 case OCFS2_IOC_GROUP_EXTEND: 186 case OCFS2_IOC_GROUP_ADD: 187 case OCFS2_IOC_GROUP_ADD64: 188 break; 189 default: 190 return -ENOIOCTLCMD; 191 } 192 193 lock_kernel(); 194 ret = ocfs2_ioctl(inode, file, cmd, arg); 195 unlock_kernel(); 196 return ret; 197 } 198 #endif 199