this diff changes unionfs to not pass down the address operations to the
lower file, but to do them itself.

benefits:
enables kernel/proc to know that it's mapping the union file, not the
lower file (so won't see branch in /proc or d_path().

negatives:
it's slower, as it has to read the data from the lower page, copy it to
the upper page, as well as this causes the data to be held in kernel
memory twice (leading to more memory pressure).

the patch is against unionfs-1.1.3.  I haven't done major testing
against it yet, but expect to do more testing against it in the next few
weeks.

>From what I recall, a possible problem I encounted a while ago was that
if the fs was unmounted before its contents were fully synced, then they
would be lost (so therefore have to sync before unmounting).
diff -rNu unionfs-1.1.3/Makefile unionfs-1.1.3-mmap/Makefile
--- unionfs-1.1.3/Makefile	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/Makefile	2006-03-02 03:28:56.000000000 +0000
@@ -36,7 +36,7 @@
 unionfs-objs := subr.o dentry.o file.o inode.o main.o super.o \
 	stale_inode.o branchman.o xattr.o rdstate.o copyup.o  \
 	dirhelper.o rename.o unlink.o lookup.o persistent_inode.o \
-	commonfops.o dirfops.o print.o malloc_debug.o
+	commonfops.o dirfops.o print.o malloc_debug.o mmap.o
 
 BINS	:=	unionctl uniondbg unionimap
 
diff -rNu unionfs-1.1.3/copyup.c unionfs-1.1.3-mmap/copyup.c
--- unionfs-1.1.3/copyup.c	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/copyup.c	2006-03-02 03:28:56.000000000 +0000
@@ -373,6 +373,10 @@
 		set_fs(old_fs);
 		KFREE(buf);
 
+		if (!err) {
+			err = output_file->f_op->fsync(output_file, new_hidden_dentry, 0);
+		}
+
 		if (err) {
 			/* copyup failed, because we ran out of space or quota,
 			 * or something else happened so let's unlink; we don't
diff -rNu unionfs-1.1.3/file.c unionfs-1.1.3-mmap/file.c
--- unionfs-1.1.3/file.c	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/file.c	2006-03-02 15:07:22.000000000 +0000
@@ -30,6 +30,7 @@
  * File Operations *
  *******************/
 
+#if 0
 static loff_t unionfs_llseek(struct file *file, loff_t offset, int origin)
 {
 	loff_t err;
@@ -68,42 +69,29 @@
 	print_exit_status((int)err);
 	return err;
 }
+#endif
 
-ssize_t unionfs_read(struct file * file, char __user * buf, size_t count,
-		     loff_t * ppos)
+ssize_t unionfs_read(struct file * file, char __user * buf, size_t count, loff_t * ppos)
 {
 	int err = -EINVAL;
-	struct file *hidden_file = NULL;
-	loff_t pos = *ppos;
 
 	print_entry_location();
 
 	if ((err = unionfs_file_revalidate(file, 0)))
 		goto out;
+		
+	err = generic_file_read(file, buf, count, ppos);
 
-	fist_print_file("entering read()", file);
-
-	hidden_file = ftohf(file);
-
-	if (!hidden_file->f_op || !hidden_file->f_op->read)
-		goto out;
-
-	err = hidden_file->f_op->read(hidden_file, buf, count, &pos);
-	*ppos = pos;
-	if (err >= 0) {
-		/* atime should also be updated for reads of size zero or more */
-		fist_copy_attr_atime(file->f_dentry->d_inode,
-				     hidden_file->f_dentry->d_inode);
-	}
-	memcpy(&(file->f_ra), &(hidden_file->f_ra),
-	       sizeof(struct file_ra_state));
+	if (err >= 0)
+		update_atime(itohi(file->f_dentry->d_inode)); 
 
-      out:
-	fist_print_file("leaving read()", file);
+	out:
+	
 	print_exit_status(err);
 	return err;
 }
 
+#if 0
 #ifdef SUPPORT_BROKEN_LOSETUP
 static ssize_t unionfs_sendfile(struct file *file, loff_t * ppos,
 				size_t count, read_actor_t actor, void *target)
@@ -130,56 +118,20 @@
 	return err;
 }
 #endif
+#endif
 
-/* this unionfs_write() does not modify data pages! */
-ssize_t unionfs_write(struct file * file, const char __user * buf, size_t count,
-		      loff_t * ppos)
+ssize_t unionfs_write(struct file * file, const char __user * buf, size_t count,loff_t * ppos)
 {
-	int err = -EINVAL;
-	struct file *hidden_file = NULL;
-	struct inode *inode;
-	struct inode *hidden_inode;
-	loff_t pos = *ppos;
-	int bstart, bend;
+	int err = 0;
 
 	print_entry_location();
 
 	if ((err = unionfs_file_revalidate(file, 1)))
 		goto out;
+	
+	err = generic_file_write(file, buf, count, ppos);
 
-	inode = file->f_dentry->d_inode;
-
-	bstart = fbstart(file);
-	bend = fbend(file);
-
-	BUG_ON(bstart == -1);
-
-	hidden_file = ftohf(file);
-	hidden_inode = hidden_file->f_dentry->d_inode;
-
-	if (!hidden_file->f_op || !hidden_file->f_op->write)
-		goto out;
-
-	/* adjust for append -- seek to the end of the file */
-	if (file->f_flags & O_APPEND)
-		pos = inode->i_size;
-
-	err = hidden_file->f_op->write(hidden_file, buf, count, &pos);
-
-	/*
-	 * copy ctime and mtime from lower layer attributes
-	 * atime is unchanged for both layers
-	 */
-	if (err >= 0)
-		fist_copy_attr_times(inode, hidden_inode);
-
-	*ppos = pos;
-
-	/* update this inode's size */
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-
-      out:
+out:
 	print_exit_status(err);
 	return err;
 }
@@ -193,6 +145,7 @@
 	return err;
 }
 
