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 = -EACCES; 63 if (!is_owner_or_cap(inode)) 64 goto bail_unlock; 65 66 if (!S_ISDIR(inode->i_mode)) 67 flags &= ~OCFS2_DIRSYNC_FL; 68 69 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 70 if (IS_ERR(handle)) { 71 status = PTR_ERR(handle); 72 mlog_errno(status); 73 goto bail_unlock; 74 } 75 76 oldflags = ocfs2_inode->ip_attr; 77 flags = flags & mask; 78 flags |= oldflags & ~mask; 79 80 /* 81 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 82 * the relevant capability. 83 */ 84 status = -EPERM; 85 if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) & 86 (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) { 87 if (!capable(CAP_LINUX_IMMUTABLE)) 88 goto bail_unlock; 89 } 90 91 ocfs2_inode->ip_attr = flags; 92 ocfs2_set_inode_flags(inode); 93 94 status = ocfs2_mark_inode_dirty(handle, inode, bh); 95 if (status < 0) 96 mlog_errno(status); 97 98 ocfs2_commit_trans(osb, handle); 99 bail_unlock: 100 ocfs2_inode_unlock(inode, 1); 101 bail: 102 mutex_unlock(&inode->i_mutex); 103 104 brelse(bh); 105 106 mlog_exit(status); 107 return status; 108 } 109 110 long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 111 { 112 struct inode *inode = filp->f_path.dentry->d_inode; 113 unsigned int flags; 114 int new_clusters; 115 int status; 116 struct ocfs2_space_resv sr; 117 struct ocfs2_new_group_input input; 118 119 switch (cmd) { 120 case OCFS2_IOC_GETFLAGS: 121 status = ocfs2_get_inode_attr(inode, &flags); 122 if (status < 0) 123 return status; 124 125 flags &= OCFS2_FL_VISIBLE; 126 return put_user(flags, (int __user *) arg); 127 case OCFS2_IOC_SETFLAGS: 128 if (get_user(flags, (int __user *) arg)) 129 return -EFAULT; 130 131 status = mnt_want_write(filp->f_path.mnt); 132 if (status) 133 return status; 134 status = ocfs2_set_inode_attr(inode, flags, 135 OCFS2_FL_MODIFIABLE); 136 mnt_drop_write(filp->f_path.mnt); 137 return status; 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 switch (cmd) { 172 case OCFS2_IOC32_GETFLAGS: 173 cmd = OCFS2_IOC_GETFLAGS; 174 break; 175 case OCFS2_IOC32_SETFLAGS: 176 cmd = OCFS2_IOC_SETFLAGS; 177 break; 178 case OCFS2_IOC_RESVSP: 179 case OCFS2_IOC_RESVSP64: 180 case OCFS2_IOC_UNRESVSP: 181 case OCFS2_IOC_UNRESVSP64: 182 case OCFS2_IOC_GROUP_EXTEND: 183 case OCFS2_IOC_GROUP_ADD: 184 case OCFS2_IOC_GROUP_ADD64: 185 break; 186 default: 187 return -ENOIOCTLCMD; 188 } 189 190 return ocfs2_ioctl(file, cmd, arg); 191 } 192 #endif 193