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