]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: add generic_llseek_cookie()
authorChristian Brauner <brauner@kernel.org>
Fri, 30 Aug 2024 13:04:49 +0000 (15:04 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 9 Sep 2024 09:58:07 +0000 (11:58 +0200)
This is similar to generic_file_llseek() but allows the caller to
specify a cookie that will be updated to indicate that a seek happened.
Caller's requiring that information in their readdir implementations can
use that.

Link: https://lore.kernel.org/r/20240830-vfs-file-f_version-v1-8-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>
fs/read_write.c
include/linux/fs.h

index b07e48cd81d1ce7ff7503578d6f31e61a3094bf4..fb519e55c8e88f19f20e28ec4a4775fbc7f68c19 100644 (file)
@@ -180,6 +180,51 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
 }
 EXPORT_SYMBOL(generic_file_llseek_size);
 
+/**
+ * generic_llseek_cookie - versioned llseek implementation
+ * @file:      file structure to seek on
+ * @offset:    file offset to seek to
+ * @whence:    type of seek
+ * @cookie:    cookie to update
+ *
+ * See generic_file_llseek for a general description and locking assumptions.
+ *
+ * In contrast to generic_file_llseek, this function also resets a
+ * specified cookie to indicate a seek took place.
+ */
+loff_t generic_llseek_cookie(struct file *file, loff_t offset, int whence,
+                            u64 *cookie)
+{
+       struct inode *inode = file->f_mapping->host;
+       loff_t maxsize = inode->i_sb->s_maxbytes;
+       loff_t eof = i_size_read(inode);
+       int ret;
+
+       if (WARN_ON_ONCE(!cookie))
+               return -EINVAL;
+
+       /*
+        * Require that this is only used for directories that guarantee
+        * synchronization between readdir and seek so that an update to
+        * @cookie is correctly synchronized with concurrent readdir.
+        */
+       if (WARN_ON_ONCE(!(file->f_mode & FMODE_ATOMIC_POS)))
+               return -EINVAL;
+
+       ret = must_set_pos(file, &offset, whence, eof);
+       if (ret < 0)
+               return ret;
+       if (ret == 0)
+               return offset;
+
+       /* No need to hold f_lock because we know that f_pos_lock is held. */
+       if (whence == SEEK_CUR)
+               return vfs_setpos_cookie(file, file->f_pos + offset, maxsize, cookie);
+
+       return vfs_setpos_cookie(file, offset, maxsize, cookie);
+}
+EXPORT_SYMBOL(generic_llseek_cookie);
+
 /**
  * generic_file_llseek - generic llseek implementation for regular files
  * @file:      file structure to seek on
index 58c91a52cad1c95a405be5f043d86b1742f0260b..3e6b3c1afb3142e473ed366ab567232f2b5d512c 100644 (file)
@@ -3202,6 +3202,8 @@ extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
 extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
                int whence, loff_t maxsize, loff_t eof);
+loff_t generic_llseek_cookie(struct file *file, loff_t offset, int whence,
+                            u64 *cookie);
 extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
                int whence, loff_t size);
 extern loff_t no_seek_end_llseek_size(struct file *, loff_t, int, loff_t);