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