summaryrefslogtreecommitdiff
path: root/fs/read_write.c
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2024-08-30 15:04:48 +0200
committerChristian Brauner <brauner@kernel.org>2024-09-09 11:58:07 +0200
commited904935c3992ec4178a38f61eca8ce7303ae1a0 (patch)
tree7cedd353d8252443915b0b4c7a25cc9b3bcff199 /fs/read_write.c
parentb8c7451928ab2698653966a54ab5fff2fce484ff (diff)
fs: use must_set_pos()
Make generic_file_llseek_size() use must_set_pos(). We'll use must_set_pos() in another helper in a minutes. Remove __maybe_unused from must_set_pos() now that it's used. Link: https://lore.kernel.org/r/20240830-vfs-file-f_version-v1-7-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.c52
1 files changed, 14 insertions, 38 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index 5434467f5c05..b07e48cd81d1 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -98,8 +98,7 @@ EXPORT_SYMBOL(vfs_setpos);
* 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)
+static int must_set_pos(struct file *file, loff_t *offset, int whence, loff_t eof)
{
switch (whence) {
case SEEK_END:
@@ -159,45 +158,22 @@ loff_t
generic_file_llseek_size(struct file *file, loff_t offset, int whence,
loff_t maxsize, 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)
- return file->f_pos;
- /*
- * f_lock protects against read/modify/write race with other
- * SEEK_CURs. Note that parallel writes and reads behave
- * like SEEK_SET.
- */
- spin_lock(&file->f_lock);
- offset = vfs_setpos(file, file->f_pos + offset, maxsize);
- spin_unlock(&file->f_lock);
+ int ret;
+
+ ret = must_set_pos(file, &offset, whence, eof);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
return offset;
- 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:
+
+ if (whence == SEEK_CUR) {
/*
- * 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.
+ * f_lock protects against read/modify/write race with
+ * other SEEK_CURs. Note that parallel writes and reads
+ * behave like SEEK_SET.
*/
- if ((unsigned long long)offset >= eof)
- return -ENXIO;
- offset = eof;
- break;
+ guard(spinlock)(&file->f_lock);
+ return vfs_setpos(file, file->f_pos + offset, maxsize);
}
return vfs_setpos(file, offset, maxsize);