lkml.org 
[lkml]   [2009]   [Feb]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCHv2 1/5] VFS: DazukoFS, stackable-fs, file access control
    From
    Date
    Patch 1: Introduces DazukoFS as a nullfs. This is the raw stackable
    filesystem part of DazukoFS and does nothing except stack and
    pass filesystem calls to the lower filesystem.

    Patched against 2.6.29-rc3.

    Signed-off-by: John Ogness <dazukocode@ogness.net>
    ---
    Documentation/filesystems/dazukofs.txt | 81 ++
    fs/Kconfig | 1
    fs/Makefile | 1
    fs/dazukofs/Kconfig | 10
    fs/dazukofs/Makefile | 7
    fs/dazukofs/dazukofs_fs.h | 163 ++++
    fs/dazukofs/dentry.c | 163 ++++
    fs/dazukofs/file.c | 324 +++++++++
    fs/dazukofs/inode.c | 813 +++++++++++++++++++++++
    fs/dazukofs/mmap.c | 116 +++
    fs/dazukofs/super.c | 335 +++++++++
    11 files changed, 2014 insertions(+)
    Index: linux-2.6.28/fs/dazukofs/dazukofs_fs.h
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/dazukofs_fs.h 2009-02-03 07:41:04.000000000 +0100
    @@ -0,0 +1,163 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2004 Erez Zadok
    + Copyright (C) 2001-2004 Stony Brook University
    + Copyright (C) 2004-2007 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#ifndef __DAZUKOFS_FS_H
    +#define __DAZUKOFS_FS_H
    +
    +#include <linux/slab.h>
    +#include <linux/fs.h>
    +#include <linux/dcache.h>
    +#include <linux/mount.h>
    +
    +extern struct kmem_cache *dazukofs_dentry_info_cachep;
    +extern struct kmem_cache *dazukofs_file_info_cachep;
    +extern const struct file_operations dazukofs_main_fops;
    +extern const struct file_operations dazukofs_dir_fops;
    +extern struct dentry_operations dazukofs_dops;
    +extern const struct address_space_operations dazukofs_aops;
    +
    +extern int dazukofs_interpose(struct dentry *lower_dentry,
    + struct dentry *dentry, struct super_block *sb,
    + int already_hashed);
    +
    +struct dazukofs_sb_info {
    + struct super_block *lower_sb;
    +};
    +
    +struct dazukofs_inode_info {
    + struct inode *lower_inode;
    +
    + /*
    + * the inode (embedded)
    + */
    + struct inode vfs_inode;
    +};
    +
    +struct dazukofs_dentry_info {
    + struct dentry *lower_dentry;
    + struct vfsmount *lower_mnt;
    +};
    +
    +struct dazukofs_file_info {
    + struct file *lower_file;
    +};
    +
    +static inline struct dazukofs_sb_info *get_sb_private(
    + struct super_block *upper_sb)
    +{
    + return upper_sb->s_fs_info;
    +}
    +
    +static inline void set_sb_private(struct super_block *upper_sb,
    + struct dazukofs_sb_info *sbi)
    +{
    + upper_sb->s_fs_info = sbi;
    +}
    +
    +static inline struct super_block *get_lower_sb(struct super_block *upper_sb)
    +{
    + return get_sb_private(upper_sb)->lower_sb;
    +}
    +
    +static inline void set_lower_sb(struct super_block *upper_sb,
    + struct super_block *lower_sb)
    +{
    + struct dazukofs_sb_info *sbi = get_sb_private(upper_sb);
    + sbi->lower_sb = lower_sb;
    +}
    +
    +static inline struct dazukofs_inode_info *get_inode_private(
    + struct inode *upper_inode)
    +{
    + return container_of(upper_inode, struct dazukofs_inode_info,
    + vfs_inode);
    +}
    +
    +static inline struct inode *get_lower_inode(struct inode *upper_inode)
    +{
    + return get_inode_private(upper_inode)->lower_inode;
    +}
    +
    +static inline void set_lower_inode(struct inode *upper_inode,
    + struct inode *lower_inode)
    +{
    + struct dazukofs_inode_info *dii = get_inode_private(upper_inode);
    + dii->lower_inode = lower_inode;
    +}
    +
    +static inline struct dazukofs_dentry_info *get_dentry_private(
    + struct dentry *upper_dentry)
    +{
    + return upper_dentry->d_fsdata;
    +}
    +
    +static inline void set_dentry_private(struct dentry *upper_dentry,
    + struct dazukofs_dentry_info *dentryi)
    +{
    + upper_dentry->d_fsdata = dentryi;
    +}
    +
    +static inline struct dentry *get_lower_dentry(struct dentry *upper_dentry)
    +{
    + return get_dentry_private(upper_dentry)->lower_dentry;
    +}
    +
    +static inline struct vfsmount *get_lower_mnt(struct dentry *upper_dentry)
    +{
    + return get_dentry_private(upper_dentry)->lower_mnt;
    +}
    +
    +static inline void set_lower_dentry(struct dentry *upper_dentry,
    + struct dentry *lower_dentry,
    + struct vfsmount *lower_mnt)
    +{
    + struct dazukofs_dentry_info *dii = get_dentry_private(upper_dentry);
    + dii->lower_dentry = lower_dentry;
    + dii->lower_mnt = lower_mnt;
    +}
    +
    +static inline struct dazukofs_file_info *get_file_private(
    + struct file *upper_file)
    +{
    + return upper_file->private_data;
    +}
    +
    +static inline void set_file_private(struct file *upper_file,
    + struct dazukofs_file_info *filei)
    +{
    + upper_file->private_data = filei;
    +}
    +
    +static inline struct file *get_lower_file(struct file *upper_file)
    +{
    + return get_file_private(upper_file)->lower_file;
    +}
    +
    +static inline void set_lower_file(struct file *upper_file,
    + struct file *lower_file)
    +{
    + struct dazukofs_file_info *dfi = get_file_private(upper_file);
    + dfi->lower_file = lower_file;
    +}
    +
    +#endif /* __DAZUKOFS_FS_H */
    Index: linux-2.6.28/fs/dazukofs/dentry.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/dentry.c 2009-02-02 22:47:28.000000000 +0100
    @@ -0,0 +1,163 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2003 Erez Zadok
    + Copyright (C) 2001-2003 Stony Brook University
    + Copyright (C) 2004-2006 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#include <linux/module.h>
    +#include <linux/fs.h>
    +#include <linux/namei.h>
    +#include <linux/mount.h>
    +#include <linux/fs_stack.h>
    +
    +#include "dazukofs_fs.h"
    +
    +/**
    + * dazukofs_d_revalidate - revalidate a dentry found in the dcache
    + * @dentry: dentry to revalidate
    + * @nd: nameidata associated with dentry
    + *
    + * Description: Called when the VFS needs to revalidate a dentry. This is
    + * called whenever a name look-up finds a dentry in the dcache. Most
    + * filesystems leave this as NULL, because all their dentries in the dcache
    + * are valid.
    + *
    + * Call d_revalidate() on the lower dentry if available. The mnt/dentry
    + * (path) data in the nameidata needs to be temporarily swapped out for the
    + * lower call.
    + *
    + * After the call, the original path data is restored and the dentry's inode
    + * attributes are updated to match the lower inode.
    + *
    + * Returns 1 if dentry is valid, otherwise 0.
    + */
    +static int dazukofs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
    +{
    + struct vfsmount *lower_mnt = get_lower_mnt(dentry);
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct vfsmount *vfsmount_save = nd->path.mnt;
    + struct dentry *dentry_save = nd->path.dentry;
    + int valid;
    +
    + if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
    + return 1;
    +
    + nd->path.mnt = mntget(lower_mnt);
    + nd->path.dentry = dget(lower_dentry);
    +
    + valid = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
    +
    + mntput(lower_mnt);
    + dput(lower_dentry);
    +
    + nd->path.mnt = vfsmount_save;
    + nd->path.dentry = dentry_save;
    +
    + /* update the inode, even if d_revalidate() != 1 */
    + if (dentry->d_inode) {
    + struct inode *lower_inode = get_lower_inode(dentry->d_inode);
    + fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
    + }
    + return valid;
    +}
    +
    +/**
    + * dazukofs_d_hash - hash the given name
    + * @dentry: the parent dentry
    + * @name: the name to hash
    + *
    + * Description: Called when the VFS adds a dentry to the hash table.
    + *
    + * Call d_hash() on the lower dentry if available. Otherwise dazukofs
    + * does nothing. This is ok because the VFS will compute a default
    + * hash.
    + *
    + * Returns 0 on success.
    + */
    +static int dazukofs_d_hash(struct dentry *dentry, struct qstr *name)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    +
    + if (!lower_dentry->d_op || !lower_dentry->d_op->d_hash)
    + return 0;
    +
    + return lower_dentry->d_op->d_hash(lower_dentry, name);
    +}
    +
    +/**
    + * dazukofs_d_release - clean up dentry
    + * @dentry: the dentry that will be released
    + *
    + * Description: Called when a dentry is really deallocated.
    + *
    + * Release our hold on the lower dentry and mnt. Then free the structure
    + * (from the cache) containing the lower data for this dentry.
    + */
    +static void dazukofs_d_release(struct dentry *dentry)
    +{
    + if (get_dentry_private(dentry)) {
    + dput(get_lower_dentry(dentry));
    + mntput(get_lower_mnt(dentry));
    +
    + kmem_cache_free(dazukofs_dentry_info_cachep,
    + get_dentry_private(dentry));
    + }
    +}
    +
    +/**
    + * dazukofs_d_compare - used to compare dentry's
    + * @dentry: the parent dentry
    + * @a: qstr of an existing dentry
    + * @b: qstr of a second dentry (dentry may not be valid)
    + *
    + * Description: Called when a dentry should be compared with another.
    + *
    + * Call d_compare() on the lower dentry if available. Otherwise, perform
    + * some basic comparisons between the two qstr's.
    + *
    + * Returns 0 if they are the same, otherwise 1.
    + */
    +static int dazukofs_d_compare(struct dentry *dentry, struct qstr *a,
    + struct qstr *b)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    +
    + if (lower_dentry->d_op && lower_dentry->d_op->d_compare)
    + return lower_dentry->d_op->d_compare(lower_dentry, a, b);
    +
    + if (a->len != b->len)
    + return 1;
    + if (memcmp(a->name, b->name, a->len))
    + return 1;
    + return 0;
    +}
    +
    +/**
    + * Unused operations:
    + * - d_delete
    + * - d_iput
    + * - d_dname
    + */
    +struct dentry_operations dazukofs_dops = {
    + .d_revalidate = dazukofs_d_revalidate,
    + .d_hash = dazukofs_d_hash,
    + .d_release = dazukofs_d_release,
    + .d_compare = dazukofs_d_compare,
    +};
    Index: linux-2.6.28/fs/dazukofs/super.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/super.c 2009-02-03 18:07:52.000000000 +0100
    @@ -0,0 +1,335 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2003 Erez Zadok
    + Copyright (C) 2001-2003 Stony Brook University
    + Copyright (C) 2004-2006 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#include <linux/module.h>
    +#include <linux/version.h>
    +#include <linux/fs.h>
    +#include <linux/namei.h>
    +#include <linux/mount.h>
    +
    +#include "dazukofs_fs.h"
    +
    +static struct kmem_cache *dazukofs_inode_info_cachep;
    +static struct kmem_cache *dazukofs_sb_info_cachep;
    +struct kmem_cache *dazukofs_dentry_info_cachep;
    +struct kmem_cache *dazukofs_file_info_cachep;
    +
    +static struct inode *dazukofs_alloc_inode(struct super_block *sb)
    +{
    + struct dazukofs_inode_info *inodei =
    + kmem_cache_alloc(dazukofs_inode_info_cachep, GFP_KERNEL);
    + if (!inodei)
    + return NULL;
    +
    + /*
    + * The inode is embedded within the dazukofs_inode_info struct.
    + */
    + return &(inodei->vfs_inode);
    +}
    +
    +static void dazukofs_destroy_inode(struct inode *inode)
    +{
    + /*
    + * The inode is embedded within the dazukofs_inode_info struct.
    + */
    + kmem_cache_free(dazukofs_inode_info_cachep,
    + get_inode_private(inode));
    +}
    +
    +static int dazukofs_statfs(struct dentry *dentry, struct kstatfs *buf)
    +{
    + return vfs_statfs(get_lower_dentry(dentry), buf);
    +}
    +
    +static void dazukofs_clear_inode(struct inode *inode)
    +{
    + iput(get_lower_inode(inode));
    +}
    +
    +static void dazukofs_put_super(struct super_block *sb)
    +{
    + struct dazukofs_sb_info *sbi = get_sb_private(sb);
    + if (sbi)
    + kmem_cache_free(dazukofs_sb_info_cachep, sbi);
    +}
    +
    +/**
    + * Unused operations:
    + * - dirty_inode
    + * - write_inode
    + * - put_inode
    + * - drop_inode
    + * - delete_inode
    + * - write_super
    + * - sync_fs
    + * - write_super_lockfs
    + * - unlockfs
    + * - remount_fs
    + * - umount_begin
    + * - show_options
    + * - show_stats
    + * - quota_read
    + * - quota_write
    + */
    +static struct super_operations dazukofs_sops = {
    + .alloc_inode = dazukofs_alloc_inode,
    + .destroy_inode = dazukofs_destroy_inode,
    + .put_super = dazukofs_put_super,
    + .statfs = dazukofs_statfs,
    + .clear_inode = dazukofs_clear_inode,
    +};
    +
    +static int dazukofs_parse_mount_options(char *options, struct super_block *sb)
    +{
    + return 0;
    +}
    +
    +static int dazukofs_fill_super(struct super_block *sb, void *data, int silent)
    +{
    + struct dazukofs_sb_info *sbi;
    + struct dentry *root;
    + static const struct qstr name = { .name = "/", .len = 1 };
    + struct dazukofs_dentry_info *di;
    +
    + sbi = kmem_cache_zalloc(dazukofs_sb_info_cachep, GFP_KERNEL);
    + if (!sbi)
    + return -ENOMEM;
    +
    + sb->s_op = &dazukofs_sops;
    +
    + root = d_alloc(NULL, &name);
    + if (!root) {
    + kmem_cache_free(dazukofs_sb_info_cachep, sbi);
    + return -ENOMEM;
    + }
    +
    + sb->s_root = root;
    +
    + sb->s_root->d_op = &dazukofs_dops;
    + sb->s_root->d_sb = sb;
    + sb->s_root->d_parent = sb->s_root;
    +
    + di = kmem_cache_zalloc(dazukofs_dentry_info_cachep, GFP_KERNEL);
    + if (!di) {
    + kmem_cache_free(dazukofs_sb_info_cachep, sbi);
    + dput(sb->s_root);
    + return -ENOMEM;
    + }
    +
    + set_dentry_private(sb->s_root, di);
    +
    + set_sb_private(sb, sbi);
    +
    + return 0;
    +}
    +
    +static int dazukofs_read_super(struct super_block *sb, const char *dev_name)
    +{
    + struct nameidata nd;
    + struct dentry *lower_root;
    + struct vfsmount *lower_mnt;
    + int err;
    +
    + memset(&nd, 0, sizeof(struct nameidata));
    + err = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
    + if (err)
    + return err;
    +
    + lower_root = dget(nd.path.dentry);
    + lower_mnt = mntget(nd.path.mnt);
    +
    + if (IS_ERR(lower_root)) {
    + err = PTR_ERR(lower_root);
    + goto out_put;
    + }
    +
    + if (!lower_root->d_inode) {
    + err = -ENOENT;
    + goto out_put;
    + }
    +
    + set_lower_sb(sb, lower_root->d_sb);
    + sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
    + set_lower_dentry(sb->s_root, lower_root, lower_mnt);
    +
    + err = dazukofs_interpose(lower_root, sb->s_root, sb, 0);
    + if (err)
    + goto out_put;
    + goto out;
    +
    +out_put:
    + dput(lower_root);
    + mntput(lower_mnt);
    +out:
    + path_put(&nd.path);
    + return err;
    +}
    +
    +static int dazukofs_get_sb(struct file_system_type *fs_type, int flags,
    + const char *dev_name, void *data,
    + struct vfsmount *mnt)
    +{
    + struct super_block *sb;
    + int err;
    +
    + err = get_sb_nodev(fs_type, flags, data, dazukofs_fill_super, mnt);
    + if (err)
    + goto out;
    +
    + sb = mnt->mnt_sb;
    +
    + err = dazukofs_parse_mount_options(data, sb);
    + if (err)
    + goto out_abort;
    +
    + err = dazukofs_read_super(sb, dev_name);
    + if (err)
    + goto out_abort;
    +
    + goto out;
    +
    +out_abort:
    + up_write(&sb->s_umount);
    + deactivate_super(sb);
    +out:
    + return err;
    +}
    +
    +static void init_once(void *data)
    +{
    + struct dazukofs_inode_info *inode_info =
    + (struct dazukofs_inode_info *)data;
    +
    + memset(inode_info, 0, sizeof(struct dazukofs_inode_info));
    + inode_init_once(&(inode_info->vfs_inode));
    +}
    +
    +static void destroy_caches(void)
    +{
    + if (dazukofs_inode_info_cachep) {
    + kmem_cache_destroy(dazukofs_inode_info_cachep);
    + dazukofs_inode_info_cachep = NULL;
    + }
    +
    + if (dazukofs_sb_info_cachep) {
    + kmem_cache_destroy(dazukofs_sb_info_cachep);
    + dazukofs_sb_info_cachep = NULL;
    + }
    +
    + if (dazukofs_dentry_info_cachep) {
    + kmem_cache_destroy(dazukofs_dentry_info_cachep);
    + dazukofs_dentry_info_cachep = NULL;
    + }
    +
    + if (dazukofs_file_info_cachep) {
    + kmem_cache_destroy(dazukofs_file_info_cachep);
    + dazukofs_file_info_cachep = NULL;
    + }
    +}
    +
    +static int init_caches(void)
    +{
    + dazukofs_inode_info_cachep =
    + kmem_cache_create("dazukofs_inode_info_cache",
    + sizeof(struct dazukofs_inode_info), 0,
    + SLAB_HWCACHE_ALIGN,
    + init_once);
    + if (!dazukofs_inode_info_cachep)
    + goto out_nomem;
    +
    + dazukofs_sb_info_cachep =
    + kmem_cache_create("dazukofs_sb_info_cache",
    + sizeof(struct dazukofs_sb_info), 0,
    + SLAB_HWCACHE_ALIGN,
    + NULL);
    + if (!dazukofs_sb_info_cachep)
    + goto out_nomem;
    +
    + dazukofs_dentry_info_cachep =
    + kmem_cache_create("dazukofs_dentry_info_cache",
    + sizeof(struct dazukofs_dentry_info), 0,
    + SLAB_HWCACHE_ALIGN,
    + NULL);
    + if (!dazukofs_dentry_info_cachep)
    + goto out_nomem;
    +
    + dazukofs_file_info_cachep =
    + kmem_cache_create("dazukofs_file_info_cache",
    + sizeof(struct dazukofs_file_info), 0,
    + SLAB_HWCACHE_ALIGN,
    + NULL);
    + if (!dazukofs_file_info_cachep)
    + goto out_nomem;
    +
    + return 0;
    +
    +out_nomem:
    + destroy_caches();
    + return -ENOMEM;
    +}
    +
    +static struct file_system_type dazukofs_fs_type = {
    + .owner = THIS_MODULE,
    + .name = "dazukofs",
    + .get_sb = dazukofs_get_sb,
    + /*
    + * XXX: We are using kill_anon_super() instead of my own function.
    + * Is this OK?
    + */
    + .kill_sb = kill_anon_super,
    + .fs_flags = 0,
    +};
    +
    +static int __init init_dazukofs_fs(void)
    +{
    + int err;
    +
    + err = init_caches();
    + if (err)
    + goto error_out1;
    +
    + err = register_filesystem(&dazukofs_fs_type);
    + if (err)
    + goto error_out2;
    +
    + printk(KERN_INFO "dazukofs: loaded\n");
    + return 0;
    +
    +error_out2:
    + destroy_caches();
    +error_out1:
    + return err;
    +}
    +
    +static void __exit exit_dazukofs_fs(void)
    +{
    + unregister_filesystem(&dazukofs_fs_type);
    + destroy_caches();
    + printk(KERN_INFO "dazukofs: unloaded\n");
    +}
    +
    +MODULE_AUTHOR("John Ogness");
    +MODULE_DESCRIPTION("pass-through stackable filesystem");
    +MODULE_LICENSE("GPL");
    +module_init(init_dazukofs_fs)
    +module_exit(exit_dazukofs_fs)
    Index: linux-2.6.28/fs/dazukofs/file.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/file.c 2009-02-03 18:08:42.000000000 +0100
    @@ -0,0 +1,324 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2004 Erez Zadok
    + Copyright (C) 2001-2004 Stony Brook University
    + Copyright (C) 2004-2007 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#include <linux/module.h>
    +#include <linux/fs.h>
    +#include <linux/mount.h>
    +#include <linux/file.h>
    +#include <linux/fs_stack.h>
    +#include <linux/cred.h>
    +
    +#include "dazukofs_fs.h"
    +
    +/**
    + * Description: Called when the VFS needs to move the file position index.
    + */
    +static loff_t dazukofs_llseek(struct file *file, loff_t offset, int origin)
    +{
    + loff_t retval;
    + struct file *lower_file = get_lower_file(file);
    +
    + lower_file->f_pos = file->f_pos;
    +
    + memcpy(&(lower_file->f_ra), &(file->f_ra),
    + sizeof(struct file_ra_state));
    +
    + if (lower_file->f_op && lower_file->f_op->llseek)
    + retval = lower_file->f_op->llseek(lower_file, offset, origin);
    + else
    + retval = generic_file_llseek(lower_file, offset, origin);
    +
    + if (retval >= 0) {
    + file->f_pos = lower_file->f_pos;
    + file->f_version = lower_file->f_version;
    + }
    + return retval;
    +}
    +
    +/**
    + * Description: Called by read(2) and related system calls.
    + */
    +static ssize_t dazukofs_read(struct file *file, char *buf, size_t count,
    + loff_t *ppos)
    +{
    + int err;
    + struct file *lower_file = get_lower_file(file);
    + loff_t pos_copy = *ppos;
    +
    + if (!lower_file->f_op || !lower_file->f_op->read)
    + return -EINVAL;
    +
    + err = lower_file->f_op->read(lower_file, buf, count, &pos_copy);
    +
    + lower_file->f_pos = pos_copy;
    + *ppos = pos_copy;
    +
    + if (err >= 0) {
    + fsstack_copy_attr_atime(file->f_dentry->d_inode,
    + lower_file->f_dentry->d_inode);
    + }
    +
    + memcpy(&(file->f_ra), &(lower_file->f_ra),
    + sizeof(struct file_ra_state));
    + return err;
    +}
    +
    +/**
    + * Description: Called by write(2) and related system calls.
    + */
    +static ssize_t dazukofs_write(struct file *file, const char *buf,
    + size_t count, loff_t *ppos)
    +{
    + int err;
    + struct file *lower_file = get_lower_file(file);
    + struct inode *inode = file->f_dentry->d_inode;
    + struct inode *lower_inode = get_lower_inode(inode);
    + loff_t pos_copy = *ppos;
    +
    + if (!lower_file->f_op || !lower_file->f_op->write)
    + return -EINVAL;
    +
    + err = lower_file->f_op->write(lower_file, buf, count, &pos_copy);
    +
    + lower_file->f_pos = pos_copy;
    + *ppos = pos_copy;
    +
    + if (err >= 0)
    + fsstack_copy_attr_atime(inode, lower_inode);
    +
    + memcpy(&(file->f_ra), &(lower_file->f_ra),
    + sizeof(struct file_ra_state));
    +
    + mutex_lock(&inode->i_mutex);
    + i_size_write(inode, i_size_read(lower_inode));
    + mutex_unlock(&inode->i_mutex);
    + return err;
    +}
    +
    +/**
    + * Description: Called when the VFS needs to read the directory contents.
    + */
    +static int dazukofs_readdir(struct file *file, void *dirent, filldir_t filldir)
    +{
    + int err;
    + struct file *lower_file = get_lower_file(file);
    + struct inode *inode = file->f_dentry->d_inode;
    +
    + lower_file->f_pos = file->f_pos;
    +
    + err = vfs_readdir(lower_file, filldir, dirent);
    +
    + file->f_pos = lower_file->f_pos;
    +
    + if (err >= 0)
    + fsstack_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
    +
    + return err;
    +}
    +
    +/**
    + * Description: Called by the ioctl(2) system call.
    + */
    +static int dazukofs_ioctl(struct inode *inode, struct file *file,
    + unsigned int cmd, unsigned long arg)
    +{
    + struct file *lower_file = get_lower_file(file);
    + struct inode *lower_inode = get_lower_inode(inode);
    +
    + if (!lower_file->f_op || !lower_file->f_op->ioctl || !lower_inode)
    + return -ENOTTY;
    +
    + return lower_file->f_op->ioctl(lower_inode, lower_file, cmd, arg);
    +}
    +
    +/**
    + * Description: Called by the VFS when an inode should be opened. When the
    + * VFS opens a file, it creates a new "struct file". It then calls the open
    + * method for the newly allocated file structure. You might think that the
    + * open method really belongs in "struct inode_operations", and you may be
    + * right. I think it's done the way it is because it makes filesystems
    + * simpler to implement. The open() method is a good place to initialize
    + * the "private_data" member in the file structure if you want to point to
    + * a device structure.
    + */
    +static int dazukofs_open(struct inode *inode, struct file *file)
    +{
    + struct dentry *dentry = file->f_dentry;
    + struct dentry *lower_dentry = dget(get_lower_dentry(dentry));
    + struct vfsmount *lower_mnt = mntget(get_lower_mnt(dentry));
    + struct file *lower_file;
    + int err = 0;
    +
    + set_file_private(file, kmem_cache_zalloc(dazukofs_file_info_cachep,
    + GFP_KERNEL));
    + if (!get_file_private(file)) {
    + err = -ENOMEM;
    + goto error_out1;
    + }
    +
    + lower_file = dentry_open(lower_dentry, lower_mnt, file->f_flags,
    + current_cred());
    + if (IS_ERR(lower_file)) {
    + err = PTR_ERR(lower_file);
    + /* dentry_open() already did dput() and mntput() */
    + goto error_out2;
    + }
    +
    + set_lower_file(file, lower_file);
    +
    + return err;
    +
    +error_out1:
    + dput(lower_dentry);
    + mntput(lower_mnt);
    +error_out2:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the close(2) system call to flush a file.
    + */
    +static int dazukofs_flush(struct file *file, fl_owner_t td)
    +{
    + struct file *lower_file = get_lower_file(file);
    +
    + if (!lower_file->f_op || !lower_file->f_op->flush)
    + return 0;
    +
    + return lower_file->f_op->flush(lower_file, td);
    +}
    +
    +/**
    + * Description: Called when the last reference to an open file is closed.
    + */
    +static int dazukofs_release(struct inode *inode, struct file *file)
    +{
    + struct inode *lower_inode = get_lower_inode(inode);
    +
    + fput(get_lower_file(file));
    + inode->i_blocks = lower_inode->i_blocks;
    +
    + kmem_cache_free(dazukofs_file_info_cachep, get_file_private(file));
    + return 0;
    +}
    +
    +/**
    + * Description: Called by the fsync(2) system call.
    + */
    +static int dazukofs_fsync(struct file *file, struct dentry *dentry,
    + int datasync)
    +{
    + struct file *lower_file = get_lower_file(file);
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    +
    + if (!lower_file->f_op || !lower_file->f_op->fsync)
    + return -EINVAL;
    +
    + return lower_file->f_op->fsync(lower_file, lower_dentry, datasync);
    +}
    +
    +/**
    + * Description: .called by the fcntl(2) system call when asynchronous
    + * (non-blocking) mode is enabled for a file.
    + */
    +static int dazukofs_fasync(int fd, struct file *file, int flag)
    +{
    + struct file *lower_file = get_lower_file(file);
    +
    + if (!lower_file->f_op || !lower_file->f_op->fasync)
    + return 0;
    +
    + return lower_file->f_op->fasync(fd, lower_file, flag);
    +}
    +
    +/**
    + * Unused operations:
    + * - owner
    + * - aio_read (generic)
    + * - aio_write (generic)
    + * - poll
    + * - unlocked_ioctl
    + * - compat_ioctl
    + * - mmap (generic)
    + * - aio_fsync
    + * - lock
    + * - sendpage
    + * - get_unmapped_area
    + * - check_flags
    + * - dir_notify
    + * - flock
    + * - splice_write
    + * - splice_read (generic)
    + * - setlease
    + */
    +const struct file_operations dazukofs_main_fops = {
    + .llseek = dazukofs_llseek,
    + .read = dazukofs_read,
    + .aio_read = generic_file_aio_read,
    + .write = dazukofs_write,
    + .aio_write = generic_file_aio_write,
    + .readdir = dazukofs_readdir,
    + .ioctl = dazukofs_ioctl,
    + .mmap = generic_file_mmap,
    + .open = dazukofs_open,
    + .flush = dazukofs_flush,
    + .release = dazukofs_release,
    + .fsync = dazukofs_fsync,
    + .fasync = dazukofs_fasync,
    + .splice_read = generic_file_splice_read,
    +};
    +
    +/**
    + * Unused operations:
    + * - owner
    + * - llseek
    + * - read
    + * - write
    + * - aio_read
    + * - aio_write
    + * - poll
    + * - unlocked_ioctl
    + * - compat_ioctl
    + * - mmap (generic)
    + * - aio_fsync
    + * - lock
    + * - sendpage
    + * - get_unmapped_area
    + * - check_flags
    + * - dir_notify
    + * - flock
    + * - splice_write
    + * - splice_read (generic)
    + * - setlease
    + */
    +const struct file_operations dazukofs_dir_fops = {
    + .readdir = dazukofs_readdir,
    + .ioctl = dazukofs_ioctl,
    + .mmap = generic_file_mmap,
    + .open = dazukofs_open,
    + .flush = dazukofs_flush,
    + .release = dazukofs_release,
    + .fsync = dazukofs_fsync,
    + .fasync = dazukofs_fasync,
    + .splice_read = generic_file_splice_read,
    +};
    Index: linux-2.6.28/fs/dazukofs/inode.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/inode.c 2009-02-03 18:10:38.000000000 +0100
    @@ -0,0 +1,813 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2004 Erez Zadok
    + Copyright (C) 2001-2004 Stony Brook University
    + Copyright (C) 2004-2007 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#include <linux/module.h>
    +#include <linux/fs.h>
    +#include <linux/namei.h>
    +#include <linux/mount.h>
    +#include <linux/uaccess.h>
    +#include <linux/fs_stack.h>
    +
    +#include "dazukofs_fs.h"
    +
    +static struct inode_operations dazukofs_symlink_iops;
    +static struct inode_operations dazukofs_dir_iops;
    +static struct inode_operations dazukofs_main_iops;
    +
    +static int dazukofs_inode_test(struct inode *inode,
    + void *candidate_lower_inode)
    +{
    + if (get_lower_inode(inode) ==
    + (struct inode *)candidate_lower_inode) {
    + return 1;
    + }
    +
    + return 0;
    +}
    +
    +static void dazukofs_init_inode(struct inode *inode, struct inode *lower_inode)
    +{
    + set_lower_inode(inode, lower_inode);
    + inode->i_ino = lower_inode->i_ino;
    + inode->i_version++;
    + inode->i_op = &dazukofs_main_iops;
    + inode->i_fop = &dazukofs_main_fops;
    + inode->i_mapping->a_ops = &dazukofs_aops;
    +}
    +
    +static int dazukofs_inode_set(struct inode *inode, void *lower_inode)
    +{
    + dazukofs_init_inode(inode, (struct inode *)lower_inode);
    + return 0;
    +}
    +
    +/**
    + * dazukofs_interpose - fill in new dentry, linking it to the lower dentry
    + * @lower_dentry: the corresponding lower dentry
    + * @denty: the new DazukoFS dentry
    + * @sb: super block of DazukoFS
    + * @already_hashed: flag to signify if "dentry" is already hashed
    + *
    + * Description: This is the key function which sets up all the hooks to
    + * give DazukoFS control.
    + *
    + * Returns 0 on success.
    + */
    +int dazukofs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
    + struct super_block *sb, int already_hashed)
    +{
    + struct inode *inode;
    + struct inode *lower_inode = igrab(lower_dentry->d_inode);
    +
    + if (!lower_inode)
    + return -ESTALE;
    +
    + if (lower_inode->i_sb != get_lower_sb(sb)) {
    + iput(lower_inode);
    + return -EXDEV;
    + }
    +
    + inode = iget5_locked(sb, (unsigned long)lower_inode,
    + dazukofs_inode_test, dazukofs_inode_set,
    + lower_inode);
    +
    + if (!inode) {
    + iput(lower_inode);
    + return -EACCES;
    + }
    +
    + if (inode->i_state & I_NEW) {
    + unlock_new_inode(inode);
    + /*
    + * This is a new node so we leave the lower_node "in use"
    + * and do not call iput().
    + */
    + } else {
    + /*
    + * This is not a new node so we decrement the usage count.
    + */
    + iput(lower_inode);
    + }
    +
    + if (S_ISLNK(lower_inode->i_mode))
    + inode->i_op = &dazukofs_symlink_iops;
    + else if (S_ISDIR(lower_inode->i_mode))
    + inode->i_op = &dazukofs_dir_iops;
    +
    + if (S_ISDIR(lower_inode->i_mode))
    + inode->i_fop = &dazukofs_dir_fops;
    +
    + if (special_file(lower_inode->i_mode)) {
    + init_special_inode(inode, lower_inode->i_mode,
    + lower_inode->i_rdev);
    + }
    +
    + dentry->d_op = &dazukofs_dops;
    +
    + if (already_hashed)
    + d_add(dentry, inode);
    + else
    + d_instantiate(dentry, inode);
    +
    + fsstack_copy_attr_all(inode, lower_inode, NULL);
    + fsstack_copy_inode_size(inode, lower_inode);
    + return 0;
    +}
    +
    +/**
    + * Description: Called when the VFS needs to look up an inode in a parent
    + * directory. The name to look for is found in the dentry. This method
    + * must call d_add() to insert the found inode into the dentry. The
    + * "i_count" field in the inode structure should be incremented. If the
    + * named inode does not exist a NULL inode should be inserted into the
    + * dentry (this is called a negative dentry). Returning an error code
    + * from this routine must only be done on a real error, otherwise
    + * creating inodes with system calls like create(2), mknod(2), mkdir(2)
    + * and so on will fail. If you wish to overload the dentry methods then
    + * you should initialise the "d_dop" field in the dentry; this is a
    + * pointer to a struct "dentry_operations". This method is called with
    + * the directory inode semaphore held.
    + */
    +static struct dentry *dazukofs_lookup(struct inode *dir, struct dentry *dentry,
    + struct nameidata *nd)
    +{
    + struct dentry *lower_dentry;
    + struct dentry *lower_dentry_parent;
    + struct vfsmount *lower_mnt;
    + int err = 0;
    +
    + if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
    + || (dentry->d_name.len == 2 &&
    + !strcmp(dentry->d_name.name, ".."))) {
    + d_drop(dentry);
    + goto out;
    + }
    +
    + dentry->d_op = &dazukofs_dops;
    +
    + lower_dentry_parent = get_lower_dentry(dentry->d_parent);
    + lower_dentry = lookup_one_len(dentry->d_name.name,
    + lower_dentry_parent,
    + dentry->d_name.len);
    +
    + if (IS_ERR(lower_dentry)) {
    + err = PTR_ERR(lower_dentry);
    + d_drop(dentry);
    + goto out;
    + }
    +
    + BUG_ON(!atomic_read(&lower_dentry->d_count));
    +
    + set_dentry_private(dentry,
    + kmem_cache_zalloc(dazukofs_dentry_info_cachep,
    + GFP_KERNEL));
    +
    + if (!get_dentry_private(dentry)) {
    + err = -ENOMEM;
    + goto out_dput;
    + }
    +
    + lower_mnt = mntget(get_lower_mnt(dentry->d_parent));
    +
    + fsstack_copy_attr_atime(dir, lower_dentry_parent->d_inode);
    +
    + set_lower_dentry(dentry, lower_dentry, lower_mnt);
    +
    + if (!lower_dentry->d_inode) {
    + /*
    + * We want to add because we could not find in lower.
    + */
    + d_add(dentry, NULL);
    + goto out;
    + }
    +
    + err = dazukofs_interpose(lower_dentry, dentry, dir->i_sb, 1);
    + if (err)
    + goto out_dput;
    + goto out;
    +
    +out_dput:
    + dput(lower_dentry);
    + d_drop(dentry);
    +out:
    + return ERR_PTR(err);
    +}
    +
    +/**
    + * Description: Called by the mknod(2) system call to create a device
    + * (char, block) inode or a named pipe (FIFO) or socket. Only required if
    + * you want to support creating these types of inodes. You will probably
    + * need to call d_instantiate() just as you would in the create() method.
    + */
    +static int dazukofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
    + dev_t dev)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_mknod(lower_dentry_parent_inode, lower_dentry, mode, dev);
    + if (err)
    + goto out;
    +
    + err = dazukofs_interpose(lower_dentry, dentry, dir->i_sb, 0);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + fsstack_copy_inode_size(dir, lower_dentry_parent_inode);
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the mkdir(2) system call. Only required if you
    + * want to support creating subdirectories. You will probably need to call
    + * d_instantiate() just as you would in the create() method.
    + */
    +static int dazukofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_mkdir(lower_dentry_parent_inode, lower_dentry, mode);
    + if (err)
    + goto out;
    +
    + err = dazukofs_interpose(lower_dentry, dentry, dir->i_sb, 0);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + fsstack_copy_inode_size(dir, lower_dentry_parent_inode);
    + dir->i_nlink = lower_dentry_parent_inode->i_nlink;
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the open(2) and creat(2) system calls. Only
    + * required if you want to support regular files. The dentry you get
    + * should not have an inode (i.e. it should be a negative dentry). Here
    + * you will probably call d_instantiate() with the dentry and the newly
    + * created inode.
    + */
    +static int dazukofs_create(struct inode *dir, struct dentry *dentry, int mode,
    + struct nameidata *nd)
    +{
    + struct vfsmount *lower_mnt = get_lower_mnt(dentry);
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + struct vfsmount *vfsmount_save;
    + struct dentry *dentry_save;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + vfsmount_save = nd->path.mnt;
    + dentry_save = nd->path.dentry;
    +
    + nd->path.mnt = mntget(lower_mnt);
    + nd->path.dentry = dget(lower_dentry);
    +
    + err = vfs_create(lower_dentry_parent_inode, lower_dentry, mode, nd);
    +
    + mntput(lower_mnt);
    + dput(lower_dentry);
    +
    + nd->path.mnt = vfsmount_save;
    + nd->path.dentry = dentry_save;
    +
    + if (err)
    + goto out;
    +
    + err = dazukofs_interpose(lower_dentry, dentry, dir->i_sb, 0);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + fsstack_copy_inode_size(dir, lower_dentry_parent_inode);
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the symlink(2) system call. Only required if you
    + * want to support symlinks. You will probably need to call d_instantiate()
    + * just as you would in the create() method.
    + */
    +static int dazukofs_symlink(struct inode *dir, struct dentry *dentry,
    + const char *symname)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_symlink(lower_dentry_parent_inode, lower_dentry, symname);
    + if (err)
    + goto out;
    +
    + err = dazukofs_interpose(lower_dentry, dentry, dir->i_sb, 0);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + fsstack_copy_inode_size(dir, lower_dentry_parent_inode);
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the readlink(2) system call. Only required if
    + * you want to support reading symbolic links.
    + */
    +static int dazukofs_readlink(struct dentry *dentry, char __user *buf,
    + int bufsiz)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *lower_dentry_inode = lower_dentry->d_inode;
    + int err;
    +
    + if (!lower_dentry_inode) {
    + err = -ENOENT;
    + d_drop(dentry);
    + goto out;
    + }
    +
    + if (!lower_dentry_inode->i_op->readlink) {
    + err = -EINVAL;
    + goto out;
    + }
    +
    + err = lower_dentry_inode->i_op->readlink(lower_dentry, buf, bufsiz);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dentry->d_inode, lower_dentry_inode);
    +out:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the VFS to follow a symbolic link to the inode
    + * it points to. Only required if you want to support symbolic links. This
    + * method returns a void pointer cookie that is passed to put_link().
    + */
    +static void *dazukofs_follow_link(struct dentry *dentry, struct nameidata *nd)
    +{
    + mm_segment_t fs_save;
    + int rc;
    + char *buf;
    + int len = PAGE_SIZE;
    + int err = 0;
    +
    + /*
    + * Released in dazukofs_put_link(). Only release here on error.
    + */
    + buf = kmalloc(len, GFP_KERNEL);
    + if (!buf) {
    + err = -ENOMEM;
    + goto out;
    + }
    +
    + fs_save = get_fs();
    + set_fs(get_ds());
    + rc = dazukofs_readlink(dentry, (char __user *)buf, len);
    + set_fs(fs_save);
    +
    + if (rc < 0) {
    + err = rc;
    + goto out_free;
    + }
    + buf[rc] = 0;
    +
    + nd_set_link(nd, buf);
    + goto out;
    +
    +out_free:
    + kfree(buf);
    +out:
    + return ERR_PTR(err);
    +}
    +
    +/**
    + * Description: Called by the VFS to release resources allocated by
    + * follow_link(). The cookie returned by follow_link() is passed to this
    + * method as the last parameter. It is used by filesystems such as NFS
    + * where page cache is not stable (i.e. page that was installed when the
    + * symbolic link walk started might not be in the page cache at the end
    + * of the walk).
    + */
    +static void dazukofs_put_link(struct dentry *dentry, struct nameidata *nd,
    + void *ptr)
    +{
    + /*
    + * Release the char* from dazukofs_follow_link().
    + */
    + kfree(nd_get_link(nd));
    +}
    +
    +/**
    + * Description: Called by the VFS to check for access rights on a
    + * POSIX-like filesystem.
    + */
    +static int dazukofs_permission(struct inode *inode, int mask)
    +{
    + return inode_permission(get_lower_inode(inode), mask);
    +}
    +
    +/**
    + * Description: Called by the VFS to set attributes for a file. This method
    + * is called by chmod(2) and related system calls.
    + */
    +static int dazukofs_setattr(struct dentry *dentry, struct iattr *ia)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *inode = dentry->d_inode;
    + struct inode *lower_inode = get_lower_inode(inode);
    + int err;
    +
    + err = notify_change(lower_dentry, ia);
    +
    + fsstack_copy_attr_all(inode, lower_inode, NULL);
    + fsstack_copy_inode_size(inode, lower_inode);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the VFS to set an extended attribute for a file.
    + * Extended attribute is a name:value pair associated with an inode. This
    + * method is called by setxattr(2) system call.
    + */
    +static int dazukofs_setxattr(struct dentry *dentry, const char *name,
    + const void *value, size_t size, int flags)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *lower_dentry_inode = lower_dentry->d_inode;
    + int err;
    +
    + if (!lower_dentry_inode) {
    + err = -ENOENT;
    + d_drop(dentry);
    + goto out;
    + }
    +
    + if (!lower_dentry_inode->i_op->setxattr) {
    + err = -ENOSYS;
    + goto out;
    + }
    +
    + err = lower_dentry_inode->i_op->setxattr(lower_dentry, name, value,
    + size, flags);
    +
    + fsstack_copy_attr_all(dentry->d_inode, lower_dentry_inode, NULL);
    + fsstack_copy_inode_size(dentry->d_inode, lower_dentry_inode);
    +out:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the VFS to retrieve the value of an extended
    + * attribute name. This method is called by getxattr(2) function call.
    + */
    +static ssize_t dazukofs_getxattr(struct dentry *dentry, const char *name,
    + void *value, size_t size)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *lower_dentry_inode = lower_dentry->d_inode;
    + ssize_t err;
    +
    + if (!lower_dentry_inode) {
    + err = -ENOENT;
    + d_drop(dentry);
    + goto out;
    + }
    +
    + if (!lower_dentry_inode->i_op->getxattr) {
    + err = -ENOSYS;
    + goto out;
    + }
    +
    + err = lower_dentry_inode->i_op->getxattr(lower_dentry, name,
    + value, size);
    +out:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the VFS to list all extended attributes for a
    + * given file. This method is called by listxattr(2) system call.
    + */
    +static ssize_t dazukofs_listxattr(struct dentry *dentry, char *list,
    + size_t size)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *lower_dentry_inode = lower_dentry->d_inode;
    + int err;
    +
    + if (!lower_dentry_inode) {
    + err = -ENOENT;
    + d_drop(dentry);
    + goto out;
    + }
    +
    + if (!lower_dentry_inode->i_op->listxattr) {
    + err = -ENOSYS;
    + goto out;
    + }
    +
    + err = lower_dentry_inode->i_op->listxattr(lower_dentry, list, size);
    +out:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the VFS to remove an extended attribute from a
    + * file. This method is called by removexattr(2) system call.
    + */
    +static int dazukofs_removexattr(struct dentry *dentry, const char *name)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct inode *lower_dentry_inode = lower_dentry->d_inode;
    + int err;
    +
    + if (!lower_dentry_inode) {
    + err = -ENOENT;
    + d_drop(dentry);
    + goto out;
    + }
    +
    + if (!lower_dentry_inode->i_op->removexattr) {
    + err = -ENOSYS;
    + goto out;
    + }
    +
    + err = lower_dentry_inode->i_op->removexattr(lower_dentry, name);
    +out:
    + return err;
    +}
    +
    +/**
    + * Description: Called by the link(2) system call. Only required if you want
    + * to support hard links. You will probably need to call d_instantiate()
    + * just as you would in the create() method.
    + */
    +static int dazukofs_link(struct dentry *old_dentry, struct inode *dir,
    + struct dentry *new_dentry)
    +{
    + struct dentry *lower_old_dentry = get_lower_dentry(old_dentry);
    + struct dentry *lower_new_dentry = get_lower_dentry(new_dentry);
    + struct dentry *lower_dentry_parent = dget(lower_new_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_link(lower_old_dentry, lower_dentry_parent_inode,
    + lower_new_dentry);
    + if (err)
    + goto out;
    +
    + err = dazukofs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + fsstack_copy_inode_size(dir, lower_dentry_parent_inode);
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the unlink(2) system call. Only required if you
    + * want to support deleting inodes.
    + */
    +static int dazukofs_unlink(struct inode *dir, struct dentry *dentry)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_unlink(lower_dentry_parent_inode, lower_dentry);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + dentry->d_inode->i_nlink =
    + get_lower_inode(dentry->d_inode)->i_nlink;
    + fsstack_copy_attr_times(dentry->d_inode, dir);
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the rmdir(2) system call. Only required if you
    + * want to support deleting subdirectories.
    + */
    +static int dazukofs_rmdir(struct inode *dir, struct dentry *dentry)
    +{
    + struct dentry *lower_dentry = get_lower_dentry(dentry);
    + struct dentry *lower_dentry_parent = dget(lower_dentry->d_parent);
    + struct inode *lower_dentry_parent_inode = lower_dentry_parent->d_inode;
    + int err;
    +
    + mutex_lock_nested(&(lower_dentry_parent_inode->i_mutex),
    + I_MUTEX_PARENT);
    +
    + err = vfs_rmdir(lower_dentry_parent_inode, lower_dentry);
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_times(dir, lower_dentry_parent_inode);
    + dir->i_nlink = lower_dentry_parent_inode->i_nlink;
    +out:
    + mutex_unlock(&(lower_dentry_parent_inode->i_mutex));
    + dput(lower_dentry_parent);
    +
    + if (!err)
    + d_drop(dentry);
    + return err;
    +}
    +
    +/**
    + * Description: Called by the rename(2) system call to rename the object to
    + * have the parent and name given by the second inode and dentry.
    + */
    +static int dazukofs_rename(struct inode *old_dir, struct dentry *old_dentry,
    + struct inode *new_dir, struct dentry *new_dentry)
    +{
    + struct dentry *lower_old_dentry = get_lower_dentry(old_dentry);
    + struct dentry *lower_new_dentry = get_lower_dentry(new_dentry);
    + struct dentry *lower_old_dentry_parent =
    + dget(lower_old_dentry->d_parent);
    + struct dentry *lower_new_dentry_parent =
    + dget(lower_new_dentry->d_parent);
    + struct inode *lower_old_dentry_parent_inode =
    + lower_old_dentry_parent->d_inode;
    + struct inode *lower_new_dentry_parent_inode =
    + lower_new_dentry_parent->d_inode;
    + int err = -ENOENT;
    +
    + if (!lower_old_dentry_parent_inode) {
    + d_drop(old_dentry);
    + goto out;
    + }
    +
    + if (!lower_new_dentry_parent_inode) {
    + d_drop(new_dentry);
    + goto out;
    + }
    +
    + lock_rename(lower_old_dentry_parent, lower_new_dentry_parent);
    + err = vfs_rename(lower_old_dentry_parent_inode, lower_old_dentry,
    + lower_new_dentry_parent_inode, lower_new_dentry);
    + unlock_rename(lower_old_dentry_parent, lower_new_dentry_parent);
    +
    + if (err)
    + goto out;
    +
    + fsstack_copy_attr_all(new_dir, lower_new_dentry_parent_inode, NULL);
    + if (new_dir != old_dir)
    + fsstack_copy_attr_all(old_dir, lower_old_dentry_parent_inode,
    + NULL);
    +out:
    + dput(lower_old_dentry_parent);
    + dput(lower_new_dentry_parent);
    + return err;
    +}
    +
    +/**
    + * Unused operations:
    + * - create
    + * - lookup
    + * - link
    + * - unlink
    + * - symlink
    + * - mkdir
    + * - rmdir
    + * - mknod
    + * - rename
    + * - truncate
    + * - getattr
    + * - truncate_range
    + * - fallocate
    + */
    +static struct inode_operations dazukofs_symlink_iops = {
    + .readlink = dazukofs_readlink,
    + .follow_link = dazukofs_follow_link,
    + .put_link = dazukofs_put_link,
    + .permission = dazukofs_permission,
    + .setattr = dazukofs_setattr,
    + .setxattr = dazukofs_setxattr,
    + .getxattr = dazukofs_getxattr,
    + .listxattr = dazukofs_listxattr,
    + .removexattr = dazukofs_removexattr,
    +};
    +
    +/**
    + * Unused operations:
    + * - readlink
    + * - follow_link
    + * - put_link
    + * - truncate
    + * - getattr
    + * - truncate_range
    + * - fallocate
    + */
    +static struct inode_operations dazukofs_dir_iops = {
    + .create = dazukofs_create,
    + .lookup = dazukofs_lookup,
    + .link = dazukofs_link,
    + .unlink = dazukofs_unlink,
    + .symlink = dazukofs_symlink,
    + .mkdir = dazukofs_mkdir,
    + .rmdir = dazukofs_rmdir,
    + .mknod = dazukofs_mknod,
    + .rename = dazukofs_rename,
    + .permission = dazukofs_permission,
    + .setattr = dazukofs_setattr,
    + .setxattr = dazukofs_setxattr,
    + .getxattr = dazukofs_getxattr,
    + .listxattr = dazukofs_listxattr,
    + .removexattr = dazukofs_removexattr,
    +};
    +
    +/**
    + * Unused operations:
    + * - create
    + * - lookup
    + * - link
    + * - unlink
    + * - symlink
    + * - mkdir
    + * - rmdir
    + * - mknod
    + * - rename
    + * - readlink
    + * - follow_link
    + * - put_link
    + * - truncate
    + * - getattr
    + * - truncate_range
    + * - fallocate
    + */
    +static struct inode_operations dazukofs_main_iops = {
    + .permission = dazukofs_permission,
    + .setattr = dazukofs_setattr,
    + .setxattr = dazukofs_setxattr,
    + .getxattr = dazukofs_getxattr,
    + .listxattr = dazukofs_listxattr,
    + .removexattr = dazukofs_removexattr,
    +};
    Index: linux-2.6.28/fs/dazukofs/mmap.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/mmap.c 2009-02-03 18:07:44.000000000 +0100
    @@ -0,0 +1,116 @@
    +/* dazukofs: access control stackable filesystem
    +
    + Copyright (C) 1997-2003 Erez Zadok
    + Copyright (C) 2001-2003 Stony Brook University
    + Copyright (C) 2004-2007 International Business Machines Corp.
    + Copyright (C) 2008-2009 John Ogness
    + Author: John Ogness <dazukocode@ogness.net>
    +
    + This program is free software; you can redistribute it and/or
    + modify it under the terms of the GNU General Public License
    + as published by the Free Software Foundation; either version 2
    + of the License, or (at your option) any later version.
    +
    + This program is distributed in the hope that it will be useful,
    + but WITHOUT ANY WARRANTY; without even the implied warranty of
    + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + GNU General Public License for more details.
    +
    + You should have received a copy of the GNU General Public License
    + along with this program; if not, write to the Free Software
    + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    +*/
    +
    +#include <linux/module.h>
    +#include <linux/fs.h>
    +#include <linux/pagemap.h>
    +
    +#include "dazukofs_fs.h"
    +
    +/**
    + * Description: Called by the VM to read a page from backing store. The page
    + * will be Locked when readpage is called, and should be unlocked and marked
    + * uptodate once the read completes. If ->readpage discovers that it needs
    + * to unlock the page for some reason, it can do so, and then return
    + * AOP_TRUNCATED_PAGE. In this case, the page will be relocated, relocked
    + * and if that all succeeds, ->readpage will be called again.
    + */
    +static int dazukofs_readpage(struct file *file, struct page *page)
    +{
    + struct dentry *dentry = file->f_dentry;
    + struct file *lower_file = get_lower_file(file);
    + struct inode *inode = dentry->d_inode;
    + struct inode *lower_inode = get_lower_inode(inode);
    + const struct address_space_operations *lower_a_ops =
    + lower_inode->i_mapping->a_ops;
    + char *page_data;
    + struct page *lower_page;
    + char *lower_page_data;
    + int err = 0;
    +
    + lower_page = read_cache_page(lower_inode->i_mapping, page->index,
    + (filler_t *)lower_a_ops->readpage,
    + (void *)lower_file);
    +
    + if (IS_ERR(lower_page)) {
    + err = PTR_ERR(lower_page);
    + lower_page = NULL;
    + printk(KERN_ERR "dazukofs: Error reading from page cache.\n");
    + goto out;
    + }
    +
    + wait_on_page_locked(lower_page);
    +
    + page_data = (char *)kmap(page);
    + if (!page_data) {
    + err = -ENOMEM;
    + printk(KERN_ERR "dazukofs: Error mapping page.\n");
    + goto out;
    + }
    +
    + lower_page_data = (char *)kmap(lower_page);
    + if (!lower_page_data) {
    + err = -ENOMEM;
    + printk(KERN_ERR "dazukofs: Error mapping lower page.\n");
    + goto out;
    + }
    +
    + memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
    +
    + kunmap(lower_page);
    + kunmap(page);
    +out:
    + if (lower_page)
    + page_cache_release(lower_page);
    +
    + if (err)
    + ClearPageUptodate(page);
    + else
    + SetPageUptodate(page);
    +
    + unlock_page(page);
    + return err;
    +}
    +
    +/**
    + * Unused operations:
    + * - writepage
    + * - sync_page
    + * - writepages
    + * - set_page_dirty
    + * - readpages
    + * - prepare_write
    + * - commit_write
    + * - write_begin
    + * - write_end
    + * - bmap
    + * - invalidatepage
    + * - releasepage
    + * - direct_IO
    + * - get_xip_page
    + * - migratepage
    + * - launder_page
    + */
    +const struct address_space_operations dazukofs_aops = {
    + .readpage = dazukofs_readpage,
    +};
    Index: linux-2.6.28/fs/dazukofs/Makefile
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/Makefile 2009-02-03 18:07:44.000000000 +0100
    @@ -0,0 +1,7 @@
    +#
    +# Makefile for the Linux dazukofs-filesystem routines.
    +#
    +
    +obj-$(CONFIG_DAZUKOFS_FS) += dazukofs.o
    +
    +dazukofs-objs := super.o inode.o file.o dentry.o mmap.o
    Index: linux-2.6.28/fs/Makefile
    ===================================================================
    --- linux-2.6.28.orig/fs/Makefile 2009-02-02 22:05:54.000000000 +0100
    +++ linux-2.6.28/fs/Makefile 2009-02-02 22:05:56.000000000 +0100
    @@ -85,6 +85,7 @@
    obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
    obj-$(CONFIG_HFS_FS) += hfs/
    obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
    +obj-$(CONFIG_DAZUKOFS_FS) += dazukofs/
    obj-$(CONFIG_VXFS_FS) += freevxfs/
    obj-$(CONFIG_NFS_FS) += nfs/
    obj-$(CONFIG_EXPORTFS) += exportfs/
    Index: linux-2.6.28/Documentation/filesystems/dazukofs.txt
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/Documentation/filesystems/dazukofs.txt 2009-02-03 18:07:44.000000000 +0100
    @@ -0,0 +1,81 @@
    +================
    + ABOUT DAZUKOFS
    +================
    +
    +DazukoFS is a pass-through stackable filesystem. A filesystem that does
    +not perform any special modification but simply passes VFS calls to and
    +from the lower filesystem is typically known as nullfs.
    +
    +
    +
    +=====================
    + MOUNTING/UNMOUNTING
    +=====================
    +
    +DazukoFS is typically mounted on top of an existing directory. For example,
    +to stack DazukoFS on top of the /opt directory, the following mount(8)
    +command can be given:
    +
    +# mount -t dazukofs /opt /opt
    +
    +A process that accesses files in /opt will now be accessing them through
    +DazukoFS. The stackable filesystem can then be unmounted with:
    +
    +# umount /opt
    +
    +
    +
    +===============
    + MOUNT ON BOOT
    +===============
    +
    +You may want DazukoFS to be mounted over certain directories when the
    +machine boots. The easiest way to do this is to add the mounts to
    +the end of /etc/fstab. They would look something like this:
    +
    +/usr /usr dazukofs defaults 0 0
    +/opt /opt dazukofs defaults 0 0
    +
    +
    +
    +=========
    + WARNING
    +=========
    +
    +It is possible to mount DazukoFS to a directory other than the directory
    +that is being stacked upon. For example:
    +
    +# mount -t dazukofs /opt /mnt
    +
    +When accessing files within /mnt, you will be accessing files in /opt
    +(through DazukoFS). When accessing files directly in /opt, DazukoFS will not
    +be involved.
    +
    +THIS HAS POTENTIAL PROBLEMS!
    +
    +If files are modified directly in /opt, the DazukoFS layer will not know
    +about it. When DazukoFS later tries to access those files, it may result
    +in corrupt data or kernel crashes. As long as /opt is modified ONLY through
    +DazukoFS, there should not be any problems.
    +
    +This method of mounting DazukoFS may be interesting for servers that export
    +a part of the filesystem and the service is in a chroot environment.
    +
    +
    +
    +==============
    + KNOWN ISSUES
    +==============
    +
    +- DazukoFS does not support writing to memory mapped files. This should not
    + cause the kernel to crash, but will instead result in the application
    + failing to perform the writes (although mmap() will appear to be
    + successful from the application's viewpoint!).
    +
    +- It is not possible to stack DazukoFS over the root filesystem (/).
    + Stacking over pseudo filesystems (/proc, /dev, /sys) has not been
    + tested and should be avoided.
    +
    +Please report problems to the dazuko-devel mailing list
    +(subscription required):
    + http://lists.nongnu.org/mailman/listinfo/dazuko-devel
    Index: linux-2.6.28/fs/dazukofs/Kconfig
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6.28/fs/dazukofs/Kconfig 2009-02-03 18:07:44.000000000 +0100
    @@ -0,0 +1,10 @@
    +config DAZUKOFS_FS
    + tristate "DazukoFS filesystem layer support (EXPERIMENTAL)"
    + depends on EXPERIMENTAL
    + help
    + A pass-through stackable filesystem (also referred to as nullfs).
    + See <file:Documentation/filesystems/dazukofs.txt> to learn more
    + about DazukoFS.
    +
    + To compile this file system support as a module, choose M here: the
    + module will be called dazukofs.
    Index: linux-2.6.28/fs/Kconfig
    ===================================================================
    --- linux-2.6.28.orig/fs/Kconfig 2009-02-02 22:05:54.000000000 +0100
    +++ linux-2.6.28/fs/Kconfig 2009-02-02 22:05:56.000000000 +0100
    @@ -204,6 +204,7 @@
    source "fs/adfs/Kconfig"
    source "fs/affs/Kconfig"
    source "fs/ecryptfs/Kconfig"
    +source "fs/dazukofs/Kconfig"
    source "fs/hfs/Kconfig"
    source "fs/hfsplus/Kconfig"
    source "fs/befs/Kconfig"

    \
     
     \ /
      Last update: 2009-02-03 20:21    [W:0.153 / U:33.536 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site