KernelNewbies
  • Comments
  • Immutable Page
  • Menu
    • Navigation
    • RecentChanges
    • FindPage
    • Local Site Map
    • Help
    • HelpContents
    • HelpOnMoinWikiSyntax
    • Display
    • Attachments
    • Info
    • Raw Text
    • Print View
    • Edit
    • Load
    • Save
  • Login

Kernel Hacking

  • Frontpage

  • Kernel Hacking

  • Kernel Documentation

  • Kernel Glossary

  • FAQ

  • Found a bug?

  • Kernel Changelog

  • Upstream Merge Guide

Projects

  • KernelJanitors

  • KernelMentors

  • KernelProjects

Community

  • Why a community?

  • Regional Kernelnewbies

  • Personal Pages

  • Upcoming Events

References

  • Mailing Lists

  • Related Sites

  • Programming Links

Wiki

  • Recent Changes

  • Site Editors

  • Side Bar

  • Tips for Editors

  • Hosted by WikiWall

Navigation

  • RecentChanges
  • FindPage
  • HelpContents

Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Revision 2 as of 2017-12-30 01:29:53
KernelNewbies:
  • NdevfsSource
/*
 * tyler@agat.net
 *
 * Nano DevFS (intended to Linux Kernel 2.6(.12))
 *
 * This module implements the nano dev file system from Greg KH.
 * This code is included in the main tree but I've writtent this module
 * because it's a very simple file system.
 *
 * ndevfs is a simple ramfs based filesystem. It creates/deletes 
 * nodes in the /dev directory dynamically in the format seen in devfs. 
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/device.h>

#define DRIVER_AUTHOR "tyler@agat.net"
#define DRIVER_DESC     "Ram File System"

#define MAGIC 0x64756d62

struct entry {
        struct list_head node;
        struct dentry *dentry;
        char name[BUS_ID_SIZE];
};

static LIST_HEAD(entries);

static struct vfsmount *mount;
static int mount_count;

static struct file_operations file_ops = {
                        read:           generic_file_read,
                        write:          generic_file_write,
                        mmap:           generic_file_mmap,
                        fsync:          simple_sync_file,
                        llseek:         generic_file_llseek,
};

static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
{
        struct inode *inode = new_inode(sb);

        if (inode) {
                inode->i_mode = mode;
                inode->i_uid = 0;
                inode->i_gid = 0;
                inode->i_blksize = PAGE_CACHE_SIZE;
                inode->i_blocks = 0;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                switch (mode & S_IFMT) {
                        case S_IFREG:
                                inode->i_fop = &file_ops;
                                break;
                        case S_IFDIR:
                                inode->i_op = &simple_dir_inode_operations;
                                inode->i_fop = &simple_dir_operations;
                                inode->i_nlink++;
                                break;
                }
        }

        return inode;
}

static int mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
        struct inode *inode = get_inode(dir->i_sb, mode, dev);

        if (dentry->d_inode) {
                return -EEXIST;
        }

        if (! inode) {
                return -EPERM;
        }

        d_instantiate(dentry, inode);
        dget(dentry);

        return 0;
}

static inline int positive(struct dentry *dentry)
{
        return dentry->d_inode && !d_unhashed(dentry);
}

static void remove(struct dentry *dentry)
{
        struct dentry *parent;

        if (!dentry) {
                return;
        }

        parent = dentry->d_parent;
        if (!parent || !parent->d_inode) {
                return;
        }

        down(&parent->d_inode->i_sem);
        if (positive(dentry)) {
                if (dentry->d_inode) {
                        if (S_ISDIR(dentry->d_inode->i_mode)) {
                                simple_rmdir(parent->d_inode, dentry);
                        }
                        else {
                                simple_unlink(parent->d_inode, dentry);
                        }
                }
        }
        up(&parent->d_inode->i_sem);
        simple_release_fs(&mount, &mount_count);
}

void mfs_create(const char *name, dev_t dev)
{
        struct dentry *dentry;
        struct dentry *parent;
        struct entry *entry;
        int err;
        int mode = S_IRUSR | S_IWUSR;

        mode |= S_IFREG;

        err = simple_pin_fs("mfs", &mount, &mount_count);
        if (err) {
                return;
        }

        if (mount && mount->mnt_sb) {
                parent = mount->mnt_sb->s_root;
        }
        else {
                pr_debug("%s: no parent?\n", __FUNCTION__);
                goto error;
        }

        down(&parent->d_inode->i_sem);
        dentry = lookup_one_len(name, parent, strlen(name));
        if (!IS_ERR(dentry)) {
                err = mknod(parent->d_inode, dentry, mode, dev);
        }
        else {
                err = PTR_ERR(dentry);
        }
        up(&parent->d_inode->i_sem);

        if (err) {
                goto error;
        }

        entry = kmalloc(sizeof(struct entry), GFP_KERNEL);
        if (!entry) {
                remove(dentry);
                err = -ENOMEM;
                goto error;
        }

        entry->dentry = dentry;
        strcpy(&entry->name[0], name);
        list_add(&entry->node, &entries);

        return;

error:
        pr_debug("%s failed with error %d\n", __FUNCTION__, err);
        simple_release_fs(&mount, &mount_count);
}

EXPORT_SYMBOL_GPL(mfs_create);

void mfs_remove(const char *name)
{
        struct entry *entry;
        struct dentry *dentry = NULL;

        list_for_each_entry(entry, &entries, node) {
                if (strcmp(&entry->name[0], name) == 0) {
                        dentry = entry->dentry;
                        break;
                }
        }

        if (!dentry) {
                pr_debug("%s: can't find %s\n", __FUNCTION__, name);
                return;
        }

        remove(dentry);
}

EXPORT_SYMBOL_GPL(mfs_remove);

static int fill_super(struct super_block *sb, void *data, int silent)
{
        static struct tree_descr files[] = {{""}};

        return simple_fill_super(sb, MAGIC, files);
}

static struct super_block *get_sb(struct file_system_type *fs_type,
                int flags, const char *dev_name, void *data)
{
        return get_sb_single(fs_type, flags, data, fill_super);
}

static struct file_system_type mfs = {
        owner:          THIS_MODULE,
        name:           "mfs",
        get_sb:         get_sb,
        kill_sb:        kill_litter_super,
};

int __init loading(void)
{
        return register_filesystem(&mfs);
}

void __exit unloading(void)
{
        simple_release_fs(&mount, &mount_count);
        unregister_filesystem(&mfs);
}

module_init(loading);
module_exit(unloading);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
  • MoinMoin Powered
  • Python Powered
  • GPL licensed
  • Valid HTML 4.01