linux-bk/fs/filesystems.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/filesystems.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 *
   6 *  table of configured filesystems
   7 */
   8
   9#include <linux/fs.h>
  10#include <linux/slab.h>
  11#include <linux/kmod.h>
  12#include <linux/module.h>
  13#include <asm/uaccess.h>
  14
  15/*
  16 * Handling of filesystem drivers list.
  17 * Rules:
  18 *      Inclusion to/removals from/scanning of list are protected by spinlock.
  19 *      During the unload module must call unregister_filesystem().
  20 *      We can access the fields of list element if:
  21 *              1) spinlock is held or
  22 *              2) we hold the reference to the module.
  23 *      The latter can be guaranteed by call of try_inc_mod_count(); if it
  24 *      returned 0 we must skip the element, otherwise we got the reference.
  25 *      Once the reference is obtained we can drop the spinlock.
  26 */
  27
  28static struct file_system_type *file_systems;
  29static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
  30
  31/* WARNING: This can be used only if we _already_ own a reference */
  32void get_filesystem(struct file_system_type *fs)
  33{
  34        if (fs->owner)
  35                __MOD_INC_USE_COUNT(fs->owner);
  36}
  37
  38void put_filesystem(struct file_system_type *fs)
  39{
  40        if (fs->owner)
  41                __MOD_DEC_USE_COUNT(fs->owner);
  42}
  43
  44static struct file_system_type **find_filesystem(const char *name)
  45{
  46        struct file_system_type **p;
  47        for (p=&file_systems; *p; p=&(*p)->next)
  48                if (strcmp((*p)->name,name) == 0)
  49                        break;
  50        return p;
  51}
  52
  53/**
  54 *      register_filesystem - register a new filesystem
  55 *      @fs: the file system structure
  56 *
  57 *      Adds the file system passed to the list of file systems the kernel
  58 *      is aware of for mount and other syscalls. Returns 0 on success,
  59 *      or a negative errno code on an error.
  60 *
  61 *      The &struct file_system_type that is passed is linked into the kernel 
  62 *      structures and must not be freed until the file system has been
  63 *      unregistered.
  64 */
  65 
  66int register_filesystem(struct file_system_type * fs)
  67{
  68        int res = 0;
  69        struct file_system_type ** p;
  70
  71        if (!fs)
  72                return -EINVAL;
  73        if (fs->next)
  74                return -EBUSY;
  75        INIT_LIST_HEAD(&fs->fs_supers);
  76        write_lock(&file_systems_lock);
  77        p = find_filesystem(fs->name);
  78        if (*p)
  79                res = -EBUSY;
  80        else
  81                *p = fs;
  82        write_unlock(&file_systems_lock);
  83        return res;
  84}
  85
  86/**
  87 *      unregister_filesystem - unregister a file system
  88 *      @fs: filesystem to unregister
  89 *
  90 *      Remove a file system that was previously successfully registered
  91 *      with the kernel. An error is returned if the file system is not found.
  92 *      Zero is returned on a success.
  93 *      
  94 *      Once this function has returned the &struct file_system_type structure
  95 *      may be freed or reused.
  96 */
  97 
  98int unregister_filesystem(struct file_system_type * fs)
  99{
 100        struct file_system_type ** tmp;
 101
 102        write_lock(&file_systems_lock);
 103        tmp = &file_systems;
 104        while (*tmp) {
 105                if (fs == *tmp) {
 106                        *tmp = fs->next;
 107                        fs->next = NULL;
 108                        write_unlock(&file_systems_lock);
 109                        return 0;
 110                }
 111                tmp = &(*tmp)->next;
 112        }
 113        write_unlock(&file_systems_lock);
 114        return -EINVAL;
 115}
 116
 117static int fs_index(const char * __name)
 118{
 119        struct file_system_type * tmp;
 120        char * name;
 121        int err, index;
 122
 123        name = getname(__name);
 124        err = PTR_ERR(name);
 125        if (IS_ERR(name))
 126                return err;
 127
 128        err = -EINVAL;
 129        read_lock(&file_systems_lock);
 130        for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
 131                if (strcmp(tmp->name,name) == 0) {
 132                        err = index;
 133                        break;
 134                }
 135        }
 136        read_unlock(&file_systems_lock);
 137        putname(name);
 138        return err;
 139}
 140
 141static int fs_name(unsigned int index, char * buf)
 142{
 143        struct file_system_type * tmp;
 144        int len, res;
 145
 146        read_lock(&file_systems_lock);
 147        for (tmp = file_systems; tmp; tmp = tmp->next, index--)
 148                if (index <= 0 && try_inc_mod_count(tmp->owner))
 149                                break;
 150        read_unlock(&file_systems_lock);
 151        if (!tmp)
 152                return -EINVAL;
 153
 154        /* OK, we got the reference, so we can safely block */
 155        len = strlen(tmp->name) + 1;
 156        res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
 157        put_filesystem(tmp);
 158        return res;
 159}
 160
 161static int fs_maxindex(void)
 162{
 163        struct file_system_type * tmp;
 164        int index;
 165
 166        read_lock(&file_systems_lock);
 167        for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
 168                ;
 169        read_unlock(&file_systems_lock);
 170        return index;
 171}
 172
 173/*
 174 * Whee.. Weird sysv syscall. 
 175 */
 176asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
 177{
 178        int retval = -EINVAL;
 179
 180        switch (option) {
 181                case 1:
 182                        retval = fs_index((const char *) arg1);
 183                        break;
 184
 185                case 2:
 186                        retval = fs_name(arg1, (char *) arg2);
 187                        break;
 188
 189                case 3:
 190                        retval = fs_maxindex();
 191                        break;
 192        }
 193        return retval;
 194}
 195
 196int get_filesystem_list(char * buf)
 197{
 198        int len = 0;
 199        struct file_system_type * tmp;
 200
 201        read_lock(&file_systems_lock);
 202        tmp = file_systems;
 203        while (tmp && len < PAGE_SIZE - 80) {
 204                len += sprintf(buf+len, "%s\t%s\n",
 205                        (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
 206                        tmp->name);
 207                tmp = tmp->next;
 208        }
 209        read_unlock(&file_systems_lock);
 210        return len;
 211}
 212
 213struct file_system_type *get_fs_type(const char *name)
 214{
 215        struct file_system_type *fs;
 216
 217        read_lock(&file_systems_lock);
 218        fs = *(find_filesystem(name));
 219        if (fs && !try_inc_mod_count(fs->owner))
 220                fs = NULL;
 221        read_unlock(&file_systems_lock);
 222        if (!fs && (request_module(name) == 0)) {
 223                read_lock(&file_systems_lock);
 224                fs = *(find_filesystem(name));
 225                if (fs && !try_inc_mod_count(fs->owner))
 226                        fs = NULL;
 227                read_unlock(&file_systems_lock);
 228        }
 229        return fs;
 230}
 231
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.