aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 88d3cb2eaf7..32c980ae0f1 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -138,6 +138,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
138 return 0; 138 return 0;
139} 139}
140 140
141static int check_flags(unsigned int flags)
142{
143 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
144 FS_NOATIME_FL | FS_NODUMP_FL | \
145 FS_SYNC_FL | FS_DIRSYNC_FL | \
146 FS_NOCOMP_FL | FS_COMPR_FL | \
147 FS_NOCOW_FL | FS_COW_FL))
148 return -EOPNOTSUPP;
149
150 if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL))
151 return -EINVAL;
152
153 if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL))
154 return -EINVAL;
155
156 return 0;
157}
158
141static int btrfs_ioctl_setflags(struct file *file, void __user *arg) 159static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
142{ 160{
143 struct inode *inode = file->f_path.dentry->d_inode; 161 struct inode *inode = file->f_path.dentry->d_inode;
@@ -153,10 +171,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
153 if (copy_from_user(&flags, arg, sizeof(flags))) 171 if (copy_from_user(&flags, arg, sizeof(flags)))
154 return -EFAULT; 172 return -EFAULT;
155 173
156 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ 174 ret = check_flags(flags);
157 FS_NOATIME_FL | FS_NODUMP_FL | \ 175 if (ret)
158 FS_SYNC_FL | FS_DIRSYNC_FL)) 176 return ret;
159 return -EOPNOTSUPP;
160 177
161 if (!is_owner_or_cap(inode)) 178 if (!is_owner_or_cap(inode))
162 return -EACCES; 179 return -EACCES;
@@ -201,6 +218,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
201 else 218 else
202 ip->flags &= ~BTRFS_INODE_DIRSYNC; 219 ip->flags &= ~BTRFS_INODE_DIRSYNC;
203 220
221 /*
222 * The COMPRESS flag can only be changed by users, while the NOCOMPRESS
223 * flag may be changed automatically if compression code won't make
224 * things smaller.
225 */
226 if (flags & FS_NOCOMP_FL) {
227 ip->flags &= ~BTRFS_INODE_COMPRESS;
228 ip->flags |= BTRFS_INODE_NOCOMPRESS;
229 } else if (flags & FS_COMPR_FL) {
230 ip->flags |= BTRFS_INODE_COMPRESS;
231 ip->flags &= ~BTRFS_INODE_NOCOMPRESS;
232 }
233 if (flags & FS_NOCOW_FL)
234 ip->flags |= BTRFS_INODE_NODATACOW;
235 else if (flags & FS_COW_FL)
236 ip->flags &= ~BTRFS_INODE_NODATACOW;
204 237
205 trans = btrfs_join_transaction(root, 1); 238 trans = btrfs_join_transaction(root, 1);
206 BUG_ON(IS_ERR(trans)); 239 BUG_ON(IS_ERR(trans));