diff options
author | Christian Brauner <brauner@kernel.org> | 2024-08-30 15:04:47 +0200 |
---|---|---|
committer | Christian Brauner <brauner@kernel.org> | 2024-09-09 11:58:07 +0200 |
commit | b8c7451928ab2698653966a54ab5fff2fce484ff (patch) | |
tree | 45d8504fc9fb5e69ea1e0570cf529a2aedd32b90 /fs/read_write.c | |
parent | fs: add vfs_setpos_cookie() (diff) | |
download | linux-b8c7451928ab2698653966a54ab5fff2fce484ff.tar.xz linux-b8c7451928ab2698653966a54ab5fff2fce484ff.zip |
fs: add must_set_pos()
Add a new must_set_pos() helper. We will use it in follow-up patches.
Temporarily mark it as unused. This is only done to keep the diff small
and reviewable.
Link: https://lore.kernel.org/r/20240830-vfs-file-f_version-v1-6-6d3e4816aa7b@kernel.org
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index 66ff52860496..5434467f5c05 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -86,6 +86,60 @@ loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize) EXPORT_SYMBOL(vfs_setpos); /** + * must_set_pos - check whether f_pos has to be updated + * @file: file to seek on + * @offset: offset to use + * @whence: type of seek operation + * @eof: end of file + * + * Check whether f_pos needs to be updated and update @offset according + * to @whence. + * + * Return: 0 if f_pos doesn't need to be updated, 1 if f_pos has to be + * updated, and negative error code on failure. + */ +static __maybe_unused int must_set_pos(struct file *file, loff_t *offset, + int whence, loff_t eof) +{ + switch (whence) { + case SEEK_END: + *offset += eof; + break; + case SEEK_CUR: + /* + * Here we special-case the lseek(fd, 0, SEEK_CUR) + * position-querying operation. Avoid rewriting the "same" + * f_pos value back to the file because a concurrent read(), + * write() or lseek() might have altered it + */ + if (*offset == 0) { + *offset = file->f_pos; + return 0; + } + break; + case SEEK_DATA: + /* + * In the generic case the entire file is data, so as long as + * offset isn't at the end of the file then the offset is data. + */ + if ((unsigned long long)*offset >= eof) + return -ENXIO; + break; + case SEEK_HOLE: + /* + * There is a virtual hole at the end of the file, so as long as + * offset isn't i_size or larger, return i_size. + */ + if ((unsigned long long)*offset >= eof) + return -ENXIO; + *offset = eof; + break; + } + + return 1; +} + +/** * generic_file_llseek_size - generic llseek implementation for regular files * @file: file structure to seek on * @offset: file offset to seek to |