Filesystems are free to implement any subset of fallocate modes and there is currently no way of telling what modes are actually supported by the file system other than trying them all. Change this by introducing new fallocate mode FALLOC_FL_QUERY_SUPPORT that is supposed to return all supported modes. FALLOC_FL_QUERY_SUPPORT mode can be only used exclusively with offset and length set to zero. Signed-off-by: Lukas Czerner <lczerner@xxxxxxxxxx> --- fs/open.c | 18 +++++++++++++++++- include/linux/falloc.h | 4 +++- include/uapi/linux/falloc.h | 13 +++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/fs/open.c b/fs/open.c index 7ea1184..15c3fce 100644 --- a/fs/open.c +++ b/fs/open.c @@ -241,13 +241,22 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) struct inode *inode = file_inode(file); long ret; - if (offset < 0 || len <= 0) + if ((offset < 0 || len <= 0) && !(mode & FALLOC_FL_QUERY_SUPPORT)) return -EINVAL; /* Return error if mode is not supported */ if (mode & ~FALLOC_FL_SUPPORTED_MASK) return -EOPNOTSUPP; + /* offset and length are not used in query support */ + if ((mode & FALLOC_FL_QUERY_SUPPORT) && (offset != 0 || len != 0)) + return -EINVAL; + + /* Query support should only be used exclusively */ + if ((mode & FALLOC_FL_QUERY_SUPPORT) && + (mode & ~FALLOC_FL_QUERY_SUPPORT)) + return -EINVAL; + /* Punch hole and zero range are mutually exclusive */ if ((mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) == (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) @@ -328,6 +337,13 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (ret == 0) fsnotify_modify(file); + /* + * Let's not allow file systems return any random data, just fallocate + * modes. + */ + if ((ret > 0) && (mode & FALLOC_FL_QUERY_SUPPORT)) + ret &= FALLOC_FL_SUPPORTED_MASK; + file_end_write(file); return ret; } diff --git a/include/linux/falloc.h b/include/linux/falloc.h index 7494dc6..1558bce 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h @@ -26,6 +26,8 @@ struct space_resv { FALLOC_FL_COLLAPSE_RANGE | \ FALLOC_FL_ZERO_RANGE | \ FALLOC_FL_INSERT_RANGE | \ - FALLOC_FL_UNSHARE_RANGE) + FALLOC_FL_QUERY_SUPPORT | \ + FALLOC_FL_UNSHARE_RANGE | \ + FALLOC_FL_PREALLOC_RANGE) #endif /* _FALLOC_H_ */ diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h index b075f60..9959355 100644 --- a/include/uapi/linux/falloc.h +++ b/include/uapi/linux/falloc.h @@ -76,4 +76,17 @@ */ #define FALLOC_FL_UNSHARE_RANGE 0x40 +/* + * FALLOC_FL_QUERY_SUPPORT is used to query file system, or block device + * for a supported fallocate flags. + */ +#define FALLOC_FL_QUERY_SUPPORT 0x80 + +/* + * FALLOC_FL_PREALLOC_RANGE is a placeholder for a default preallocation + * mode. It has the same effect as not specifying any flag at all. We need + * this to report back support for this particular mode, + */ +#define FALLOC_FL_PREALLOC_RANGE 0x100 + #endif /* _UAPI_FALLOC_H_ */ -- 2.7.5