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