+#if 0
 static unsigned int unionfs_poll(struct file *file, poll_table * wait)
 {
 	unsigned int mask = DEFAULT_POLLMASK;
@@ -217,37 +170,31 @@
 	print_exit_status(mask);
 	return mask;
 }
+#endif
 
-/* FIST-LITE special version of mmap */
 static int unionfs_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	int err = 0;
-	struct file *hidden_file = NULL;
-	int willwrite;
-
-	print_entry_location();
-
-	/* This might could be deferred to mmap's writepage. */
-	willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
-	if ((err = unionfs_file_revalidate(file, willwrite)))
-		goto out;
+        int err = 0;
+        int willwrite;
 
-	hidden_file = ftohf(file);
-
-	err = -ENODEV;
-	if (!hidden_file->f_op || !hidden_file->f_op->mmap)
-		goto out;
+        print_entry_location();
 
-	vma->vm_file = hidden_file;
-	err = hidden_file->f_op->mmap(hidden_file, vma);
-	get_file(hidden_file);	/* make sure it doesn't get freed on us */
-	fput(file);		/* no need to keep extra ref on ours */
+        /* This might could be deferred to mmap's writepage. */
+        willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
+        if ((err = unionfs_file_revalidate(file, willwrite)))
+                goto out;
+
+        err = generic_file_mmap(file, vma);
+        if (err) {
+                printk("unionfs_mmap: generic_file_mmap failed\n");
+        }
 
       out:
-	print_exit_status(err);
-	return err;
+        print_exit_status(err);
+        return err;
 }
 
+#if 0
 static int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
 	int err;
@@ -293,22 +240,29 @@
 	print_exit_status(err);
 	return err;
 }
