Skip to content

Commit 57413d8

Browse files
Christoph Hellwigbrauner
authored andcommitted
fs: sort out the fallocate mode vs flag mess
The fallocate system call takes a mode argument, but that argument contains a wild mix of exclusive modes and an optional flags. Replace FALLOC_FL_SUPPORTED_MASK with FALLOC_FL_MODE_MASK, which excludes the optional flag bit, so that we can use switch statement on the value to easily enumerate the cases while getting the check for duplicate modes for free. To make this (and in the future the file system implementations) more readable also add a symbolic name for the 0 mode used to allocate blocks. Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/r/20240827065123.1762168-4-hch@lst.de Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent f951171 commit 57413d8

File tree

3 files changed

+38
-32
lines changed

3 files changed

+38
-32
lines changed

fs/open.c

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -252,40 +252,39 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
252252
if (offset < 0 || len <= 0)
253253
return -EINVAL;
254254

255-
/* Return error if mode is not supported */
256-
if (mode & ~FALLOC_FL_SUPPORTED_MASK)
255+
if (mode & ~(FALLOC_FL_MODE_MASK | FALLOC_FL_KEEP_SIZE))
257256
return -EOPNOTSUPP;
258257

259-
/* Punch hole and zero range are mutually exclusive */
260-
if ((mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) ==
261-
(FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE))
262-
return -EOPNOTSUPP;
263-
264-
/* Punch hole must have keep size set */
265-
if ((mode & FALLOC_FL_PUNCH_HOLE) &&
266-
!(mode & FALLOC_FL_KEEP_SIZE))
258+
/*
259+
* Modes are exclusive, even if that is not obvious from the encoding
260+
* as bit masks and the mix with the flag in the same namespace.
261+
*
262+
* To make things even more complicated, FALLOC_FL_ALLOCATE_RANGE is
263+
* encoded as no bit set.
264+
*/
265+
switch (mode & FALLOC_FL_MODE_MASK) {
266+
case FALLOC_FL_ALLOCATE_RANGE:
267+
case FALLOC_FL_UNSHARE_RANGE:
268+
case FALLOC_FL_ZERO_RANGE:
269+
break;
270+
case FALLOC_FL_PUNCH_HOLE:
271+
if (!(mode & FALLOC_FL_KEEP_SIZE))
272+
return -EOPNOTSUPP;
273+
break;
274+
case FALLOC_FL_COLLAPSE_RANGE:
275+
case FALLOC_FL_INSERT_RANGE:
276+
if (mode & FALLOC_FL_KEEP_SIZE)
277+
return -EOPNOTSUPP;
278+
break;
279+
default:
267280
return -EOPNOTSUPP;
268-
269-
/* Collapse range should only be used exclusively. */
270-
if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&
271-
(mode & ~FALLOC_FL_COLLAPSE_RANGE))
272-
return -EINVAL;
273-
274-
/* Insert range should only be used exclusively. */
275-
if ((mode & FALLOC_FL_INSERT_RANGE) &&
276-
(mode & ~FALLOC_FL_INSERT_RANGE))
277-
return -EINVAL;
278-
279-
/* Unshare range should only be used with allocate mode. */
280-
if ((mode & FALLOC_FL_UNSHARE_RANGE) &&
281-
(mode & ~(FALLOC_FL_UNSHARE_RANGE | FALLOC_FL_KEEP_SIZE)))
282-
return -EINVAL;
281+
}
283282

284283
if (!(file->f_mode & FMODE_WRITE))
285284
return -EBADF;
286285

287286
/*
288-
* We can only allow pure fallocate on append only files
287+
* On append-only files only space preallocation is supported.
289288
*/
290289
if ((mode & ~FALLOC_FL_KEEP_SIZE) && IS_APPEND(inode))
291290
return -EPERM;

include/linux/falloc.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@ struct space_resv {
2525
#define FS_IOC_UNRESVSP64 _IOW('X', 43, struct space_resv)
2626
#define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv)
2727

28-
#define FALLOC_FL_SUPPORTED_MASK (FALLOC_FL_KEEP_SIZE | \
29-
FALLOC_FL_PUNCH_HOLE | \
30-
FALLOC_FL_COLLAPSE_RANGE | \
31-
FALLOC_FL_ZERO_RANGE | \
32-
FALLOC_FL_INSERT_RANGE | \
33-
FALLOC_FL_UNSHARE_RANGE)
28+
/*
29+
* Mask of all supported fallocate modes. Only one can be set at a time.
30+
*
31+
* In addition to the mode bit, the mode argument can also encode flags.
32+
* FALLOC_FL_KEEP_SIZE is the only supported flag so far.
33+
*/
34+
#define FALLOC_FL_MODE_MASK (FALLOC_FL_ALLOCATE_RANGE | \
35+
FALLOC_FL_PUNCH_HOLE | \
36+
FALLOC_FL_COLLAPSE_RANGE | \
37+
FALLOC_FL_ZERO_RANGE | \
38+
FALLOC_FL_INSERT_RANGE | \
39+
FALLOC_FL_UNSHARE_RANGE)
3440

3541
/* on ia32 l_start is on a 32-bit boundary */
3642
#if defined(CONFIG_X86_64)

include/uapi/linux/falloc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#ifndef _UAPI_FALLOC_H_
33
#define _UAPI_FALLOC_H_
44

5+
#define FALLOC_FL_ALLOCATE_RANGE 0x00 /* allocate range */
56
#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */
67
#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */
78
#define FALLOC_FL_NO_HIDE_STALE 0x04 /* reserved codepoint */

0 commit comments

Comments
 (0)