linux/fs/fs_struct.c
<<
>>
Prefs
   1#include <linux/export.h>
   2#include <linux/sched.h>
   3#include <linux/fs.h>
   4#include <linux/path.h>
   5#include <linux/slab.h>
   6#include <linux/fs_struct.h>
   7#include "internal.h"
   8
   9static inline void path_get_longterm(struct path *path)
  10{
  11        path_get(path);
  12        mnt_make_longterm(path->mnt);
  13}
  14
  15static inline void path_put_longterm(struct path *path)
  16{
  17        mnt_make_shortterm(path->mnt);
  18        path_put(path);
  19}
  20
  21/*
  22 * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
  23 * It can block.
  24 */
  25void set_fs_root(struct fs_struct *fs, struct path *path)
  26{
  27        struct path old_root;
  28
  29        path_get_longterm(path);
  30        spin_lock(&fs->lock);
  31        write_seqcount_begin(&fs->seq);
  32        old_root = fs->root;
  33        fs->root = *path;
  34        write_seqcount_end(&fs->seq);
  35        spin_unlock(&fs->lock);
  36        if (old_root.dentry)
  37                path_put_longterm(&old_root);
  38}
  39
  40/*
  41 * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
  42 * It can block.
  43 */
  44void set_fs_pwd(struct fs_struct *fs, struct path *path)
  45{
  46        struct path old_pwd;
  47
  48        path_get_longterm(path);
  49        spin_lock(&fs->lock);
  50        write_seqcount_begin(&fs->seq);
  51        old_pwd = fs->pwd;
  52        fs->pwd = *path;
  53        write_seqcount_end(&fs->seq);
  54        spin_unlock(&fs->lock);
  55
  56        if (old_pwd.dentry)
  57                path_put_longterm(&old_pwd);
  58}
  59
  60static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
  61{
  62        if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
  63                return 0;
  64        *p = *new;
  65        return 1;
  66}
  67
  68void chroot_fs_refs(struct path *old_root, struct path *new_root)
  69{
  70        struct task_struct *g, *p;
  71        struct fs_struct *fs;
  72        int count = 0;
  73
  74        read_lock(&tasklist_lock);
  75        do_each_thread(g, p) {
  76                task_lock(p);
  77                fs = p->fs;
  78                if (fs) {
  79                        int hits = 0;
  80                        spin_lock(&fs->lock);
  81                        write_seqcount_begin(&fs->seq);
  82                        hits += replace_path(&fs->root, old_root, new_root);
  83                        hits += replace_path(&fs->pwd, old_root, new_root);
  84                        write_seqcount_end(&fs->seq);
  85                        while (hits--) {
  86                                count++;
  87                                path_get_longterm(new_root);
  88                        }
  89                        spin_unlock(&fs->lock);
  90                }
  91                task_unlock(p);
  92        } while_each_thread(g, p);
  93        read_unlock(&tasklist_lock);
  94        while (count--)
  95                path_put_longterm(old_root);
  96}
  97
  98void free_fs_struct(struct fs_struct *fs)
  99{
 100        path_put_longterm(&fs->root);
 101        path_put_longterm(&fs->pwd);
 102        kmem_cache_free(fs_cachep, fs);
 103}
 104
 105void exit_fs(struct task_struct *tsk)
 106{
 107        struct fs_struct *fs = tsk->fs;
 108
 109        if (fs) {
 110                int kill;
 111                task_lock(tsk);
 112                spin_lock(&fs->lock);
 113                tsk->fs = NULL;
 114                kill = !--fs->users;
 115                spin_unlock(&fs->lock);
 116                task_unlock(tsk);
 117                if (kill)
 118                        free_fs_struct(fs);
 119        }
 120}
 121
 122struct fs_struct *copy_fs_struct(struct fs_struct *old)
 123{
 124        struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
 125        /* We don't need to lock fs - think why ;-) */
 126        if (fs) {
 127                fs->users = 1;
 128                fs->in_exec = 0;
 129                spin_lock_init(&fs->lock);
 130                seqcount_init(&fs->seq);
 131                fs->umask = old->umask;
 132
 133                spin_lock(&old->lock);
 134                fs->root = old->root;
 135                path_get_longterm(&fs->root);
 136                fs->pwd = old->pwd;
 137                path_get_longterm(&fs->pwd);
 138                spin_unlock(&old->lock);
 139        }
 140        return fs;
 141}
 142
 143int unshare_fs_struct(void)
 144{
 145        struct fs_struct *fs = current->fs;
 146        struct fs_struct *new_fs = copy_fs_struct(fs);
 147        int kill;
 148
 149        if (!new_fs)
 150                return -ENOMEM;
 151
 152        task_lock(current);
 153        spin_lock(&fs->lock);
 154        kill = !--fs->users;
 155        current->fs = new_fs;
 156        spin_unlock(&fs->lock);
 157        task_unlock(current);
 158
 159        if (kill)
 160                free_fs_struct(fs);
 161
 162        return 0;
 163}
 164EXPORT_SYMBOL_GPL(unshare_fs_struct);
 165
 166int current_umask(void)
 167{
 168        return current->fs->umask;
 169}
 170EXPORT_SYMBOL(current_umask);
 171
 172/* to be mentioned only in INIT_TASK */
 173struct fs_struct init_fs = {
 174        .users          = 1,
 175        .lock           = __SPIN_LOCK_UNLOCKED(init_fs.lock),
 176        .seq            = SEQCNT_ZERO,
 177        .umask          = 0022,
 178};
 179
 180void daemonize_fs_struct(void)
 181{
 182        struct fs_struct *fs = current->fs;
 183
 184        if (fs) {
 185                int kill;
 186
 187                task_lock(current);
 188
 189                spin_lock(&init_fs.lock);
 190                init_fs.users++;
 191                spin_unlock(&init_fs.lock);
 192
 193                spin_lock(&fs->lock);
 194                current->fs = &init_fs;
 195                kill = !--fs->users;
 196                spin_unlock(&fs->lock);
 197
 198                task_unlock(current);
 199                if (kill)
 200                        free_fs_struct(fs);
 201        }
 202}
 203
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.