+#endif
 
 struct file_operations unionfs_main_fops = {
-	.llseek = unionfs_llseek,
+	.llseek = generic_file_llseek,
 	.read = unionfs_read,
 	.write = unionfs_write,
 	.readdir = unionfs_file_readdir,
+#if 0
 	.poll = unionfs_poll,
+#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
 	.unlocked_ioctl = unionfs_ioctl,
+#else
+	.ioctl = unionfs_ioctl,
 #endif
 	.mmap = unionfs_mmap,
 	.open = unionfs_open,
 	.flush = unionfs_flush,
 	.release = unionfs_file_release,
-	.fsync = unionfs_fsync,
+	.fsync = file_fsync,
+#if 0
 	.fasync = unionfs_fasync,
+#endif
 #ifdef SUPPORT_BROKEN_LOSETUP
 	.sendfile = unionfs_sendfile,
 #endif
diff -rNu unionfs-1.1.3/fist.h unionfs-1.1.3-mmap/fist.h
--- unionfs-1.1.3/fist.h	1970-01-01 00:00:00.000000000 +0000
+++ unionfs-1.1.3-mmap/fist.h	2006-03-02 03:28:56.000000000 +0000
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2003-2005 Erez Zadok
+ * Copyright (c) 2003-2005 Charles P. Wright
+ * Copyright (c) 2005      Arun M. Krishnakumar
+ * Copyright (c) 2005      David P. Quigley
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003-2003 Puja Gupta
+ * Copyright (c) 2003-2003 Harikesavan Krishnan
+ * Copyright (c) 2003-2005 Stony Brook University
+ * Copyright (c) 2003-2005 The Research Foundation of State University of New York
+ *
+ * For specific licensing information, see the COPYING file distributed with
+ * this package.
+ *
+ * This Copyright notice must be kept intact and distributed with all sources.
+ */
+/*
+ *  $Id: fist.h,v 1.61 2005/09/18 05:02:56 jsipek Exp $
+ */
+
+#ifndef __FIST_H_
+#define __FIST_H_
+
+/*
+ * KERNEL ONLY CODE:
+ */
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/limits.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/buffer_head.h>
+#include <linux/pagemap.h>
+#include <linux/namei.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/page-flags.h>
+#include <linux/writeback.h>
+#include <linux/page-flags.h>
+#include <linux/statfs.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#if defined(UNIONFS_XATTR)
+#include <linux/xattr.h>
+#endif
+#include <linux/security.h>
+#include <linux/compat.h>
+
+#include <linux/swap.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/mman.h>
+#include <linux/seq_file.h>
+#include <linux/dcache.h>
+#include <linux/poll.h>
+
+/*
+ * MACROS:
+ */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif				/* not SEEK_SET */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif				/* not SEEK_CUR */
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif				/* not SEEK_END */
+
+#ifndef DEFAULT_POLLMASK
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+#endif
+
+/*
+ * EXTERNALS:
+ */
+
+#ifdef FIST_MALLOC_DEBUG
+extern void *unionfs_kmalloc(size_t len, int flag, int line, const char *file);
+extern void unionfs_kfree(void *ptr, int line, const char *file);
+
+extern struct dentry *unionfs_dget_parent(struct dentry *child, int line,
+					  const char *file);
+extern struct dentry *unionfs_dget(struct dentry *ptr, int line,
+				   const char *file);
+extern void unionfs_dput(struct dentry *ptr, int line, const char *file);
+extern struct dentry *unionfs_lookup_one_len(const char *name,
+					     struct dentry *parent, int len,
+					     int line, const char *file);
+void record_path_lookup(struct nameidata *nd, int line, const char *file);
+void record_path_release(struct nameidata *nd, int line, const char *file);
+struct file *unionfs_dentry_open(struct dentry *ptr, struct vfsmount *mnt,
+				 int flags, int line, const char *file);
+void record_set(struct dentry *upper, int index, struct dentry *ptr,
+		struct dentry *old, int line, const char *file);
+
+#define KMALLOC(size,flag) unionfs_kmalloc((size),(flag),__LINE__,__FILE__)
+#define KFREE(ptr) unionfs_kfree((ptr),__LINE__,__FILE__)
+#define DGET(d) unionfs_dget((d),__LINE__,__FILE__)
+#define DPUT(d) unionfs_dput((d),__LINE__,__FILE__)
+#define LOOKUP_ONE_LEN(name,parent,len) unionfs_lookup_one_len((name),(parent),(len),__LINE__,__FILE__)
+# define RECORD_PATH_LOOKUP(nd)	record_path_lookup((nd),__LINE__,__FILE__)
+# define RECORD_PATH_RELEASE(nd) record_path_release((nd),__LINE__,__FILE__)
+/* This has the effect of reducing the reference count sooner or later,
+ * if the file is closed.  If it isn't then the mount will be busy and
+ * you can't unmount.
+ */
+# define DENTRY_OPEN(d,m,f) unionfs_dentry_open((d),(m),(f),__LINE__,__FILE__)
+# define GET_PARENT(dentry) unionfs_dget_parent((dentry),__LINE__,__FILE__)
+#else				/* not FIST_MALLOC_DEBUG */
+# define KMALLOC(a,b)		kmalloc((a),(b))
+# define KFREE(a)		kfree((a))
+# define DPUT(a)		dput((a))
+# define DGET(a)		dget((a))
+# define LOOKUP_ONE_LEN(a,b,c)	lookup_one_len((a),(b),(c))
+# define RECORD_PATH_LOOKUP(a)
+# define RECORD_PATH_RELEASE(a)
+# define DENTRY_OPEN(d,m,f)	dentry_open((d),(m),(f))
+# define GET_PARENT(d)		dget_parent(d)
+#endif				/* not FIST_MALLOC_DEBUG */
+
+/* This needs to go so low so that we can bring in DGET/DPUT. */
+
+#ifdef UNIONFS_NDEBUG
+/* All of these should be noops. */
+static inline int fist_get_debug_value(void)
+{
+	return 0;
+}
+static inline int fist_set_debug_value(int val)
+{
+	return -ENOTSUPP;
+}
+
+#define fist_print_dentry(msg, o)
+#define __fist_print_dentry(msg, o, i)
+#define fist_print_generic_dentry(msg, o)
+#define fist_print_generic_dentry3(msg, o)
+#define __fist_print_generic_dentry(msg, o, i)
+#define fist_print_inode(msg, o)
+#define fist_print_generic_inode(msg, o)
+#define fist_print_file(msg, o)
+#define fist_checkinode(o, msg)
+#define fist_print_sb(msg, o)
+#else
+extern int fist_get_debug_value(void);
+extern int fist_set_debug_value(int val);
+extern void fist_dprint_internal(const char *file, const char *function,
+				 int line, int level, char *str, ...)
+    __attribute__ ((format(__printf__, 5, 6)));
+
+extern void fist_print_dentry(const char *, const struct dentry *);
+extern void __fist_print_dentry(const char *, const struct dentry *, int);
+extern void fist_print_generic_dentry(const char *, const struct dentry *);
+extern void fist_print_generic_dentry3(const char *, const char *,
+				       const struct dentry *);
+extern void __fist_print_generic_dentry(const char *, const char *, const
+					struct dentry *, int);
+extern void fist_print_inode(const char *, const struct inode *);
+extern void fist_print_generic_inode(const char *, const struct inode *);
+extern void fist_print_file(const char *, const struct file *);
+extern void fist_checkinode(const struct inode *, const char *);
+extern void fist_print_sb(const char *str, const struct super_block *);
+
+extern char *add_indent(void);
+extern char *del_indent(void);
+#endif
+
+/* The poison pointer.  This needs to be changed on an ia64. */
+#define POISON    ((void *)0x5a5a5a5a)
+
+#define WHEREAMI() \
+do { \
+	printk("HERE: %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); \
+} while (0)
+
+#ifndef UNIONFS_NDEBUG
+
+/* Call if you encounter a bug. */
+#define FISTBUG(msg) \
+do { \
+	printk("<0>FISTBUG at %s:%s:%d %s", __FILE__, __FUNCTION__, __LINE__, msg); \
+	(*((char *)0))=0;	\
+} while (0);
+
+/* The if (0 ...) is so that we can make sure that you don't pass this
+ * define a non-pointer.  gcc should optimize it away. */
+#define PASSERT(EX)	\
+do {	\
+    void *p = (void *)(EX);\
+    if (0 && ((EX) == (void *)4)) { /* do nothing */ }; \
+    if (!(p) || (p == POISON)) {	\
+	printk(KERN_CRIT "ASSERTION FAILED: %s %s at %s:%d (%s)\n", #EX,	\
+	        (p == POISON) ? "(poisoned)" : "(null)", \
+                __FILE__, __LINE__, __FUNCTION__);	\
+	(*((char *)0))=0;	\
+    }	\
+} while (0)
+
+/* The if (0 ...) is so that we can make sure that you don't pass this
+ * define a non-pointer.  gcc should optimize it away. */
+/* same PASSERT, but tell me who was the caller of the function */
+#define PASSERT2(EX)	\
+do {	\
+    void *p = (void *)(EX);\
+    if (0 && ((EX) ==  (void *)4)) { /* do nothing */ }; \
+    if (!(p) || (p == POISON)) {	\
+	printk(KERN_CRIT "ASSERTION FAILED %s %s at %s:%d (%s) called by %s:%d (%s)\n", #EX, (p == POISON) ? "(poisoned)" : "(null)",	\
+	       __FILE__, __LINE__, __FUNCTION__, file, line, function);\
+	(*((char *)0))=0;	\
+    }	\
+} while (0)
+
+/* The if (0 ...) is so that we can make sure that you don't pass this
+ * define a pointer.  gcc should optimize it away. */
+#define ASSERT(EX)	\
+do {	\
+    if (0 && ((EX) == 1)) { /* do nothing */ }; \
+    if ((EX) == 0) {	\
+	printk(KERN_CRIT "ASSERTION FAILED: %s at %s:%d (%s)\n", #EX,	\
+	       __FILE__, __LINE__, __FUNCTION__);	\
+	(*((char *)0))=0;	\
+    }	\
+} while (0)
+
+/* same ASSERT, but tell me who was the caller of the function */
+#define ASSERT2(EX)	\
+do {	\
+    if (0 && ((EX) == 1)) { /* do nothing */ }; \
+    if ((EX) == 0) {	\
+	printk(KERN_CRIT "ASSERTION FAILED %s at %s:%d (%s) called by %s:%d (%s)\n", #EX,	\
+	       __FILE__, __LINE__, __FUNCTION__, file, line, function);\
+	(*((char *)0))=0;	\
+    }	\
+} while (0)
+
+#define fist_dprint(level, str, args...) fist_dprint_internal(__FILE__, __FUNCTION__, __LINE__, level, KERN_DEBUG str, ## args)
+#define print_entry(format, args...) fist_dprint(4, "%sIN:  %s %s:%d " format "\n", add_indent(), __FUNCTION__, __FILE__, __LINE__, ##args)
+#define print_entry_location() fist_dprint(4, "%sIN:  %s %s:%d\n", add_indent(), __FUNCTION__, __FILE__, __LINE__)
+#define print_exit_location() fist_dprint(5, "%s OUT: %s %s:%d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__)
+#define print_exit_status(status) fist_dprint(5, "%s OUT: %s %s:%d, STATUS: %d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status)
+#define print_exit_pointer(status) \
+do { \
+  if (IS_ERR(status)) \
+    fist_dprint(5, "%s OUT: %s %s:%d, RESULT: %ld\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \
+  else \
+    fist_dprint(5, "%s OUT: %s %s:%d, RESULT: 0x%p\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status); \
+} while (0)
+
+#define print_util_entry(format, args...) fist_dprint(6, "%sIN:  %s %s:%d" format "\n", add_indent(), __FUNCTION__, __FILE__, __LINE__, ##args)
+#define print_util_entry_location() fist_dprint(6, "%sIN:  %s %s:%d\n", add_indent(), __FUNCTION__, __FILE__, __LINE__)
+#define print_util_exit_location() fist_dprint(7, "%s OUT: %s %s:%d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__)
+#define print_util_exit_status(status) fist_dprint(7, "%s OUT: %s %s:%d, STATUS: %d\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, status)
+#define print_util_exit_pointer(status) \
+do { \
+  if (IS_ERR(status)) \
+    fist_dprint(7, "%s OUT: %s %s:%d, RESULT: %ld\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \
+  else \
+    fist_dprint(5, "%s OUT: %s %s:%d, RESULT: 0x%x\n", del_indent(), __FUNCTION__, __FILE__, __LINE__, PTR_ERR(status)); \
+} while (0)
+
+#else
+#define ASSERT(ex)
+#define ASSERT2(ex)
+#define PASSERT(ex)
+#define PASSERT2(ex)
+#define FISTBUG(args...)
+#define fist_dprint(args...)
+#define print_entry(args...)
+#define print_entry_location()
+#define print_exit_location()
+#define print_exit_status(status)
+#define print_exit_pointer(status)
+#define print_util_entry(args...)
+#define print_util_entry_location()
+#define print_util_exit_location()
+#define print_util_exit_status(status)
+#define print_util_exit_pointer(status)
+#endif
+
+#endif				/* __KERNEL__ */
+
+/*
+ * DEFINITIONS FOR USER AND KERNEL CODE:
+ * (Note: ioctl numbers 1--9 are reserved for fistgen, the rest
+ *  are auto-generated automatically based on the user's .fist file.)
+ */
+# define FIST_IOCTL_GET_DEBUG_VALUE	_IOR(0x15, 1, int)
+# define FIST_IOCTL_SET_DEBUG_VALUE	_IOW(0x15, 2, int)
+# define UNIONFS_IOCTL_BRANCH_COUNT	_IOR(0x15, 10, int)
+# define UNIONFS_IOCTL_INCGEN		_IOR(0x15, 11, int)
+# define UNIONFS_IOCTL_ADDBRANCH	_IOW(0x15, 12, int)
+# define UNIONFS_IOCTL_DELBRANCH	_IOW(0x15, 13, int)
+# define UNIONFS_IOCTL_RDWRBRANCH	_IOW(0x15, 14, int)
+# define UNIONFS_IOCTL_QUERYFILE	_IOR(0x15, 15, int)
+
+/* We don't support normal remount, but unionctl uses it. */
+# define UNIONFS_REMOUNT_MAGIC		0x4a5a4380
+
+struct unionfs_addbranch_args {
+	unsigned int ab_branch;
+	char *ab_path;
+	unsigned int ab_perms;
+};
+
+struct unionfs_rdwrbranch_args {
+	unsigned int rwb_branch;
+	unsigned int rwb_perms;
+};
+
+#endif				/* not __FIST_H_ */
+/*
+ *
+ * vim:shiftwidth=8
+ * vim:tabstop=8
+ *
+ * For Emacs:
+ * Local variables:
+ * c-basic-offset: 8
+ * c-comment-only-line-offset: 0
+ * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0)
+ *              (substatement-open . 0) (label . 0) (statement-cont . +))
+ * indent-tabs-mode: t
+ * tab-width: 8
+ * End:
+ */
diff -rNu unionfs-1.1.3/inode.c unionfs-1.1.3-mmap/inode.c
--- unionfs-1.1.3/inode.c	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/inode.c	2006-03-02 03:28:56.000000000 +0000
@@ -973,12 +973,25 @@
 			}
 
 		}
+				
 		err = notify_change(hidden_dentry, ia);
 		if (err)
 			goto out;
 		break;
 	}
 
+	//do size change to upper inode (as mmap code)
+	//other meta data is handled by fist_copy_attr_all
+
+	if (ia->ia_valid & ATTR_SIZE) {
+		if (ia->ia_size != i_size_read(inode)) {
+			err = vmtruncate(inode, ia->ia_size);
+			if (err) {
+				printk("unionfs_setattr: vmtruncate failed\n");
+			}
+		}
+	}
+
 	/* get the size from the first hidden inode */
 	hidden_inode = itohi(dentry->d_inode);
 	fist_checkinode(inode, "unionfs_setattr");
diff -rNu unionfs-1.1.3/main.c unionfs-1.1.3-mmap/main.c
--- unionfs-1.1.3/main.c	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/main.c	2006-03-02 14:57:30.000000000 +0000
@@ -141,14 +141,6 @@
 		init_special_inode(inode, hidden_inode->i_mode,
 				   hidden_inode->i_rdev);
 
-	/* Fix our inode's address operations to that of the lower inode (Unionfs is FiST-Lite) */
-	if (inode->i_mapping->a_ops != hidden_inode->i_mapping->a_ops) {
-		fist_dprint(7, "fixing inode 0x%p a_ops (0x%p -> 0x%p)\n",
-			    inode, inode->i_mapping->a_ops,
-			    hidden_inode->i_mapping->a_ops);
-		inode->i_mapping->a_ops = hidden_inode->i_mapping->a_ops;
-	}
-
 	/* all well, copy inode attributes */
 	fist_copy_attr_all(inode, hidden_inode);
 
@@ -747,7 +739,7 @@
 static int __init init_unionfs_fs(void)
 {
 	int err;
-	printk("Registering unionfs " UNIONFS_VERSION "\n");
+	printk("Registering unionfs " UNIONFS_VERSION " (shaya)\n");
 
 	fist_set_debug_value(init_debug);
 
diff -rNu unionfs-1.1.3/mmap.c unionfs-1.1.3-mmap/mmap.c
--- unionfs-1.1.3/mmap.c	1970-01-01 00:00:00.000000000 +0000
+++ unionfs-1.1.3-mmap/mmap.c	2006-03-02 15:07:03.000000000 +0000
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 1997-2005 Erez Zadok <[EMAIL PROTECTED]>
+ * Copyright (c) 2001-2005 Stony Brook University
+ *
+ * For specific licensing information, see the COPYING file distributed with
+ * this package, or get one from ftp://ftp.filesystems.org/pub/fistgen/COPYING.
+ *
+ * This Copyright notice must be kept intact and distributed with all
+ * fistgen sources INCLUDING sources generated by fistgen.
+ */
+/*
+ *  $Id: mmap.c,v 1.18 2005/02/04 15:40:10 cwright Exp $
+ */
+
+#include "unionfs.h"
+
+void unionfs_copy_block(const char * from, char * to, unsigned len)
+{
+	        memcpy(to, from, len);
+}
+
+int unionfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	int err = -EIO;
+	struct inode * inode;
+	struct inode * lower_inode;
+	struct page * lower_page;
+	char * kaddr, * lower_kaddr;
+
+	print_entry_location();
+
+	inode = page->mapping->host;
+	lower_inode = itohi(inode);
+
+	/* find lower page (returns a locked page) */
+	lower_page = grab_cache_page(lower_inode->i_mapping, page->index);
+	if (!lower_page)
+		goto out;
+
+	/* get page address, and encode it */
+	kaddr = (char *) kmap(page);
+	lower_kaddr = (char*) kmap(lower_page);
+	
+	unionfs_copy_block(kaddr, lower_kaddr, PAGE_CACHE_SIZE);
+	
+	kunmap(page);
+	kunmap(lower_page);
+
+	/* call lower writepage (expects locked page) */
+	err = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
+
+	/*
+	 * update mtime and ctime of lower level file system
+	 * unionfs' mtime and ctime are updated by generic_file_write
+	 */
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+
+	page_cache_release(lower_page);	/* b/c grab_cache_page increased refcnt */
+
+	if (err)
+		ClearPageUptodate(page);
+	else
+		SetPageUptodate(page);
+out:
+	unlock_page(page);
+	print_exit_status(err);
+	return err;
+}
+
+/*
+ * readpage is called from generic_page_read and the fault handler.
+ * If your file system uses generic_page_read for the read op, it
+ * must implement readpage.
+ *
+ * Readpage expects a locked page, and must unlock it.
+ */
+int unionfs_do_readpage(struct file * file, struct page * page)
+{
+	int err = -EIO;
+	struct dentry * dentry;
+	struct file * lower_file = NULL;
+	struct inode * inode, * lower_inode;
+	char *page_data;
+	struct page * lower_page;
+	char * lower_page_data;
+
+	print_entry_location();
+
+	dentry = file->f_dentry; /* CPW: Moved below print_entry_location */
+	if (ftopd(file) == NULL) {
+		err = -ENOENT;
+		goto out_err;
+	}
+	lower_file = ftohf(file);
+	BUG_ON(lower_file == NULL);	/* XXX: is this assertion right here? */
+	inode = dentry->d_inode;
+	lower_inode = itohi(inode);
+
+        lower_page = NULL;
+
+	/* find lower page (returns a locked page) */
+	lower_page = read_cache_page(lower_inode->i_mapping,
+				     page->index,
+                                     (filler_t *) lower_inode->i_mapping->a_ops->readpage,
+                                     (void *) lower_file);
+	
+	if (IS_ERR(lower_page)) {
+		err = PTR_ERR(lower_page);
+		lower_page = NULL;
+		goto out_release;
+	}
+
+	/*
+	 * wait for the page data to show up
+	 * (signaled by readpage as unlocking the page)
+	 */
+	wait_on_page_locked(lower_page);
+	if (!PageUptodate(lower_page)) {
+		/*
+		 * call readpage() again if we returned from wait_on_page with a
+		 * page that's not up-to-date; that can happen when a partial
+		 * page has a few buffers which are ok, but not the whole
+		 * page.
+		 */
+		lock_page(lower_page);
+		err = lower_inode->i_mapping->a_ops->readpage(lower_file,
+							      lower_page);
+		if (err) {
+			lower_page = NULL;
+			goto out_release;
+		}
+		wait_on_page_locked(lower_page);
+		if (!PageUptodate(lower_page)) {
+			err = -EIO;
+			goto out_release;
+		}
+	}
+
+	/* map pages, get their addresses */
+	page_data = (char *) kmap(page);
+        lower_page_data = (char *) kmap(lower_page);
+
+	unionfs_copy_block(lower_page_data, page_data, PAGE_CACHE_SIZE);
+
+	err = 0;
+	
+        kunmap(lower_page);
+	kunmap(page);
+
+out_release:
+	if (lower_page)
+		page_cache_release(lower_page);	/* undo read_cache_page */
+
+	if (err == 0)
+		SetPageUptodate(page);
+	else
+		ClearPageUptodate(page);
+
+out_err:
+	print_exit_status(err);
+	return err;
+}
+int unionfs_readpage(struct file * file, struct page * page)
+{
+	int err;
+	print_entry_location();
+
+	err = unionfs_do_readpage(file, page);
+
+	/*
+	 * we have to unlock our page, b/c we _might_ have gotten a locked page.
+	 * but we no longer have to wakeup on our page here, b/c UnlockPage does
+	 * it
+	 */
+	
+	unlock_page(page);
+
+	print_exit_status(err);
+	return err;
+}
+
+int unionfs_prepare_write(struct file * file, struct page * page, unsigned from, unsigned to)
+{
+	int err = 0;
+
+	print_entry_location();
+	
+	print_exit_status(err);
+	return err;
+}
+
+int unionfs_commit_write(struct file * file, struct page * page, unsigned from, unsigned to)
+{
+        int err = -ENOMEM;
+        struct inode * inode, * lower_inode;
+        struct file * lower_file = NULL;
+        loff_t pos;
+        unsigned bytes = to - from;
+	char * page_data = NULL;
+	mm_segment_t old_fs;
+
+        print_entry_location();
+
+        BUG_ON(file == NULL);
+
+        inode = page->mapping->host; /* CPW: Moved below print_entry_location */
+        lower_inode = itohi(inode);
+
+        if (ftopd(file) != NULL)
+                lower_file = ftohf(file);
+	
+        BUG_ON(lower_file == NULL);	/* XXX: is this assertion right here? */
+	
+	page_data = (char *) kmap(page);
+	lower_file->f_pos = (page->index << PAGE_CACHE_SHIFT) + from;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = vfs_write(lower_file, page_data + from, bytes, &lower_file->f_pos);
+	set_fs(old_fs);
+
+	kunmap(page);
+
+        if (err < 0)
+                goto out;
+
+        inode->i_blocks = lower_inode->i_blocks;
+        /* we may have to update i_size */
+        pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+        if (pos > i_size_read(inode))
+                i_size_write(inode, pos);
+
+        /*
+         * update mtime and ctime of lower level file system
+         * unionfs' mtime and ctime are updated by generic_file_write
+         */
+        lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+
+        mark_inode_dirty_sync(inode);
+
+out:
+        /* we must set our page as up-to-date */
+        if (err < 0)
+                ClearPageUptodate(page);
+        else
+                SetPageUptodate(page);
+        print_exit_status(err);
+        return err;			/* assume all is ok */
+}
+
+sector_t unionfs_bmap(struct address_space * mapping, sector_t block)
+{
+        int err = 0;
+        struct inode * inode, * lower_inode;
+	
+        print_entry_location();
+
+        inode = (struct inode *) mapping->host;
+        lower_inode = itohi(inode);
+
+        if (lower_inode->i_mapping->a_ops->bmap)
+                err = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping, block);
+        print_exit_location();
+        return err;
+}
+
+
+/*
+ * This function is copied verbatim from mm/filemap.c.
+ * XXX: It should be simply moved to some header file instead -- bug Al about it!
+ */
+static inline int sync_page(struct page *page)
+{
+        struct address_space *mapping = page->mapping;
+
+        if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
+                return mapping->a_ops->sync_page(page);
+        return 0;
+}
+
+int unionfs_sync_page(struct page *page)
+{
+        int err = 0;
+        struct inode * inode;
+        struct inode * lower_inode;
+        struct page * lower_page;
+
+        print_entry_location();
+
+        inode = page->mapping->host; /* CPW: Moved below print_entry_location */
+        lower_inode = itohi(inode);
+
+        /* find lower page (returns a locked page) */
+        lower_page = grab_cache_page(lower_inode->i_mapping, page->index);
+        if (!lower_page) {
+                err = -ENOMEM;
+                goto out;
+        }
+        err = sync_page(lower_page);
+
+        unlock_page(lower_page);	/* b/c grab_cache_page locked it */
+        page_cache_release(lower_page);	/* b/c grab_cache_page increased refcnt */
+
+out:
+        print_exit_status(err);
+        return err;
+}
+
+
+struct address_space_operations unionfs_aops = {
+        writepage:unionfs_writepage,
+        readpage:unionfs_readpage,
+        prepare_write:unionfs_prepare_write,
+        commit_write:unionfs_commit_write,
+        bmap:unionfs_bmap,
+        sync_page:unionfs_sync_page,
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * End:
+ */
diff -rNu unionfs-1.1.3/super.c unionfs-1.1.3-mmap/super.c
--- unionfs-1.1.3/super.c	2006-02-20 22:47:06.000000000 +0000
+++ unionfs-1.1.3-mmap/super.c	2006-03-02 15:07:50.000000000 +0000
@@ -28,7 +28,7 @@
 
 static void unionfs_read_inode(struct inode *inode)
 {
-	static struct address_space_operations unionfs_empty_aops;
+	extern struct address_space_operations unionfs_aops;
 	int size;
 
 	print_entry_location();
@@ -60,10 +60,7 @@
 	inode->i_version++;
 	inode->i_op = &unionfs_main_iops;
 	inode->i_fop = &unionfs_main_fops;
-	/* I don't think ->a_ops is ever allowed to be NULL */
-	inode->i_mapping->a_ops = &unionfs_empty_aops;
-	fist_dprint(7, "setting inode 0x%p a_ops to empty (0x%p)\n",
-		    inode, inode->i_mapping->a_ops);
+	inode->i_mapping->a_ops = &unionfs_aops;
 
 	print_exit_location();
 }
@@ -100,6 +97,10 @@
 
 	fist_checkinode(inode, "unionfs_delete_inode IN");
 	inode->i_size = 0;	/* every f/s seems to do that */
+
+	if (inode->i_data.nrpages)
+		truncate_inode_pages(&inode->i_data, 0);
+	
 	clear_inode(inode);
 
 	print_exit_location();
_______________________________________________
unionfs mailing list
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to