|
@@ -231,7 +231,8 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
|
|
return -EINVAL;
|
|
|
|
|
|
/* Return error if mode is not supported */
|
|
|
- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
|
|
|
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
|
|
|
+ FALLOC_FL_COLLAPSE_RANGE))
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
/* Punch hole must have keep size set */
|
|
@@ -239,11 +240,20 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
|
|
!(mode & FALLOC_FL_KEEP_SIZE))
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
+ /* Collapse range should only be used exclusively. */
|
|
|
+ if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&
|
|
|
+ (mode & ~FALLOC_FL_COLLAPSE_RANGE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
if (!(file->f_mode & FMODE_WRITE))
|
|
|
return -EBADF;
|
|
|
|
|
|
- /* It's not possible punch hole on append only file */
|
|
|
- if (mode & FALLOC_FL_PUNCH_HOLE && IS_APPEND(inode))
|
|
|
+ /*
|
|
|
+ * It's not possible to punch hole or perform collapse range
|
|
|
+ * on append only file
|
|
|
+ */
|
|
|
+ if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE)
|
|
|
+ && IS_APPEND(inode))
|
|
|
return -EPERM;
|
|
|
|
|
|
if (IS_IMMUTABLE(inode))
|
|
@@ -271,6 +281,14 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
|
|
if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
|
|
|
return -EFBIG;
|
|
|
|
|
|
+ /*
|
|
|
+ * There is no need to overlap collapse range with EOF, in which case
|
|
|
+ * it is effectively a truncate operation
|
|
|
+ */
|
|
|
+ if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&
|
|
|
+ (offset + len >= i_size_read(inode)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
if (!file->f_op->fallocate)
|
|
|
return -EOPNOTSUPP;
|
|
|
|