From bb3b2cfeb206f5b10b859e134651b54120e3f530 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Jun 2026 18:05:56 +0100 Subject: ARM: 9480/1: entry: expand comment in __switch_to As per discussion between the developers in the mail thread linked, expand the comment in __switch_to so that readers of the code understand what is going on. Suggested-by: Mark Rutland Acked-by: Mark Rutland Signed-off-by: Linus Walleij > Signed-off-by: Russell King --- fs/fs_struct.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 fs/fs_struct.c (limited to 'fs/fs_struct.c') diff --git a/fs/fs_struct.c b/fs/fs_struct.c new file mode 100644 index 000000000..394875d06 --- /dev/null +++ b/fs/fs_struct.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +/* + * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. + * It can block. + */ +void set_fs_root(struct fs_struct *fs, const struct path *path) +{ + struct path old_root; + + path_get(path); + write_seqlock(&fs->seq); + old_root = fs->root; + fs->root = *path; + write_sequnlock(&fs->seq); + if (old_root.dentry) + path_put(&old_root); +} + +/* + * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. + * It can block. + */ +void set_fs_pwd(struct fs_struct *fs, const struct path *path) +{ + struct path old_pwd; + + path_get(path); + write_seqlock(&fs->seq); + old_pwd = fs->pwd; + fs->pwd = *path; + write_sequnlock(&fs->seq); + + if (old_pwd.dentry) + path_put(&old_pwd); +} + +static inline int replace_path(struct path *p, const struct path *old, const struct path *new) +{ + if (likely(p->dentry != old->dentry || p->mnt != old->mnt)) + return 0; + *p = *new; + return 1; +} + +void chroot_fs_refs(const struct path *old_root, const struct path *new_root) +{ + struct task_struct *g, *p; + struct fs_struct *fs; + int count = 0; + + read_lock(&tasklist_lock); + for_each_process_thread(g, p) { + task_lock(p); + fs = p->fs; + if (fs) { + int hits = 0; + write_seqlock(&fs->seq); + hits += replace_path(&fs->root, old_root, new_root); + hits += replace_path(&fs->pwd, old_root, new_root); + while (hits--) { + count++; + path_get(new_root); + } + write_sequnlock(&fs->seq); + } + task_unlock(p); + } + read_unlock(&tasklist_lock); + while (count--) + path_put(old_root); +} + +void free_fs_struct(struct fs_struct *fs) +{ + path_put(&fs->root); + path_put(&fs->pwd); + kmem_cache_free(fs_cachep, fs); +} + +void exit_fs(struct task_struct *tsk) +{ + struct fs_struct *fs = tsk->fs; + + if (fs) { + int kill; + task_lock(tsk); + read_seqlock_excl(&fs->seq); + tsk->fs = NULL; + kill = !--fs->users; + read_sequnlock_excl(&fs->seq); + task_unlock(tsk); + if (kill) + free_fs_struct(fs); + } +} + +struct fs_struct *copy_fs_struct(struct fs_struct *old) +{ + struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); + /* We don't need to lock fs - think why ;-) */ + if (fs) { + fs->users = 1; + fs->in_exec = 0; + seqlock_init(&fs->seq); + fs->umask = old->umask; + + read_seqlock_excl(&old->seq); + fs->root = old->root; + path_get(&fs->root); + fs->pwd = old->pwd; + path_get(&fs->pwd); + read_sequnlock_excl(&old->seq); + } + return fs; +} + +int unshare_fs_struct(void) +{ + struct fs_struct *fs = current->fs; + struct fs_struct *new_fs = copy_fs_struct(fs); + int kill; + + if (!new_fs) + return -ENOMEM; + + task_lock(current); + read_seqlock_excl(&fs->seq); + kill = !--fs->users; + current->fs = new_fs; + read_sequnlock_excl(&fs->seq); + task_unlock(current); + + if (kill) + free_fs_struct(fs); + + return 0; +} +EXPORT_SYMBOL_GPL(unshare_fs_struct); + +/* to be mentioned only in INIT_TASK */ +struct fs_struct init_fs = { + .users = 1, + .seq = __SEQLOCK_UNLOCKED(init_fs.seq), + .umask = 0022, +}; -- cgit v1.3.1