lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <861vufgwlt.fsf@johno.fn.ogness.net>
Date:	Tue, 03 Feb 2009 20:15:58 +0100
From:	John Ogness <dazukocode@...ess.net>
To:	linux-kernel@...r.kernel.org
Cc:	viro@...iv.linux.org.uk, malware-list@...ts.printk.net,
	eparis@...hat.com, hch@...radead.org, alan@...rguk.ukuu.org.uk
Subject: [PATCHv2 1/5] VFS: DazukoFS, stackable-fs, file access control

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@...ess.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@...ess.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@...ess.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@...ess.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@...ess.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@...ess.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@...ess.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"
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