Message ID | 20240830-vfs-file-f_version-v1-8-6d3e4816aa7b@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | file: remove f_version | expand |
On Fri 30-08-24 15:04:49, Christian Brauner wrote: > 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. > > Signed-off-by: Christian Brauner <brauner@kernel.org> Looks good. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza > --- > fs/read_write.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/fs.h | 2 ++ > 2 files changed, 46 insertions(+) > > diff --git a/fs/read_write.c b/fs/read_write.c > index ad93b72cc378..47f7b4e32a53 100644 > --- a/fs/read_write.c > +++ b/fs/read_write.c > @@ -179,6 +179,50 @@ 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; > + > + ret = must_set_pos(file, &offset, whence, eof); > + if (ret < 0) > + return ret; > + if (ret == 0) > + return offset; > + > + if (whence == SEEK_CUR) { > + /* > + * f_lock protects against read/modify/write race with > + * other SEEK_CURs. Note that parallel writes and reads > + * behave like SEEK_SET. > + */ > + guard(spinlock)(&file->f_lock); > + 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 > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 58c91a52cad1..3e6b3c1afb31 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -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); > > -- > 2.45.2 >
diff --git a/fs/read_write.c b/fs/read_write.c index ad93b72cc378..47f7b4e32a53 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -179,6 +179,50 @@ 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; + + ret = must_set_pos(file, &offset, whence, eof); + if (ret < 0) + return ret; + if (ret == 0) + return offset; + + if (whence == SEEK_CUR) { + /* + * f_lock protects against read/modify/write race with + * other SEEK_CURs. Note that parallel writes and reads + * behave like SEEK_SET. + */ + guard(spinlock)(&file->f_lock); + 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 diff --git a/include/linux/fs.h b/include/linux/fs.h index 58c91a52cad1..3e6b3c1afb31 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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);
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. Signed-off-by: Christian Brauner <brauner@kernel.org> --- fs/read_write.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 46 insertions(+)