summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2023-10-05 19:08:35 +0200
committerChristian Brauner <brauner@kernel.org>2023-10-19 11:02:49 +0200
commit6cf41fcfe099b61b4e3ea7dbe04a906f4c904822 (patch)
tree0586ef64ce77176e2cb86a9a17ad256e6ac6a5c9
parent7116c0af4b8414b2f19fdb366eea213cbd9d91c2 (diff)
backing file: free directly
Backing files as used by overlayfs are never installed into file descriptor tables and are explicitly documented as such. They aren't subject to rcu access conditions like regular files are. Their lifetime is bound to the lifetime of the overlayfs file, i.e., they're stashed in ovl_file->private_data and go away otherwise. If they're set as vma->vm_file - which is their main purpose - then they're subject to regular refcount rules and vma->vm_file can't be installed into an fdtable after having been set. All in all I don't see any need for rcu delay here. So free it directly. This all hinges on such hybrid beasts to never actually be installed into fdtables which - as mentioned before - is not allowed. So add an explicit WARN_ON_ONCE() so we catch any case where someone is suddenly trying to install one of those things into a file descriptor table so we can have a nice long chat with them. Link: https://lore.kernel.org/r/20231005-sakralbau-wappnen-f5c31755ed70@brauner Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/file.c3
-rw-r--r--fs/file_table.c9
2 files changed, 4 insertions, 8 deletions
diff --git a/fs/file.c b/fs/file.c
index 4eb026631673..1a475d7d636e 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -604,6 +604,9 @@ void fd_install(unsigned int fd, struct file *file)
struct files_struct *files = current->files;
struct fdtable *fdt;
+ if (WARN_ON_ONCE(unlikely(file->f_mode & FMODE_BACKING)))
+ return;
+
rcu_read_lock_sched();
if (unlikely(files->resize_in_progress)) {
diff --git a/fs/file_table.c b/fs/file_table.c
index a79a80031343..08fd1dd6d863 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -61,13 +61,6 @@ struct path *backing_file_real_path(struct file *f)
}
EXPORT_SYMBOL_GPL(backing_file_real_path);
-static void file_free_rcu(struct rcu_head *head)
-{
- struct file *f = container_of(head, struct file, f_rcuhead);
-
- kfree(backing_file(f));
-}
-
static inline void file_free(struct file *f)
{
security_file_free(f);
@@ -76,7 +69,7 @@ static inline void file_free(struct file *f)
put_cred(f->f_cred);
if (unlikely(f->f_mode & FMODE_BACKING)) {
path_put(backing_file_real_path(f));
- call_rcu(&f->f_rcuhead, file_free_rcu);
+ kfree(backing_file(f));
} else {
kmem_cache_free(filp_cachep, f);
}