mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
fs: don't needlessly acquire f_lock
Before 2011 there was no meaningful synchronization between read/readdir/write/seek. Only in commit ef3d0fd27e90 ("vfs: do (nearly) lockless generic_file_llseek") synchronization was added for SEEK_CUR by taking f_lock around vfs_setpos(). Then in 2014 full synchronization between read/readdir/write/seek was added in commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") by introducing f_pos_lock for regular files with FMODE_ATOMIC_POS and for directories. At that point taking f_lock became unnecessary for such files. So only acquire f_lock for SEEK_CUR if this isn't a file that would have acquired f_pos_lock if necessary. Link: https://lore.kernel.org/r/20250207-daten-mahlzeit-99d2079864fb@brauner Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
1bb772565f
commit
da06e3c517
10
fs/file.c
10
fs/file.c
@ -1182,6 +1182,16 @@ static inline bool file_needs_f_pos_lock(struct file *file)
|
||||
(file_count(file) > 1 || file->f_op->iterate_shared);
|
||||
}
|
||||
|
||||
bool file_seek_cur_needs_f_lock(struct file *file)
|
||||
{
|
||||
if (!(file->f_mode & FMODE_ATOMIC_POS) && !file->f_op->iterate_shared)
|
||||
return false;
|
||||
|
||||
VFS_WARN_ON_ONCE((file_count(file) > 1) &&
|
||||
!mutex_is_locked(&file->f_pos_lock));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct fd fdget_pos(unsigned int fd)
|
||||
{
|
||||
struct fd f = fdget(fd);
|
||||
|
@ -338,3 +338,4 @@ static inline bool path_mounted(const struct path *path)
|
||||
return path->mnt->mnt_root == path->dentry;
|
||||
}
|
||||
void file_f_owner_release(struct file *file);
|
||||
bool file_seek_cur_needs_f_lock(struct file *file);
|
||||
|
@ -169,11 +169,16 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
|
||||
|
||||
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.
|
||||
* If the file requires locking via f_pos_lock we know
|
||||
* that mutual exclusion for SEEK_CUR on the same file
|
||||
* is guaranteed. If the file isn't locked, we take
|
||||
* f_lock to protect against f_pos races with other
|
||||
* SEEK_CURs.
|
||||
*/
|
||||
guard(spinlock)(&file->f_lock);
|
||||
if (file_seek_cur_needs_f_lock(file)) {
|
||||
guard(spinlock)(&file->f_lock);
|
||||
return vfs_setpos(file, file->f_pos + offset, maxsize);
|
||||
}
|
||||
return vfs_setpos(file, file->f_pos + offset, maxsize);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user