diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 29 |
1 files changed, 26 insertions, 3 deletions
@@ -231,7 +231,13 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
231 | return -EINVAL; | 231 | return -EINVAL; |
232 | 232 | ||
233 | /* Return error if mode is not supported */ | 233 | /* Return error if mode is not supported */ |
234 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | 234 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | |
235 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) | ||
236 | return -EOPNOTSUPP; | ||
237 | |||
238 | /* Punch hole and zero range are mutually exclusive */ | ||
239 | if ((mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) == | ||
240 | (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) | ||
235 | return -EOPNOTSUPP; | 241 | return -EOPNOTSUPP; |
236 | 242 | ||
237 | /* Punch hole must have keep size set */ | 243 | /* Punch hole must have keep size set */ |
@@ -239,11 +245,20 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
239 | !(mode & FALLOC_FL_KEEP_SIZE)) | 245 | !(mode & FALLOC_FL_KEEP_SIZE)) |
240 | return -EOPNOTSUPP; | 246 | return -EOPNOTSUPP; |
241 | 247 | ||
248 | /* Collapse range should only be used exclusively. */ | ||
249 | if ((mode & FALLOC_FL_COLLAPSE_RANGE) && | ||
250 | (mode & ~FALLOC_FL_COLLAPSE_RANGE)) | ||
251 | return -EINVAL; | ||
252 | |||
242 | if (!(file->f_mode & FMODE_WRITE)) | 253 | if (!(file->f_mode & FMODE_WRITE)) |
243 | return -EBADF; | 254 | return -EBADF; |
244 | 255 | ||
245 | /* It's not possible punch hole on append only file */ | 256 | /* |
246 | if (mode & FALLOC_FL_PUNCH_HOLE && IS_APPEND(inode)) | 257 | * It's not possible to punch hole or perform collapse range |
258 | * on append only file | ||
259 | */ | ||
260 | if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE) | ||
261 | && IS_APPEND(inode)) | ||
247 | return -EPERM; | 262 | return -EPERM; |
248 | 263 | ||
249 | if (IS_IMMUTABLE(inode)) | 264 | if (IS_IMMUTABLE(inode)) |
@@ -271,6 +286,14 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
271 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) | 286 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) |
272 | return -EFBIG; | 287 | return -EFBIG; |
273 | 288 | ||
289 | /* | ||
290 | * There is no need to overlap collapse range with EOF, in which case | ||
291 | * it is effectively a truncate operation | ||
292 | */ | ||
293 | if ((mode & FALLOC_FL_COLLAPSE_RANGE) && | ||
294 | (offset + len >= i_size_read(inode))) | ||
295 | return -EINVAL; | ||
296 | |||
274 | if (!file->f_op->fallocate) | 297 | if (!file->f_op->fallocate) |
275 | return -EOPNOTSUPP; | 298 | return -EOPNOTSUPP; |
276 | 299 | ||