diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 88d3cb2eaf75..32c980ae0f1c 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 | ||
141 | static 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 | |||
141 | static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | 159 | static 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)); |