From: Namjae Jeon <namjae.jeon@xxxxxxxxxxx> Add new flag(FALLOC_FL_COLLAPSE_RANGE) for fallocate. updated detailed semantics in comments. Signed-off-by: Namjae Jeon <namjae.jeon@xxxxxxxxxxx> Signed-off-by: Ashish Sangwan <a.sangwan@xxxxxxxxxxx> --- fs/open.c | 24 +++++++++++++++++++++--- include/uapi/linux/falloc.h | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/fs/open.c b/fs/open.c index 7931f76..85d243a 100644 --- a/fs/open.c +++ b/fs/open.c @@ -225,12 +225,14 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); long ret; + unsigned blksize_mask = (1 << inode->i_blkbits) - 1; if (offset < 0 || len <= 0) 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 */ @@ -241,8 +243,12 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) 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)) @@ -270,6 +276,18 @@ 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; + /* + * Collapse range works only on fs block size aligned offsets. + * Check if collapse range is contained within (aligned)i_size. + * Collapse range can only be used exclusively. + */ + if ((mode & FALLOC_FL_COLLAPSE_RANGE) && + (offset & blksize_mask || len & blksize_mask || + mode & ~FALLOC_FL_COLLAPSE_RANGE || + (offset + len > + round_up(i_size_read(inode), (blksize_mask + 1))))) + return -EINVAL; + if (!file->f_op->fallocate) return -EOPNOTSUPP; diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h index 990c4cc..9614b72 100644 --- a/include/uapi/linux/falloc.h +++ b/include/uapi/linux/falloc.h @@ -4,6 +4,23 @@ #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ #define FALLOC_FL_NO_HIDE_STALE 0x04 /* reserved codepoint */ +/* + * FALLOC_FL_COLLAPSE_RANGE: + * This flag works in 2 steps. + * Firstly, it deallocates any data blocks present between [offset, offset+len) + * This step is same as punch hole and leaves a hole in the place from where + * the blocks are removed. + * Next, it eliminates the hole created by moving data blocks into it. + * For extent based file systems, we achieve this functionality simply by + * updating the starting logical offset of each extent which appears beyond + * the hole. As this flag works on blocks of filesystem, the offset and len + * provided to fallocate should be aligned with block size of filesystem. + * The semantics of this flag are: + * 1) It should be used exclusively. No other fallocate flag in combination. + * 2) Offset and len supplied to fallocate should be aligned with block size. + * 3) (offset + len) could not be greater than file size. + */ +#define FALLOC_FL_COLLAPSE_RANGE 0x08 /* it does not leave a hole */ #endif /* _UAPI_FALLOC_H_ */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html