diff -urN oldtree/Documentation/ecryptfs.txt newtree/Documentation/ecryptfs.txt
--- oldtree/Documentation/ecryptfs.txt	1970-01-01 00:00:00.000000000 +0000
+++ newtree/Documentation/ecryptfs.txt	2006-02-18 17:24:58.707097720 +0000
@@ -0,0 +1,81 @@
+eCryptfs: A stacked cryptographic filesystem for Linux
+Maintainer: Phillip Hellewell
+Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
+Developers: Michael C. Thompson
+            Kent Yoder
+Current Release Version: 0.1
+
+This software is currently undergoing development. Make sure to
+maintain a backup copy of any data you write into eCryptfs.
+
+eCryptfs requires the userspace tools downloadable from the
+SourceForge site:
+
+http://sourceforge.net/projects/ecryptfs/
+
+Requirements include:
+ - Kernel version 2.6.15-rc1-mm1 or higher
+  - eCryptfs will work with 2.6.14, but you will need the
+    export_user_type.patch applied
+ - David Howells' userspace keyring headers and libraries, obtainable
+   from http://people.redhat.com/~dhowells/keyutils/
+  - (You will need to apply the keyutil_h_fix.diff patch to version 0.3)
+ - GnuPG Made Easy (GPGME)
+ - Building the kernel with:
+  - Cryptographic API
+  - Blowfish cipher
+  - Key retention support
+  - Filesystems->Miscellaneous filesystems->eCryptfs
+
+
+BUILD AND INSTALL INSTRUCTIONS
+
+If you are installing from the patch set:
+1) Apply export_user_type.patch to the kernel if you are running
+   kernel version 2.6.14
+2) Apply all patches in the patches/ directory to the kernel
+
+Once eCryptfs is already in the kernel:
+3) Select build options (see Requirements) and build kernel
+4) Apply keyutil_h_fix.diff to the keyutils if you are running version
+   0.3
+5) Run make and make install from the request-key/ directory.
+
+
+MOUNT-WIDE PASSPHRASE
+
+Create a new directory into which eCryptfs will write its encrypted
+files (i.e., /root/crypt).  Then, create the mount point directory
+(i.e., /mnt/crypt).  Now it's time to mount eCryptfs:
+
+mount -t ecryptfs /root/crypt /mnt/crypt
+
+You should be prompted for a passphrase and a salt (the salt may be
+blank).
+
+Try writing a new file:
+
+echo "Hello, World" > /mnt/crypt/hello.txt
+
+The operation will complete.  Notice that there is a new file in
+/root/crypt that is 3 pages (12288 bytes) in size.  This is the
+encrypted underlying file for what you just wrote.  To test reading,
+from start to finish, you need to clear the user session keyring:
+
+keyctl clear @u
+
+Then umount /mnt/crypt and mount again per the instructions given
+above.
+
+cat /mnt/crypt/hello.txt
+
+
+NOTES
+
+eCryptfs should only be mounted on (1) empty directories or (2)
+directories containing files only created by eCryptfs. If you mount a
+directory that has pre-existing files not created by eCryptfs, then
+behavior is undefined.
+
+Mike Halcrow
+mhalcrow@us.ibm.com
diff -urN oldtree/fs/Kconfig newtree/fs/Kconfig
--- oldtree/fs/Kconfig	2006-02-18 17:12:40.743285272 +0000
+++ newtree/fs/Kconfig	2006-02-18 17:24:58.710097264 +0000
@@ -937,6 +937,18 @@
 	  To compile this file system support as a module, choose M here: the
 	  module will be called affs.  If unsure, say N.
 
+config ECRYPTFS
+        tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
+        depends on EXPERIMENTAL
+        select KEYS
+        select CRYPTO
+        help
+          Encrypted filesystem that operates on the VFS layer.  See
+          Documentation/ecryptfs.txt to learn more about eCryptfs.
+
+          To compile this file system support as a module, choose M here: the
+          module will be called ecryptfs.
+
 config HFS_FS
 	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff -urN oldtree/fs/Kconfig.orig newtree/fs/Kconfig.orig
--- oldtree/fs/Kconfig.orig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/Kconfig.orig	2006-02-18 17:12:40.000000000 +0000
@@ -0,0 +1,1833 @@
+#
+# File system configuration
+#
+
+menu "File systems"
+
+config EXT2_FS
+	tristate "Second extended fs support"
+	help
+	  Ext2 is a standard Linux file system for hard disks.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called ext2.  Be aware however that the file system
+	  of your root partition (the one containing the directory /) cannot
+	  be compiled as a module, and so this could be dangerous.
+
+	  If unsure, say Y.
+
+config EXT2_FS_XATTR
+	bool "Ext2 extended attributes"
+	depends on EXT2_FS
+	help
+	  Extended attributes are name:value pairs associated with inodes by
+	  the kernel or by users (see the attr(5) manual page, or visit
+	  <http://acl.bestbits.at/> for details).
+
+	  If unsure, say N.
+
+config EXT2_FS_POSIX_ACL
+	bool "Ext2 POSIX Access Control Lists"
+	depends on EXT2_FS_XATTR
+	select FS_POSIX_ACL
+	help
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
+
+config EXT2_FS_SECURITY
+	bool "Ext2 Security Labels"
+	depends on EXT2_FS_XATTR
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the ext2 filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
+config EXT2_FS_XIP
+	bool "Ext2 execute in place support"
+	depends on EXT2_FS
+	help
+	  Execute in place can be used on memory-backed block devices. If you
+	  enable this option, you can select to mount block devices which are
+	  capable of this feature without using the page cache.
+
+	  If you do not use a block device that is capable of using this,
+	  or if unsure, say N.
+
+config FS_XIP
+# execute in place
+	bool
+	depends on EXT2_FS_XIP
+	default y
+
+config EXT3_FS
+	tristate "Ext3 journalling file system support"
+	select JBD
+	help
+	  This is the journaling version of the Second extended file system
+	  (often called ext3), the de facto standard Linux file system
+	  (method to organize files on a storage device) for hard disks.
+
+	  The journaling code included in this driver means you do not have
+	  to run e2fsck (file system checker) on your file systems after a
+	  crash.  The journal keeps track of any changes that were being made
+	  at the time the system crashed, and can ensure that your file system
+	  is consistent without the need for a lengthy check.
+
+	  Other than adding the journal to the file system, the on-disk format
+	  of ext3 is identical to ext2.  It is possible to freely switch
+	  between using the ext3 driver and the ext2 driver, as long as the
+	  file system has been cleanly unmounted, or e2fsck is run on the file
+	  system.
+
+	  To add a journal on an existing ext2 file system or change the
+	  behavior of ext3 file systems, you can use the tune2fs utility ("man
+	  tune2fs").  To modify attributes of files and directories on ext3
+	  file systems, use chattr ("man chattr").  You need to be using
+	  e2fsprogs version 1.20 or later in order to create ext3 journals
+	  (available at <http://sourceforge.net/projects/e2fsprogs/>).
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called ext3.  Be aware however that the file system
+	  of your root partition (the one containing the directory /) cannot
+	  be compiled as a module, and so this may be dangerous.
+
+config EXT3_FS_XATTR
+	bool "Ext3 extended attributes"
+	depends on EXT3_FS
+	default y
+	help
+	  Extended attributes are name:value pairs associated with inodes by
+	  the kernel or by users (see the attr(5) manual page, or visit
+	  <http://acl.bestbits.at/> for details).
+
+	  If unsure, say N.
+
+	  You need this for POSIX ACL support on ext3.
+
+config EXT3_FS_POSIX_ACL
+	bool "Ext3 POSIX Access Control Lists"
+	depends on EXT3_FS_XATTR
+	select FS_POSIX_ACL
+	help
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
+
+config EXT3_FS_SECURITY
+	bool "Ext3 Security Labels"
+	depends on EXT3_FS_XATTR
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the ext3 filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
+config JBD
+	tristate
+	help
+	  This is a generic journaling layer for block devices.  It is
+	  currently used by the ext3 and OCFS2 file systems, but it could
+	  also be used to add journal support to other file systems or block
+	  devices such as RAID or LVM.
+
+	  If you are using the ext3 or OCFS2 file systems, you need to
+	  say Y here. If you are not using ext3 OCFS2 then you will probably
+	  want to say N.
+
+	  To compile this device as a module, choose M here: the module will be
+	  called jbd.  If you are compiling ext3 or OCFS2 into the kernel,
+	  you cannot compile this code as a module.
+
+config JBD_DEBUG
+	bool "JBD (ext3) debugging support"
+	depends on JBD
+	help
+	  If you are using the ext3 journaled file system (or potentially any
+	  other file system/device using JBD), this option allows you to
+	  enable debugging output while the system is running, in order to
+	  help track down any problems you are having.  By default the
+	  debugging output will be turned off.
+
+	  If you select Y here, then you will be able to turn on debugging
+	  with "echo N > /proc/sys/fs/jbd-debug", where N is a number between
+	  1 and 5, the higher the number, the more debugging output is
+	  generated.  To turn debugging off again, do
+	  "echo 0 > /proc/sys/fs/jbd-debug".
+
+config FS_MBCACHE
+# Meta block cache for Extended Attributes (ext2/ext3)
+	tristate
+	depends on EXT2_FS_XATTR || EXT3_FS_XATTR
+	default y if EXT2_FS=y || EXT3_FS=y
+	default m if EXT2_FS=m || EXT3_FS=m
+
+config REISERFS_FS
+	tristate "Reiserfs support"
+	help
+	  Stores not just filenames but the files themselves in a balanced
+	  tree.  Uses journaling.
+
+	  Balanced trees are more efficient than traditional file system
+	  architectural foundations.
+
+	  In general, ReiserFS is as fast as ext2, but is very efficient with
+	  large directories and small files.  Additional patches are needed
+	  for NFS and quotas, please see <http://www.namesys.com/> for links.
+
+	  It is more easily extended to have features currently found in
+	  database and keyword search systems than block allocation based file
+	  systems are.  The next version will be so extended, and will support
+	  plugins consistent with our motto ``It takes more than a license to
+	  make source code open.''
+
+	  Read <http://www.namesys.com/> to learn more about reiserfs.
+
+	  Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
+
+	  If you like it, you can pay us to add new features to it that you
+	  need, buy a support contract, or pay us to port it to another OS.
+
+config REISERFS_CHECK
+	bool "Enable reiserfs debug mode"
+	depends on REISERFS_FS
+	help
+	  If you set this to Y, then ReiserFS will perform every check it can
+	  possibly imagine of its internal consistency throughout its
+	  operation.  It will also go substantially slower.  More than once we
+	  have forgotten that this was on, and then gone despondent over the
+	  latest benchmarks.:-) Use of this option allows our team to go all
+	  out in checking for consistency when debugging without fear of its
+	  effect on end users.  If you are on the verge of sending in a bug
+	  report, say Y and you might get a useful error message.  Almost
+	  everyone should say N.
+
+config REISERFS_PROC_INFO
+	bool "Stats in /proc/fs/reiserfs"
+	depends on REISERFS_FS
+	help
+	  Create under /proc/fs/reiserfs a hierarchy of files, displaying
+	  various ReiserFS statistics and internal data at the expense of
+	  making your kernel or module slightly larger (+8 KB). This also
+	  increases the amount of kernel memory required for each mount.
+	  Almost everyone but ReiserFS developers and people fine-tuning
+	  reiserfs or tracing problems should say N.
+
+config REISERFS_FS_XATTR
+	bool "ReiserFS extended attributes"
+	depends on REISERFS_FS
+	help
+	  Extended attributes are name:value pairs associated with inodes by
+	  the kernel or by users (see the attr(5) manual page, or visit
+	  <http://acl.bestbits.at/> for details).
+
+	  If unsure, say N.
+
+config REISERFS_FS_POSIX_ACL
+	bool "ReiserFS POSIX Access Control Lists"
+	depends on REISERFS_FS_XATTR
+	select FS_POSIX_ACL
+	help
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
+
+config REISERFS_FS_SECURITY
+	bool "ReiserFS Security Labels"
+	depends on REISERFS_FS_XATTR
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the ReiserFS filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
+config JFS_FS
+	tristate "JFS filesystem support"
+	select NLS
+	help
+	  This is a port of IBM's Journaled Filesystem .  More information is
+	  available in the file <file:Documentation/filesystems/jfs.txt>.
+
+	  If you do not intend to use the JFS filesystem, say N.
+
+config JFS_POSIX_ACL
+	bool "JFS POSIX Access Control Lists"
+	depends on JFS_FS
+	select FS_POSIX_ACL
+	help
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
+
+config JFS_SECURITY
+	bool "JFS Security Labels"
+	depends on JFS_FS
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the jfs filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
+config JFS_DEBUG
+	bool "JFS debugging"
+	depends on JFS_FS
+	help
+	  If you are experiencing any problems with the JFS filesystem, say
+	  Y here.  This will result in additional debugging messages to be
+	  written to the system log.  Under normal circumstances, this
+	  results in very little overhead.
+
+config JFS_STATISTICS
+	bool "JFS statistics"
+	depends on JFS_FS
+	help
+	  Enabling this option will cause statistics from the JFS file system
+	  to be made available to the user in the /proc/fs/jfs/ directory.
+
+config FS_POSIX_ACL
+# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs)
+#
+# NOTE: you can implement Posix ACLs without these helpers (XFS does).
+# 	Never use this symbol for ifdefs.
+#
+	bool
+	default n
+
+source "fs/xfs/Kconfig"
+
+config OCFS2_FS
+	tristate "OCFS2 file system support (EXPERIMENTAL)"
+	depends on NET && EXPERIMENTAL
+	select CONFIGFS_FS
+	select JBD
+	select CRC32
+	select INET
+	help
+	  OCFS2 is a general purpose extent based shared disk cluster file
+	  system with many similarities to ext3. It supports 64 bit inode
+	  numbers, and has automatically extending metadata groups which may
+	  also make it attractive for non-clustered use.
+
+	  You'll want to install the ocfs2-tools package in order to at least
+	  get "mount.ocfs2".
+
+	  Project web page:    http://oss.oracle.com/projects/ocfs2
+	  Tools web page:      http://oss.oracle.com/projects/ocfs2-tools
+	  OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
+
+	  Note: Features which OCFS2 does not support yet:
+	          - extended attributes
+		  - shared writeable mmap
+	          - loopback is supported, but data written will not
+	            be cluster coherent.
+	          - quotas
+	          - cluster aware flock
+	          - Directory change notification (F_NOTIFY)
+	          - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
+	          - POSIX ACLs
+	          - readpages / writepages (not user visible)
+
+config MINIX_FS
+	tristate "Minix fs support"
+	help
+	  Minix is a simple operating system used in many classes about OS's.
+	  The minix file system (method to organize files on a hard disk
+	  partition or a floppy disk) was the original file system for Linux,
+	  but has been superseded by the second extended file system ext2fs.
+	  You don't want to use the minix file system on your hard disk
+	  because of certain built-in restrictions, but it is sometimes found
+	  on older Linux floppy disks.  This option will enlarge your kernel
+	  by about 28 KB. If unsure, say N.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called minix.  Note that the file system of your root
+	  partition (the one containing the directory /) cannot be compiled as
+	  a module.
+
+config ROMFS_FS
+	tristate "ROM file system support"
+	---help---
+	  This is a very small read-only file system mainly intended for
+	  initial ram disks of installation disks, but it could be used for
+	  other read-only media as well.  Read
+	  <file:Documentation/filesystems/romfs.txt> for details.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called romfs.  Note that the file system of your
+	  root partition (the one containing the directory /) cannot be a
+	  module.
+
+	  If you don't know whether you need it, then you don't need it:
+	  answer N.
+
+config INOTIFY
+	bool "Inotify file change notification support"
+	default y
+	---help---
+	  Say Y here to enable inotify support and the associated system
+	  calls.  Inotify is a file change notification system and a
+	  replacement for dnotify.  Inotify fixes numerous shortcomings in
+	  dnotify and introduces several new features.  It allows monitoring
+	  of both files and directories via a single open fd.  Other features
+	  include multiple file events, one-shot support, and unmount
+	  notification.
+
+	  For more information, see Documentation/filesystems/inotify.txt
+
+	  If unsure, say Y.
+
+config QUOTA
+	bool "Quota support"
+	help
+	  If you say Y here, you will be able to set per user limits for disk
+	  usage (also called disk quotas). Currently, it works for the
+	  ext2, ext3, and reiserfs file system. ext3 also supports journalled
+	  quotas for which you don't need to run quotacheck(8) after an unclean
+	  shutdown.
+	  For further details, read the Quota mini-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, or the documentation provided
+	  with the quota tools. Probably the quota support is only useful for
+	  multi user systems. If unsure, say N.
+
+config QFMT_V1
+	tristate "Old quota format support"
+	depends on QUOTA
+	help
+	  This quota format was (is) used by kernels earlier than 2.4.22. If
+	  you have quota working and you don't want to convert to new quota
+	  format say Y here.
+
+config QFMT_V2
+	tristate "Quota format v2 support"
+	depends on QUOTA
+	help
+	  This quota format allows using quotas with 32-bit UIDs/GIDs. If you
+	  need this functionality say Y here.
+
+config QUOTACTL
+	bool
+	depends on XFS_QUOTA || QUOTA
+	default y
+
+config DNOTIFY
+	bool "Dnotify support" if EMBEDDED
+	default y
+	help
+	  Dnotify is a directory-based per-fd file change notification system
+	  that uses signals to communicate events to user-space.  There exist
+	  superior alternatives, but some applications may still rely on
+	  dnotify.
+
+	  Because of this, if unsure, say Y.
+
+config AUTOFS_FS
+	tristate "Kernel automounter support"
+	help
+	  The automounter is a tool to automatically mount remote file systems
+	  on demand. This implementation is partially kernel-based to reduce
+	  overhead in the already-mounted case; this is unlike the BSD
+	  automounter (amd), which is a pure user space daemon.
+
+	  To use the automounter you need the user-space tools from the autofs
+	  package; you can find the location in <file:Documentation/Changes>.
+	  You also want to answer Y to "NFS file system support", below.
+
+	  If you want to use the newer version of the automounter with more
+	  features, say N here and say Y to "Kernel automounter v4 support",
+	  below.
+
+	  To compile this support as a module, choose M here: the module will be
+	  called autofs.
+
+	  If you are not a part of a fairly large, distributed network, you
+	  probably do not need an automounter, and can say N here.
+
+config AUTOFS4_FS
+	tristate "Kernel automounter version 4 support (also supports v3)"
+	help
+	  The automounter is a tool to automatically mount remote file systems
+	  on demand. This implementation is partially kernel-based to reduce
+	  overhead in the already-mounted case; this is unlike the BSD
+	  automounter (amd), which is a pure user space daemon.
+
+	  To use the automounter you need the user-space tools from
+	  <ftp://ftp.kernel.org/pub/linux/daemons/autofs/v4/>; you also
+	  want to answer Y to "NFS file system support", below.
+
+	  To compile this support as a module, choose M here: the module will be
+	  called autofs4.  You will need to add "alias autofs autofs4" to your
+	  modules configuration file.
+
+	  If you are not a part of a fairly large, distributed network or
+	  don't have a laptop which needs to dynamically reconfigure to the
+	  local network, you probably do not need an automounter, and can say
+	  N here.
+
+config FUSE_FS
+	tristate "Filesystem in Userspace support"
+	help
+	  With FUSE it is possible to implement a fully functional filesystem
+	  in a userspace program.
+
+	  There's also companion library: libfuse.  This library along with
+	  utilities is available from the FUSE homepage:
+	  <http://fuse.sourceforge.net/>
+
+	  See <file:Documentation/filesystems/fuse.txt> for more information.
+	  See <file:Documentation/Changes> for needed library/utility version.
+
+	  If you want to develop a userspace FS, or if you want to use
+	  a filesystem based on FUSE, answer Y or M.
+
+menu "CD-ROM/DVD Filesystems"
+
+config ISO9660_FS
+	tristate "ISO 9660 CDROM file system support"
+	help
+	  This is the standard file system used on CD-ROMs.  It was previously
+	  known as "High Sierra File System" and is called "hsfs" on other
+	  Unix systems.  The so-called Rock-Ridge extensions which allow for
+	  long Unix filenames and symbolic links are also supported by this
+	  driver.  If you have a CD-ROM drive and want to do more with it than
+	  just listen to audio CDs and watch its LEDs, say Y (and read
+	  <file:Documentation/filesystems/isofs.txt> and the CD-ROM-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>), thereby
+	  enlarging your kernel by about 27 KB; otherwise say N.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called isofs.
+
+config JOLIET
+	bool "Microsoft Joliet CDROM extensions"
+	depends on ISO9660_FS
+	select NLS
+	help
+	  Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system
+	  which allows for long filenames in unicode format (unicode is the
+	  new 16 bit character code, successor to ASCII, which encodes the
+	  characters of almost all languages of the world; see
+	  <http://www.unicode.org/> for more information).  Say Y here if you
+	  want to be able to read Joliet CD-ROMs under Linux.
+
+config ZISOFS
+	bool "Transparent decompression extension"
+	depends on ISO9660_FS
+	select ZLIB_INFLATE
+	help
+	  This is a Linux-specific extension to RockRidge which lets you store
+	  data in compressed form on a CD-ROM and have it transparently
+	  decompressed when the CD-ROM is accessed.  See
+	  <http://www.kernel.org/pub/linux/utils/fs/zisofs/> for the tools
+	  necessary to create such a filesystem.  Say Y here if you want to be
+	  able to read such compressed CD-ROMs.
+
+config ZISOFS_FS
+# for fs/nls/Config.in
+	tristate
+	depends on ZISOFS
+	default ISO9660_FS
+
+config UDF_FS
+	tristate "UDF file system support"
+	help
+	  This is the new file system used on some CD-ROMs and DVDs. Say Y if
+	  you intend to mount DVD discs or CDRW's written in packet mode, or
+	  if written to by other UDF utilities, such as DirectCD.
+	  Please read <file:Documentation/filesystems/udf.txt>.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called udf.
+
+	  If unsure, say N.
+
+config UDF_NLS
+	bool
+	default y
+	depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)
+
+endmenu
+
+menu "DOS/FAT/NT Filesystems"
+
+config FAT_FS
+	tristate
+	select NLS
+	help
+	  If you want to use one of the FAT-based file systems (the MS-DOS and
+	  VFAT (Windows 95) file systems), then you must say Y or M here
+	  to include FAT support. You will then be able to mount partitions or
+	  diskettes with FAT-based file systems and transparently access the
+	  files on them, i.e. MSDOS files will look and behave just like all
+	  other Unix files.
+
+	  This FAT support is not a file system in itself, it only provides
+	  the foundation for the other file systems. You will have to say Y or
+	  M to at least one of "MSDOS fs support" or "VFAT fs support" in
+	  order to make use of it.
+
+	  Another way to read and write MSDOS floppies and hard drive
+	  partitions from within Linux (but not transparently) is with the
+	  mtools ("man mtools") program suite. You don't need to say Y here in
+	  order to do that.
+
+	  If you need to move large files on floppies between a DOS and a
+	  Linux box, say Y here, mount the floppy under Linux with an MSDOS
+	  file system and use GNU tar's M option. GNU tar is a program
+	  available for Unix and DOS ("man tar" or "info tar").
+
+	  It is now also becoming possible to read and write compressed FAT
+	  file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
+	  details.
+
+	  The FAT support will enlarge your kernel by about 37 KB. If unsure,
+	  say Y.
+
+	  To compile this as a module, choose M here: the module will be called
+	  fat.  Note that if you compile the FAT support as a module, you
+	  cannot compile any of the FAT-based file systems into the kernel
+	  -- they will have to be modules as well.
+
+config MSDOS_FS
+	tristate "MSDOS fs support"
+	select FAT_FS
+	help
+	  This allows you to mount MSDOS partitions of your hard drive (unless
+	  they are compressed; to access compressed MSDOS partitions under
+	  Linux, you can either use the DOS emulator DOSEMU, described in the
+	  DOSEMU-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, or try dmsdosfs in
+	  <ftp://ibiblio.org/pub/Linux/system/filesystems/dosfs/>. If you
+	  intend to use dosemu with a non-compressed MSDOS partition, say Y
+	  here) and MSDOS floppies. This means that file access becomes
+	  transparent, i.e. the MSDOS files look and behave just like all
+	  other Unix files.
+
+	  If you have Windows 95 or Windows NT installed on your MSDOS
+	  partitions, you should use the VFAT file system (say Y to "VFAT fs
+	  support" below), or you will not be able to see the long filenames
+	  generated by Windows 95 / Windows NT.
+
+	  This option will enlarge your kernel by about 7 KB. If unsure,
+	  answer Y. This will only work if you said Y to "DOS FAT fs support"
+	  as well. To compile this as a module, choose M here: the module will
+	  be called msdos.
+
+config VFAT_FS
+	tristate "VFAT (Windows-95) fs support"
+	select FAT_FS
+	help
+	  This option provides support for normal Windows file systems with
+	  long filenames.  That includes non-compressed FAT-based file systems
+	  used by Windows 95, Windows 98, Windows NT 4.0, and the Unix
+	  programs from the mtools package.
+
+	  The VFAT support enlarges your kernel by about 10 KB and it only
+	  works if you said Y to the "DOS FAT fs support" above.  Please read
+	  the file <file:Documentation/filesystems/vfat.txt> for details.  If
+	  unsure, say Y.
+
+	  To compile this as a module, choose M here: the module will be called
+	  vfat.
+
+config FAT_DEFAULT_CODEPAGE
+	int "Default codepage for FAT"
+	depends on MSDOS_FS || VFAT_FS
+	default 437
+	help
+	  This option should be set to the codepage of your FAT filesystems.
+	  It can be overridden with the "codepage" mount option.
+	  See <file:Documentation/filesystems/vfat.txt> for more information.
+
+config FAT_DEFAULT_IOCHARSET
+	string "Default iocharset for FAT"
+	depends on VFAT_FS
+	default "iso8859-1"
+	help
+	  Set this to the default input/output character set you'd
+	  like FAT to use. It should probably match the character set
+	  that most of your FAT filesystems use, and can be overridden
+	  with the "iocharset" mount option for FAT filesystems.
+	  Note that "utf8" is not recommended for FAT filesystems.
+	  If unsure, you shouldn't set "utf8" here.
+	  See <file:Documentation/filesystems/vfat.txt> for more information.
+
+config NTFS_FS
+	tristate "NTFS file system support"
+	select NLS
+	help
+	  NTFS is the file system of Microsoft Windows NT, 2000, XP and 2003.
+
+	  Saying Y or M here enables read support.  There is partial, but
+	  safe, write support available.  For write support you must also
+	  say Y to "NTFS write support" below.
+
+	  There are also a number of user-space tools available, called
+	  ntfsprogs.  These include ntfsundelete and ntfsresize, that work
+	  without NTFS support enabled in the kernel.
+
+	  This is a rewrite from scratch of Linux NTFS support and replaced
+	  the old NTFS code starting with Linux 2.5.11.  A backport to
+	  the Linux 2.4 kernel series is separately available as a patch
+	  from the project web site.
+
+	  For more information see <file:Documentation/filesystems/ntfs.txt>
+	  and <http://linux-ntfs.sourceforge.net/>.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called ntfs.
+
+	  If you are not using Windows NT, 2000, XP or 2003 in addition to
+	  Linux on your computer it is safe to say N.
+
+config NTFS_DEBUG
+	bool "NTFS debugging support"
+	depends on NTFS_FS
+	help
+	  If you are experiencing any problems with the NTFS file system, say
+	  Y here.  This will result in additional consistency checks to be
+	  performed by the driver as well as additional debugging messages to
+	  be written to the system log.  Note that debugging messages are
+	  disabled by default.  To enable them, supply the option debug_msgs=1
+	  at the kernel command line when booting the kernel or as an option
+	  to insmod when loading the ntfs module.  Once the driver is active,
+	  you can enable debugging messages by doing (as root):
+	  echo 1 > /proc/sys/fs/ntfs-debug
+	  Replacing the "1" with "0" would disable debug messages.
+
+	  If you leave debugging messages disabled, this results in little
+	  overhead, but enabling debug messages results in very significant
+	  slowdown of the system.
+
+	  When reporting bugs, please try to have available a full dump of
+	  debugging messages while the misbehaviour was occurring.
+
+config NTFS_RW
+	bool "NTFS write support"
+	depends on NTFS_FS
+	help
+	  This enables the partial, but safe, write support in the NTFS driver.
+
+	  The only supported operation is overwriting existing files, without
+	  changing the file length.  No file or directory creation, deletion or
+	  renaming is possible.  Note only non-resident files can be written to
+	  so you may find that some very small files (<500 bytes or so) cannot
+	  be written to.
+
+	  While we cannot guarantee that it will not damage any data, we have
+	  so far not received a single report where the driver would have
+	  damaged someones data so we assume it is perfectly safe to use.
+
+	  Note:  While write support is safe in this version (a rewrite from
+	  scratch of the NTFS support), it should be noted that the old NTFS
+	  write support, included in Linux 2.5.10 and before (since 1997),
+	  is not safe.
+
+	  This is currently useful with TopologiLinux.  TopologiLinux is run
+	  on top of any DOS/Microsoft Windows system without partitioning your
+	  hard disk.  Unlike other Linux distributions TopologiLinux does not
+	  need its own partition.  For more information see
+	  <http://topologi-linux.sourceforge.net/>
+
+	  It is perfectly safe to say N here.
+
+endmenu
+
+menu "Pseudo filesystems"
+
+config PROC_FS
+	bool "/proc file system support"
+	help
+	  This is a virtual file system providing information about the status
+	  of the system. "Virtual" means that it doesn't take up any space on
+	  your hard disk: the files are created on the fly by the kernel when
+	  you try to access them. Also, you cannot read the files with older
+	  version of the program less: you need to use more or cat.
+
+	  It's totally cool; for example, "cat /proc/interrupts" gives
+	  information about what the different IRQs are used for at the moment
+	  (there is a small number of Interrupt ReQuest lines in your computer
+	  that are used by the attached devices to gain the CPU's attention --
+	  often a source of trouble if two devices are mistakenly configured
+	  to use the same IRQ). The program procinfo to display some
+	  information about your system gathered from the /proc file system.
+
+	  Before you can use the /proc file system, it has to be mounted,
+	  meaning it has to be given a location in the directory hierarchy.
+	  That location should be /proc. A command such as "mount -t proc proc
+	  /proc" or the equivalent line in /etc/fstab does the job.
+
+	  The /proc file system is explained in the file
+	  <file:Documentation/filesystems/proc.txt> and on the proc(5) manpage
+	  ("man 5 proc").
+
+	  This option will enlarge your kernel by about 67 KB. Several
+	  programs depend on this, so everyone should say Y here.
+
+config PROC_KCORE
+	bool "/proc/kcore support" if !ARM
+	depends on PROC_FS && MMU
+
+config PROC_VMCORE
+        bool "/proc/vmcore support (EXPERIMENTAL)"
+        depends on PROC_FS && EXPERIMENTAL && CRASH_DUMP
+        help
+        Exports the dump image of crashed kernel in ELF format.
+
+config SYSFS
+	bool "sysfs file system support" if EMBEDDED
+	default y
+	help
+	The sysfs filesystem is a virtual filesystem that the kernel uses to
+	export internal kernel objects, their attributes, and their
+	relationships to one another.
+
+	Users can use sysfs to ascertain useful information about the running
+	kernel, such as the devices the kernel has discovered on each bus and
+	which driver each is bound to. sysfs can also be used to tune devices
+	and other kernel subsystems.
+
+	Some system agents rely on the information in sysfs to operate.
+	/sbin/hotplug uses device and object attributes in sysfs to assist in
+	delegating policy decisions, like persistantly naming devices.
+
+	sysfs is currently used by the block subsystem to mount the root
+	partition.  If sysfs is disabled you must specify the boot device on
+	the kernel boot command line via its major and minor numbers.  For
+	example, "root=03:01" for /dev/hda1.
+
+	Designers of embedded systems may wish to say N here to conserve space.
+
+config TMPFS
+	bool "Virtual memory file system support (former shm fs)"
+	help
+	  Tmpfs is a file system which keeps all files in virtual memory.
+
+	  Everything in tmpfs is temporary in the sense that no files will be
+	  created on your hard drive. The files live in memory and swap
+	  space. If you unmount a tmpfs instance, everything stored therein is
+	  lost.
+
+	  See <file:Documentation/filesystems/tmpfs.txt> for details.
+
+config HUGETLBFS
+	bool "HugeTLB file system support"
+	depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
+
+config HUGETLB_PAGE
+	def_bool HUGETLBFS
+
+config RAMFS
+	bool
+	default y
+	---help---
+	  Ramfs is a file system which keeps all files in RAM. It allows
+	  read and write access.
+
+	  It is more of an programming example than a useable file system.  If
+	  you need a file system which lives in RAM with limit checking use
+	  tmpfs.
+
+	  To compile this as a module, choose M here: the module will be called
+	  ramfs.
+
+config RELAYFS_FS
+	tristate "Relayfs file system support"
+	---help---
+	  Relayfs is a high-speed data relay filesystem designed to provide
+	  an efficient mechanism for tools and facilities to relay large
+	  amounts of data from kernel space to user space.
+
+	  To compile this code as a module, choose M here: the module will be
+	  called relayfs.
+
+	  If unsure, say N.
+
+config CONFIGFS_FS
+	tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  configfs is a ram-based filesystem that provides the converse
+	  of sysfs's functionality. Where sysfs is a filesystem-based
+	  view of kernel objects, configfs is a filesystem-based manager
+	  of kernel objects, or config_items.
+
+	  Both sysfs and configfs can and should exist together on the
+	  same system. One is not a replacement for the other.
+
+endmenu
+
+menu "Miscellaneous filesystems"
+
+config ADFS_FS
+	tristate "ADFS file system support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  The Acorn Disc Filing System is the standard file system of the
+	  RiscOS operating system which runs on Acorn's ARM-based Risc PC
+	  systems and the Acorn Archimedes range of machines. If you say Y
+	  here, Linux will be able to read from ADFS partitions on hard drives
+	  and from ADFS-formatted floppy discs. If you also want to be able to
+	  write to those devices, say Y to "ADFS write support" below.
+
+	  The ADFS partition should be the first partition (i.e.,
+	  /dev/[hs]d?1) on each of your drives. Please read the file
+	  <file:Documentation/filesystems/adfs.txt> for further details.
+
+	  To compile this code as a module, choose M here: the module will be
+	  called adfs.
+
+	  If unsure, say N.
+
+config ADFS_FS_RW
+	bool "ADFS write support (DANGEROUS)"
+	depends on ADFS_FS
+	help
+	  If you say Y here, you will be able to write to ADFS partitions on
+	  hard drives and ADFS-formatted floppy disks. This is experimental
+	  codes, so if you're unsure, say N.
+
+config AFFS_FS
+	tristate "Amiga FFS file system support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  The Fast File System (FFS) is the common file system used on hard
+	  disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20).  Say Y
+	  if you want to be able to read and write files from and to an Amiga
+	  FFS partition on your hard drive.  Amiga floppies however cannot be
+	  read with this driver due to an incompatibility of the floppy
+	  controller used in an Amiga and the standard floppy controller in
+	  PCs and workstations. Read <file:Documentation/filesystems/affs.txt>
+	  and <file:fs/affs/Changes>.
+
+	  With this driver you can also mount disk files used by Bernd
+	  Schmidt's Un*X Amiga Emulator
+	  (<http://www.freiburg.linux.de/~uae/>).
+	  If you want to do this, you will also need to say Y or M to "Loop
+	  device support", above.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called affs.  If unsure, say N.
+
+config HFS_FS
+	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select NLS
+	help
+	  If you say Y here, you will be able to mount Macintosh-formatted
+	  floppy disks and hard drive partitions with full read-write access.
+	  Please read <file:fs/hfs/HFS.txt> to learn about the available mount
+	  options.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called hfs.
+
+config HFSPLUS_FS
+	tristate "Apple Extended HFS file system support"
+	select NLS
+	select NLS_UTF8
+	help
+	  If you say Y here, you will be able to mount extended format
+	  Macintosh-formatted hard drive partitions with full read-write access.
+
+	  This file system is often called HFS+ and was introduced with
+	  MacOS 8. It includes all Mac specific filesystem data such as
+	  data forks and creator codes, but it also has several UNIX
+	  style features such as file ownership and permissions.
+
+config BEFS_FS
+	tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select NLS
+	help
+	  The BeOS File System (BeFS) is the native file system of Be, Inc's
+	  BeOS. Notable features include support for arbitrary attributes
+	  on files and directories, and database-like indeces on selected
+	  attributes. (Also note that this driver doesn't make those features
+	  available at this time). It is a 64 bit filesystem, so it supports
+	  extremly large volumes and files.
+
+	  If you use this filesystem, you should also say Y to at least one
+	  of the NLS (native language support) options below.
+
+	  If you don't know what this is about, say N.
+
+	  To compile this as a module, choose M here: the module will be
+	  called befs.
+
+config BEFS_DEBUG
+	bool "Debug BeFS"
+	depends on BEFS_FS
+	help
+	  If you say Y here, you can use the 'debug' mount option to enable
+	  debugging output from the driver. 
+
+config BFS_FS
+	tristate "BFS file system support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  Boot File System (BFS) is a file system used under SCO UnixWare to
+	  allow the bootloader access to the kernel image and other important
+	  files during the boot process.  It is usually mounted under /stand
+	  and corresponds to the slice marked as "STAND" in the UnixWare
+	  partition.  You should say Y if you want to read or write the files
+	  on your /stand slice from within Linux.  You then also need to say Y
+	  to "UnixWare slices support", below.  More information about the BFS
+	  file system is contained in the file
+	  <file:Documentation/filesystems/bfs.txt>.
+
+	  If you don't know what this is about, say N.
+
+	  To compile this as a module, choose M here: the module will be called
+	  bfs.  Note that the file system of your root partition (the one
+	  containing the directory /) cannot be compiled as a module.
+
+
+
+config EFS_FS
+	tristate "EFS file system support (read only) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  EFS is an older file system used for non-ISO9660 CD-ROMs and hard
+	  disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
+	  uses the XFS file system for hard disk partitions however).
+
+	  This implementation only offers read-only access. If you don't know
+	  what all this is about, it's safe to say N. For more information
+	  about EFS see its home page at <http://aeschi.ch.eu.org/efs/>.
+
+	  To compile the EFS file system support as a module, choose M here: the
+	  module will be called efs.
+
+config JFFS_FS
+	tristate "Journalling Flash File System (JFFS) support"
+	depends on MTD
+	help
+	  JFFS is the Journaling Flash File System developed by Axis
+	  Communications in Sweden, aimed at providing a crash/powerdown-safe
+	  file system for disk-less embedded devices. Further information is
+	  available at (<http://developer.axis.com/software/jffs/>).
+
+config JFFS_FS_VERBOSE
+	int "JFFS debugging verbosity (0 = quiet, 3 = noisy)"
+	depends on JFFS_FS
+	default "0"
+	help
+	  Determines the verbosity level of the JFFS debugging messages.
+
+config JFFS_PROC_FS
+	bool "JFFS stats available in /proc filesystem"
+	depends on JFFS_FS && PROC_FS
+	help
+	  Enabling this option will cause statistics from mounted JFFS file systems
+	  to be made available to the user in the /proc/fs/jffs/ directory.
+
+config JFFS2_FS
+	tristate "Journalling Flash File System v2 (JFFS2) support"
+	select CRC32
+	depends on MTD
+	help
+	  JFFS2 is the second generation of the Journalling Flash File System
+	  for use on diskless embedded devices. It provides improved wear
+	  levelling, compression and support for hard links. You cannot use
+	  this on normal block devices, only on 'MTD' devices.
+
+	  Further information on the design and implementation of JFFS2 is
+	  available at <http://sources.redhat.com/jffs2/>.
+
+config JFFS2_FS_DEBUG
+	int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
+	depends on JFFS2_FS
+	default "0"
+	help
+	  This controls the amount of debugging messages produced by the JFFS2
+	  code. Set it to zero for use in production systems. For evaluation,
+	  testing and debugging, it's advisable to set it to one. This will
+	  enable a few assertions and will print debugging messages at the
+	  KERN_DEBUG loglevel, where they won't normally be visible. Level 2
+	  is unlikely to be useful - it enables extra debugging in certain
+	  areas which at one point needed debugging, but when the bugs were
+	  located and fixed, the detailed messages were relegated to level 2.
+
+	  If reporting bugs, please try to have available a full dump of the
+	  messages at debug level 1 while the misbehaviour was occurring.
+
+config JFFS2_FS_WRITEBUFFER
+	bool "JFFS2 write-buffering support"
+	depends on JFFS2_FS
+	default y
+	help
+	  This enables the write-buffering support in JFFS2.
+
+	  This functionality is required to support JFFS2 on the following
+	  types of flash devices:
+	    - NAND flash
+	    - NOR flash with transparent ECC
+	    - DataFlash
+
+config JFFS2_SUMMARY
+	bool "JFFS2 summary support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL
+	default n
+	help
+	  This feature makes it possible to use summary information
+	  for faster filesystem mount.
+
+	  The summary information can be inserted into a filesystem image
+	  by the utility 'sumtool'.
+
+	  If unsure, say 'N'.
+
+config JFFS2_COMPRESSION_OPTIONS
+	bool "Advanced compression options for JFFS2"
+	depends on JFFS2_FS
+	default n
+	help
+	  Enabling this option allows you to explicitly choose which
+	  compression modules, if any, are enabled in JFFS2. Removing
+	  compressors and mean you cannot read existing file systems,
+	  and enabling experimental compressors can mean that you
+	  write a file system which cannot be read by a standard kernel.
+
+	  If unsure, you should _definitely_ say 'N'.
+
+config JFFS2_ZLIB
+	bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS
+	select ZLIB_INFLATE
+	select ZLIB_DEFLATE
+	depends on JFFS2_FS
+	default y
+        help
+          Zlib is designed to be a free, general-purpose, legally unencumbered,
+          lossless data-compression library for use on virtually any computer
+          hardware and operating system. See <http://www.gzip.org/zlib/> for
+          further information.
+
+          Say 'Y' if unsure.
+
+config JFFS2_RTIME
+	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+	depends on JFFS2_FS
+	default y
+        help
+          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+
+config JFFS2_RUBIN
+	bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
+	depends on JFFS2_FS
+	default n
+        help
+          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+
+choice
+        prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
+        default JFFS2_CMODE_PRIORITY
+        depends on JFFS2_FS
+        help
+          You can set here the default compression mode of JFFS2 from
+          the available compression modes. Don't touch if unsure.
+
+config JFFS2_CMODE_NONE
+        bool "no compression"
+        help
+          Uses no compression.
+
+config JFFS2_CMODE_PRIORITY
+        bool "priority"
+        help
+          Tries the compressors in a predefinied order and chooses the first
+          successful one.
+
+config JFFS2_CMODE_SIZE
+        bool "size (EXPERIMENTAL)"
+        help
+          Tries all compressors and chooses the one which has the smallest
+          result.
+
+endchoice
+
+config CRAMFS
+	tristate "Compressed ROM file system support (cramfs)"
+	select ZLIB_INFLATE
+	help
+	  Saying Y here includes support for CramFs (Compressed ROM File
+	  System).  CramFs is designed to be a simple, small, and compressed
+	  file system for ROM based embedded systems.  CramFs is read-only,
+	  limited to 256MB file systems (with 16MB files), and doesn't support
+	  16/32 bits uid/gid, hard links and timestamps.
+
+	  See <file:Documentation/filesystems/cramfs.txt> and
+	  <file:fs/cramfs/README> for further information.
+
+	  To compile this as a module, choose M here: the module will be called
+	  cramfs.  Note that the root file system (the one containing the
+	  directory /) cannot be compiled as a module.
+
+	  If unsure, say N.
+
+config VXFS_FS
+	tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+	help
+	  FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
+	  file system format.  VERITAS VxFS(TM) is the standard file system
+	  of SCO UnixWare (and possibly others) and optionally available
+	  for Sunsoft Solaris, HP-UX and many other operating systems.
+	  Currently only readonly access is supported.
+
+	  NOTE: the file system type as used by mount(1), mount(2) and
+	  fstab(5) is 'vxfs' as it describes the file system format, not
+	  the actual driver.
+
+	  To compile this as a module, choose M here: the module will be
+	  called freevxfs.  If unsure, say N.
+
+
+config HPFS_FS
+	tristate "OS/2 HPFS file system support"
+	help
+	  OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
+	  is the file system used for organizing files on OS/2 hard disk
+	  partitions. Say Y if you want to be able to read files from and
+	  write files to an OS/2 HPFS partition on your hard drive. OS/2
+	  floppies however are in regular MSDOS format, so you don't need this
+	  option in order to be able to read them. Read
+	  <file:Documentation/filesystems/hpfs.txt>.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called hpfs.  If unsure, say N.
+
+
+
+config QNX4FS_FS
+	tristate "QNX4 file system support (read only)"
+	help
+	  This is the file system used by the real-time operating systems
+	  QNX 4 and QNX 6 (the latter is also called QNX RTP).
+	  Further information is available at <http://www.qnx.com/>.
+	  Say Y if you intend to mount QNX hard disks or floppies.
+	  Unless you say Y to "QNX4FS read-write support" below, you will
+	  only be able to read these file systems.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called qnx4.
+
+	  If you don't know whether you need it, then you don't need it:
+	  answer N.
+
+config QNX4FS_RW
+	bool "QNX4FS write support (DANGEROUS)"
+	depends on QNX4FS_FS && EXPERIMENTAL && BROKEN
+	help
+	  Say Y if you want to test write support for QNX4 file systems.
+
+	  It's currently broken, so for now:
+	  answer N.
+
+
+
+config SYSV_FS
+	tristate "System V/Xenix/V7/Coherent file system support"
+	help
+	  SCO, Xenix and Coherent are commercial Unix systems for Intel
+	  machines, and Version 7 was used on the DEC PDP-11. Saying Y
+	  here would allow you to read from their floppies and hard disk
+	  partitions.
+
+	  If you have floppies or hard disk partitions like that, it is likely
+	  that they contain binaries from those other Unix systems; in order
+	  to run these binaries, you will want to install linux-abi which is a
+	  a set of kernel modules that lets you run SCO, Xenix, Wyse,
+	  UnixWare, Dell Unix and System V programs under Linux.  It is
+	  available via FTP (user: ftp) from
+	  <ftp://ftp.openlinux.org/pub/people/hch/linux-abi/>).
+	  NOTE: that will work only for binaries from Intel-based systems;
+	  PDP ones will have to wait until somebody ports Linux to -11 ;-)
+
+	  If you only intend to mount files from some other Unix over the
+	  network using NFS, you don't need the System V file system support
+	  (but you need NFS file system support obviously).
+
+	  Note that this option is generally not needed for floppies, since a
+	  good portable way to transport files and directories between unixes
+	  (and even other operating systems) is given by the tar program ("man
+	  tar" or preferably "info tar").  Note also that this option has
+	  nothing whatsoever to do with the option "System V IPC". Read about
+	  the System V file system in
+	  <file:Documentation/filesystems/sysv-fs.txt>.
+	  Saying Y here will enlarge your kernel by about 27 KB.
+
+	  To compile this as a module, choose M here: the module will be called
+	  sysv.
+
+	  If you haven't heard about all of this before, it's safe to say N.
+
+
+
+config UFS_FS
+	tristate "UFS file system support (read only)"
+	help
+	  BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
+	  OpenBSD and NeXTstep) use a file system called UFS. Some System V
+	  Unixes can create and mount hard disk partitions and diskettes using
+	  this file system as well. Saying Y here will allow you to read from
+	  these partitions; if you also want to write to them, say Y to the
+	  experimental "UFS file system write support", below. Please read the
+	  file <file:Documentation/filesystems/ufs.txt> for more information.
+
+          The recently released UFS2 variant (used in FreeBSD 5.x) is
+          READ-ONLY supported.
+
+	  If you only intend to mount files from some other Unix over the
+	  network using NFS, you don't need the UFS file system support (but
+	  you need NFS file system support obviously).
+
+	  Note that this option is generally not needed for floppies, since a
+	  good portable way to transport files and directories between unixes
+	  (and even other operating systems) is given by the tar program ("man
+	  tar" or preferably "info tar").
+
+	  When accessing NeXTstep files, you may need to convert them from the
+	  NeXT character set to the Latin1 character set; use the program
+	  recode ("info recode") for this purpose.
+
+	  To compile the UFS file system support as a module, choose M here: the
+	  module will be called ufs.
+
+	  If you haven't heard about all of this before, it's safe to say N.
+
+config UFS_FS_WRITE
+	bool "UFS file system write support (DANGEROUS)"
+	depends on UFS_FS && EXPERIMENTAL && BROKEN
+	help
+	  Say Y here if you want to try writing to UFS partitions. This is
+	  experimental, so you should back up your UFS partitions beforehand.
+
+endmenu
+
+menu "Network File Systems"
+	depends on NET
+
+config NFS_FS
+	tristate "NFS file system support"
+	depends on INET
+	select LOCKD
+	select SUNRPC
+	select NFS_ACL_SUPPORT if NFS_V3_ACL
+	help
+	  If you are connected to some other (usually local) Unix computer
+	  (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
+	  on that computer (the NFS server) using the Network File Sharing
+	  protocol, say Y. "Mounting files" means that the client can access
+	  the files with usual UNIX commands as if they were sitting on the
+	  client's hard disk. For this to work, the server must run the
+	  programs nfsd and mountd (but does not need to have NFS file system
+	  support enabled in its kernel). NFS is explained in the Network
+	  Administrator's Guide, available from
+	  <http://www.tldp.org/docs.html#guide>, on its man page: "man
+	  nfs", and in the NFS-HOWTO.
+
+	  A superior but less widely used alternative to NFS is provided by
+	  the Coda file system; see "Coda file system support" below.
+
+	  If you say Y here, you should have said Y to TCP/IP networking also.
+	  This option would enlarge your kernel by about 27 KB.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called nfs.
+
+	  If you are configuring a diskless machine which will mount its root
+	  file system over NFS at boot time, say Y here and to "Kernel
+	  level IP autoconfiguration" above and to "Root file system on NFS"
+	  below. You cannot compile this driver as a module in this case.
+	  There are two packages designed for booting diskless machines over
+	  the net: netboot, available from
+	  <http://ftp1.sourceforge.net/netboot/>, and Etherboot,
+	  available from <http://ftp1.sourceforge.net/etherboot/>.
+
+	  If you don't know what all this is about, say N.
+
+config NFS_V3
+	bool "Provide NFSv3 client support"
+	depends on NFS_FS
+	help
+	  Say Y here if you want your NFS client to be able to speak version
+	  3 of the NFS protocol.
+
+	  If unsure, say Y.
+
+config NFS_V3_ACL
+	bool "Provide client support for the NFSv3 ACL protocol extension"
+	depends on NFS_V3
+	help
+	  Implement the NFSv3 ACL protocol extension for manipulating POSIX
+	  Access Control Lists.  The server should also be compiled with
+	  the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.
+
+	  If unsure, say N.
+
+config NFS_V4
+	bool "Provide NFSv4 client support (EXPERIMENTAL)"
+	depends on NFS_FS && EXPERIMENTAL
+	select RPCSEC_GSS_KRB5
+	help
+	  Say Y here if you want your NFS client to be able to speak the newer
+	  version 4 of the NFS protocol.
+
+	  Note: Requires auxiliary userspace daemons which may be found on
+		http://www.citi.umich.edu/projects/nfsv4/
+
+	  If unsure, say N.
+
+config NFS_DIRECTIO
+	bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
+	depends on NFS_FS && EXPERIMENTAL
+	help
+	  This option enables applications to perform uncached I/O on files
+	  in NFS file systems using the O_DIRECT open() flag.  When O_DIRECT
+	  is set for a file, its data is not cached in the system's page
+	  cache.  Data is moved to and from user-level application buffers
+	  directly.  Unlike local disk-based file systems, NFS O_DIRECT has
+	  no alignment restrictions.
+
+	  Unless your program is designed to use O_DIRECT properly, you are
+	  much better off allowing the NFS client to manage data caching for
+	  you.  Misusing O_DIRECT can cause poor server performance or network
+	  storms.  This kernel build option defaults OFF to avoid exposing
+	  system administrators unwittingly to a potentially hazardous
+	  feature.
+
+	  For more details on NFS O_DIRECT, see fs/nfs/direct.c.
+
+	  If unsure, say N.  This reduces the size of the NFS client, and
+	  causes open() to return EINVAL if a file residing in NFS is
+	  opened with the O_DIRECT flag.
+
+config NFSD
+	tristate "NFS server support"
+	depends on INET
+	select LOCKD
+	select SUNRPC
+	select EXPORTFS
+	select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL
+	help
+	  If you want your Linux box to act as an NFS *server*, so that other
+	  computers on your local network which support NFS can access certain
+	  directories on your box transparently, you have two options: you can
+	  use the self-contained user space program nfsd, in which case you
+	  should say N here, or you can say Y and use the kernel based NFS
+	  server. The advantage of the kernel based solution is that it is
+	  faster.
+
+	  In either case, you will need support software; the respective
+	  locations are given in the file <file:Documentation/Changes> in the
+	  NFS section.
+
+	  If you say Y here, you will get support for version 2 of the NFS
+	  protocol (NFSv2). If you also want NFSv3, say Y to the next question
+	  as well.
+
+	  Please read the NFS-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile the NFS server support as a module, choose M here: the
+	  module will be called nfsd.  If unsure, say N.
+
+config NFSD_V2_ACL
+	bool
+	depends on NFSD
+
+config NFSD_V3
+	bool "Provide NFSv3 server support"
+	depends on NFSD
+	help
+	  If you would like to include the NFSv3 server as well as the NFSv2
+	  server, say Y here.  If unsure, say Y.
+
+config NFSD_V3_ACL
+	bool "Provide server support for the NFSv3 ACL protocol extension"
+	depends on NFSD_V3
+	select NFSD_V2_ACL
+	help
+	  Implement the NFSv3 ACL protocol extension for manipulating POSIX
+	  Access Control Lists on exported file systems. NFS clients should
+	  be compiled with the NFSv3 ACL protocol extension; see the
+	  CONFIG_NFS_V3_ACL option.  If unsure, say N.
+
+config NFSD_V4
+	bool "Provide NFSv4 server support (EXPERIMENTAL)"
+	depends on NFSD_V3 && EXPERIMENTAL
+	select NFSD_TCP
+	select CRYPTO_MD5
+	select CRYPTO
+	select FS_POSIX_ACL
+	help
+	  If you would like to include the NFSv4 server as well as the NFSv2
+	  and NFSv3 servers, say Y here.  This feature is experimental, and
+	  should only be used if you are interested in helping to test NFSv4.
+	  If unsure, say N.
+
+config NFSD_TCP
+	bool "Provide NFS server over TCP support"
+	depends on NFSD
+	default y
+	help
+	  If you want your NFS server to support TCP connections, say Y here.
+	  TCP connections usually perform better than the default UDP when
+	  the network is lossy or congested.  If unsure, say Y.
+
+config ROOT_NFS
+	bool "Root file system on NFS"
+	depends on NFS_FS=y && IP_PNP
+	help
+	  If you want your Linux box to mount its whole root file system (the
+	  one containing the directory /) from some other computer over the
+	  net via NFS (presumably because your box doesn't have a hard disk),
+	  say Y. Read <file:Documentation/nfsroot.txt> for details. It is
+	  likely that in this case, you also want to say Y to "Kernel level IP
+	  autoconfiguration" so that your box can discover its network address
+	  at boot time.
+
+	  Most people say N here.
+
+config LOCKD
+	tristate
+
+config LOCKD_V4
+	bool
+	depends on NFSD_V3 || NFS_V3
+	default y
+
+config EXPORTFS
+	tristate
+
+config NFS_ACL_SUPPORT
+	tristate
+	select FS_POSIX_ACL
+
+config NFS_COMMON
+	bool
+	depends on NFSD || NFS_FS
+	default y
+
+config SUNRPC
+	tristate
+
+config SUNRPC_GSS
+	tristate
+
+config RPCSEC_GSS_KRB5
+	tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
+	depends on SUNRPC && EXPERIMENTAL
+	select SUNRPC_GSS
+	select CRYPTO
+	select CRYPTO_MD5
+	select CRYPTO_DES
+	help
+	  Provides for secure RPC calls by means of a gss-api
+	  mechanism based on Kerberos V5. This is required for
+	  NFSv4.
+
+	  Note: Requires an auxiliary userspace daemon which may be found on
+		http://www.citi.umich.edu/projects/nfsv4/
+
+	  If unsure, say N.
+
+config RPCSEC_GSS_SPKM3
+	tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
+	depends on SUNRPC && EXPERIMENTAL
+	select SUNRPC_GSS
+	select CRYPTO
+	select CRYPTO_MD5
+	select CRYPTO_DES
+	help
+	  Provides for secure RPC calls by means of a gss-api
+	  mechanism based on the SPKM3 public-key mechanism.
+
+	  Note: Requires an auxiliary userspace daemon which may be found on
+	  	http://www.citi.umich.edu/projects/nfsv4/
+
+	  If unsure, say N.
+
+config SMB_FS
+	tristate "SMB file system support (to mount Windows shares etc.)"
+	depends on INET
+	select NLS
+	help
+	  SMB (Server Message Block) is the protocol Windows for Workgroups
+	  (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
+	  files and printers over local networks.  Saying Y here allows you to
+	  mount their file systems (often called "shares" in this context) and
+	  access them just like any other Unix directory.  Currently, this
+	  works only if the Windows machines use TCP/IP as the underlying
+	  transport protocol, and not NetBEUI.  For details, read
+	  <file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  Note: if you just want your box to act as an SMB *server* and make
+	  files and printing services available to Windows clients (which need
+	  to have a TCP/IP stack), you don't need to say Y here; you can use
+	  the program SAMBA (available from <ftp://ftp.samba.org/pub/samba/>)
+	  for that.
+
+	  General information about how to connect Linux, Windows machines and
+	  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
+
+	  To compile the SMB support as a module, choose M here: the module will
+	  be called smbfs.  Most people say N, however.
+
+config SMB_NLS_DEFAULT
+	bool "Use a default NLS"
+	depends on SMB_FS
+	help
+	  Enabling this will make smbfs use nls translations by default. You
+	  need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
+	  settings and you need to give the default nls for the SMB server as
+	  CONFIG_SMB_NLS_REMOTE.
+
+	  The nls settings can be changed at mount time, if your smbmount
+	  supports that, using the codepage and iocharset parameters.
+
+	  smbmount from samba 2.2.0 or later supports this.
+
+config SMB_NLS_REMOTE
+	string "Default Remote NLS Option"
+	depends on SMB_NLS_DEFAULT
+	default "cp437"
+	help
+	  This setting allows you to specify a default value for which
+	  codepage the server uses. If this field is left blank no
+	  translations will be done by default. The local codepage/charset
+	  default to CONFIG_NLS_DEFAULT.
+
+	  The nls settings can be changed at mount time, if your smbmount
+	  supports that, using the codepage and iocharset parameters.
+
+	  smbmount from samba 2.2.0 or later supports this.
+
+config CIFS
+	tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)"
+	depends on INET
+	select NLS
+	help
+	  This is the client VFS module for the Common Internet File System
+	  (CIFS) protocol which is the successor to the Server Message Block 
+	  (SMB) protocol, the native file sharing mechanism for most early
+	  PC operating systems.  The CIFS protocol is fully supported by 
+	  file servers such as Windows 2000 (including Windows 2003, NT 4  
+	  and Windows XP) as well by Samba (which provides excellent CIFS
+	  server support for Linux and many other operating systems). Limited
+	  support for Windows ME and similar servers is provided as well. 
+	  You must use the smbfs client filesystem to access older SMB servers
+	  such as OS/2 and DOS.
+
+	  The intent of the cifs module is to provide an advanced
+	  network file system client for mounting to CIFS compliant servers, 
+	  including support for dfs (hierarchical name space), secure per-user
+	  session establishment, safe distributed caching (oplock), optional
+	  packet signing, Unicode and other internationalization improvements, 
+	  and optional Winbind (nsswitch) integration. You do not need to enable
+	  cifs if running only a (Samba) server. It is possible to enable both
+	  smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003
+	  and Samba 3 servers, and smbfs for accessing old servers). If you need 
+	  to mount to Samba or Windows from this machine, say Y.
+
+config CIFS_STATS
+        bool "CIFS statistics"
+        depends on CIFS
+        help
+          Enabling this option will cause statistics for each server share
+	  mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
+
+config CIFS_STATS2
+	bool "CIFS extended statistics"
+	depends on CIFS_STATS
+	help
+	  Enabling this option will allow more detailed statistics on SMB
+	  request timing to be displayed in /proc/fs/cifs/DebugData and also
+	  allow optional logging of slow responses to dmesg (depending on the
+	  value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details).
+	  These additional statistics may have a minor effect on performance
+	  and memory utilization.
+
+	  Unless you are a developer or are doing network performance analysis
+	  or tuning, say N.
+
+config CIFS_XATTR
+        bool "CIFS extended attributes"
+        depends on CIFS
+        help
+          Extended attributes are name:value pairs associated with inodes by
+          the kernel or by users (see the attr(5) manual page, or visit
+          <http://acl.bestbits.at/> for details).  CIFS maps the name of
+          extended attributes beginning with the user namespace prefix
+          to SMB/CIFS EAs. EAs are stored on Windows servers without the
+          user namespace prefix, but their names are seen by Linux cifs clients
+          prefaced by the user namespace prefix. The system namespace
+          (used by some filesystems to store ACLs) is not supported at
+          this time.
+
+          If unsure, say N.
+
+config CIFS_POSIX
+        bool "CIFS POSIX Extensions"
+        depends on CIFS_XATTR
+        help
+          Enabling this option will cause the cifs client to attempt to
+	  negotiate a newer dialect with servers, such as Samba 3.0.5
+	  or later, that optionally can handle more POSIX like (rather
+	  than Windows like) file behavior.  It also enables
+	  support for POSIX ACLs (getfacl and setfacl) to servers
+	  (such as Samba 3.10 and later) which can negotiate
+	  CIFS POSIX ACL support.  If unsure, say N.
+
+config CIFS_EXPERIMENTAL
+	  bool "CIFS Experimental Features (EXPERIMENTAL)"
+	  depends on CIFS && EXPERIMENTAL
+	  help
+	    Enables cifs features under testing. These features are
+	    experimental and currently include support for writepages
+	    (multipage writebehind performance improvements) and directory
+	    change notification ie fcntl(F_DNOTIFY) as well as some security
+	    improvements.  Some also depend on setting at runtime the
+	    pseudo-file /proc/fs/cifs/Experimental (which is disabled by
+	    default). See the file fs/cifs/README for more details.
+
+	    If unsure, say N.
+
+config CIFS_UPCALL
+	  bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+	  depends on CIFS_EXPERIMENTAL
+	  select CONNECTOR
+	  help
+	    Enables an upcall mechanism for CIFS which will be used to contact
+	    userspace helper utilities to provide SPNEGO packaged Kerberos
+	    tickets which are needed to mount to certain secure servers
+	    (for which more secure Kerberos authentication is required). If
+	    unsure, say N.
+
+config NCP_FS
+	tristate "NCP file system support (to mount NetWare volumes)"
+	depends on IPX!=n || INET
+	help
+	  NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
+	  used by Novell NetWare clients to talk to file servers.  It is to
+	  IPX what NFS is to TCP/IP, if that helps.  Saying Y here allows you
+	  to mount NetWare file server volumes and to access them just like
+	  any other Unix directory.  For details, please read the file
+	  <file:Documentation/filesystems/ncpfs.txt> in the kernel source and
+	  the IPX-HOWTO from <http://www.tldp.org/docs.html#howto>.
+
+	  You do not have to say Y here if you want your Linux box to act as a
+	  file *server* for Novell NetWare clients.
+
+	  General information about how to connect Linux, Windows machines and
+	  Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
+
+	  To compile this as a module, choose M here: the module will be called
+	  ncpfs.  Say N unless you are connected to a Novell network.
+
+source "fs/ncpfs/Kconfig"
+
+config CODA_FS
+	tristate "Coda file system support (advanced network fs)"
+	depends on INET
+	help
+	  Coda is an advanced network file system, similar to NFS in that it
+	  enables you to mount file systems of a remote server and access them
+	  with regular Unix commands as if they were sitting on your hard
+	  disk.  Coda has several advantages over NFS: support for
+	  disconnected operation (e.g. for laptops), read/write server
+	  replication, security model for authentication and encryption,
+	  persistent client caches and write back caching.
+
+	  If you say Y here, your Linux box will be able to act as a Coda
+	  *client*.  You will need user level code as well, both for the
+	  client and server.  Servers are currently user level, i.e. they need
+	  no kernel support.  Please read
+	  <file:Documentation/filesystems/coda.txt> and check out the Coda
+	  home page <http://www.coda.cs.cmu.edu/>.
+
+	  To compile the coda client support as a module, choose M here: the
+	  module will be called coda.
+
+config CODA_FS_OLD_API
+	bool "Use 96-bit Coda file identifiers"
+	depends on CODA_FS
+	help
+	  A new kernel-userspace API had to be introduced for Coda v6.0
+	  to support larger 128-bit file identifiers as needed by the
+	  new realms implementation.
+
+	  However this new API is not backward compatible with older
+	  clients. If you really need to run the old Coda userspace
+	  cache manager then say Y.
+	  
+	  For most cases you probably want to say N.
+
+config AFS_FS
+# for fs/nls/Config.in
+	tristate "Andrew File System support (AFS) (Experimental)"
+	depends on INET && EXPERIMENTAL
+	select RXRPC
+	help
+	  If you say Y here, you will get an experimental Andrew File System
+	  driver. It currently only supports unsecured read-only AFS access.
+
+	  See <file:Documentation/filesystems/afs.txt> for more intormation.
+
+	  If unsure, say N.
+
+config RXRPC
+	tristate
+
+config 9P_FS
+	tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
+	depends on INET && EXPERIMENTAL
+	help
+	  If you say Y here, you will get experimental support for
+	  Plan 9 resource sharing via the 9P2000 protocol.
+
+	  See <http://v9fs.sf.net> for more information.
+
+	  If unsure, say N.
+
+endmenu
+
+menu "Partition Types"
+
+source "fs/partitions/Kconfig"
+
+endmenu
+
+source "fs/nls/Kconfig"
+
+endmenu
+
diff -urN oldtree/fs/Makefile newtree/fs/Makefile
--- oldtree/fs/Makefile	2006-02-18 17:12:40.745284968 +0000
+++ newtree/fs/Makefile	2006-02-18 17:24:58.711097112 +0000
@@ -66,6 +66,7 @@
 obj-$(CONFIG_ISO9660_FS)	+= isofs/
 obj-$(CONFIG_DEVFS_FS)		+= devfs/
 obj-$(CONFIG_HFSPLUS_FS)	+= hfsplus/ # Before hfs to find wrapped HFS+
+obj-$(CONFIG_ECRYPTFS)		+= ecryptfs/
 obj-$(CONFIG_HFS_FS)		+= hfs/
 obj-$(CONFIG_VXFS_FS)		+= freevxfs/
 obj-$(CONFIG_NFS_FS)		+= nfs/
diff -urN oldtree/fs/Makefile.orig newtree/fs/Makefile.orig
--- oldtree/fs/Makefile.orig	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/Makefile.orig	2006-02-18 17:24:58.712096960 +0000
@@ -0,0 +1,103 @@
+#
+# Makefile for the Linux filesystems.
+#
+# 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+# 
+
+obj-y :=	open.o read_write.o file_table.o buffer.o  bio.o super.o \
+		block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
+		ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
+		attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
+		seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
+		ioprio.o pnode.o
+
+obj-$(CONFIG_INOTIFY)		+= inotify.o
+obj-$(CONFIG_EPOLL)		+= eventpoll.o
+obj-$(CONFIG_COMPAT)		+= compat.o
+
+nfsd-$(CONFIG_NFSD)		:= nfsctl.o
+obj-y				+= $(nfsd-y) $(nfsd-m)
+
+obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
+obj-$(CONFIG_BINFMT_EM86)	+= binfmt_em86.o
+obj-$(CONFIG_BINFMT_MISC)	+= binfmt_misc.o
+
+# binfmt_script is always there
+obj-y				+= binfmt_script.o
+
+obj-$(CONFIG_BINFMT_ELF)	+= binfmt_elf.o
+obj-$(CONFIG_BINFMT_ELF_FDPIC)	+= binfmt_elf_fdpic.o
+obj-$(CONFIG_BINFMT_SOM)	+= binfmt_som.o
+obj-$(CONFIG_BINFMT_FLAT)	+= binfmt_flat.o
+
+obj-$(CONFIG_FS_MBCACHE)	+= mbcache.o
+obj-$(CONFIG_FS_POSIX_ACL)	+= posix_acl.o xattr_acl.o
+obj-$(CONFIG_NFS_COMMON)	+= nfs_common/
+
+obj-$(CONFIG_QUOTA)		+= dquot.o
+obj-$(CONFIG_QFMT_V1)		+= quota_v1.o
+obj-$(CONFIG_QFMT_V2)		+= quota_v2.o
+obj-$(CONFIG_QUOTACTL)		+= quota.o
+
+obj-$(CONFIG_DNOTIFY)		+= dnotify.o
+
+obj-$(CONFIG_PROC_FS)		+= proc/
+obj-y				+= partitions/
+obj-$(CONFIG_SYSFS)		+= sysfs/
+obj-y				+= devpts/
+
+obj-$(CONFIG_PROFILING)		+= dcookies.o
+ 
+# Do not add any filesystems before this line
+obj-$(CONFIG_REISERFS_FS)	+= reiserfs/
+obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3
+obj-$(CONFIG_JBD)		+= jbd/
+obj-$(CONFIG_EXT2_FS)		+= ext2/
+obj-$(CONFIG_CRAMFS)		+= cramfs/
+obj-$(CONFIG_RAMFS)		+= ramfs/
+obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
+obj-$(CONFIG_CODA_FS)		+= coda/
+obj-$(CONFIG_MINIX_FS)		+= minix/
+obj-$(CONFIG_FAT_FS)		+= fat/
+obj-$(CONFIG_MSDOS_FS)		+= msdos/
+obj-$(CONFIG_VFAT_FS)		+= vfat/
+obj-$(CONFIG_BFS_FS)		+= bfs/
+obj-$(CONFIG_ISO9660_FS)	+= isofs/
+obj-$(CONFIG_DEVFS_FS)		+= devfs/
+obj-$(CONFIG_HFSPLUS_FS)	+= hfsplus/ # Before hfs to find wrapped HFS+
+obj-$(CONFIG_HFS_FS)		+= hfs/
+obj-$(CONFIG_VXFS_FS)		+= freevxfs/
+obj-$(CONFIG_NFS_FS)		+= nfs/
+obj-$(CONFIG_EXPORTFS)		+= exportfs/
+obj-$(CONFIG_NFSD)		+= nfsd/
+obj-$(CONFIG_LOCKD)		+= lockd/
+obj-$(CONFIG_NLS)		+= nls/
+obj-$(CONFIG_SYSV_FS)		+= sysv/
+obj-$(CONFIG_SMB_FS)		+= smbfs/
+obj-$(CONFIG_CIFS)		+= cifs/
+obj-$(CONFIG_NCP_FS)		+= ncpfs/
+obj-$(CONFIG_HPFS_FS)		+= hpfs/
+obj-$(CONFIG_NTFS_FS)		+= ntfs/
+obj-$(CONFIG_UFS_FS)		+= ufs/
+obj-$(CONFIG_EFS_FS)		+= efs/
+obj-$(CONFIG_JFFS_FS)		+= jffs/
+obj-$(CONFIG_JFFS2_FS)		+= jffs2/
+obj-$(CONFIG_AFFS_FS)		+= affs/
+obj-$(CONFIG_ROMFS_FS)		+= romfs/
+obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
+obj-$(CONFIG_AUTOFS_FS)		+= autofs/
+obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
+obj-$(CONFIG_ADFS_FS)		+= adfs/
+obj-$(CONFIG_FUSE_FS)		+= fuse/
+obj-$(CONFIG_UDF_FS)		+= udf/
+obj-$(CONFIG_RELAYFS_FS)	+= relayfs/
+obj-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs/
+obj-$(CONFIG_JFS_FS)		+= jfs/
+obj-$(CONFIG_XFS_FS)		+= xfs/
+obj-$(CONFIG_9P_FS)		+= 9p/
+obj-$(CONFIG_AFS_FS)		+= afs/
+obj-$(CONFIG_BEFS_FS)		+= befs/
+obj-$(CONFIG_HOSTFS)		+= hostfs/
+obj-$(CONFIG_HPPFS)		+= hppfs/
+obj-$(CONFIG_DEBUG_FS)		+= debugfs/
diff -urN oldtree/fs/ecryptfs/Makefile newtree/fs/ecryptfs/Makefile
--- oldtree/fs/ecryptfs/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/Makefile	2006-02-18 17:24:58.713096808 +0000
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux 2.6 eCryptfs
+#
+
+obj-$(CONFIG_ECRYPTFS) += ecryptfs.o
+
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o
diff -urN oldtree/fs/ecryptfs/crypto.c newtree/fs/ecryptfs/crypto.c
--- oldtree/fs/ecryptfs/crypto.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/crypto.c	2006-02-18 17:24:58.715096504 +0000
@@ -0,0 +1,955 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 2001-2004 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *   		Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/key.h>
+#include <linux/namei.h>
+#include <linux/crypto.h>
+#include <linux/file.h>
+#include <asm/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * Requirement:
+ *	Size of dst buffer needs to be atleast src_size * 2
+ */
+inline void ecryptfs_to_hex(char *dst, char *src, int src_size)
+{
+	int x;
+
+	for (x = 0; x < src_size; x++)
+		sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
+}
+
+/**
+ * Requirement:
+ * 	Size of src buffer needs to be atleast twice that of dst_size
+ */
+inline void ecryptfs_from_hex(char *dst, char *src, int dst_size)
+{
+	int x;
+	char tmp[3] = { 0, };
+
+	for (x = 0; x < dst_size; x++) {
+		tmp[0] = src[x * 2];
+		tmp[1] = src[x * 2 + 1];
+		dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);
+	}
+}
+
+static int iv_mixer;
+
+/**
+ * Rotate the initialization vector for an extent.  This stirs things
+ * up to help protect against linear cryptanalysis when an attacker
+ * may have access to several encryptions based on the same IV.
+ */
+void ecryptfs_rotate_iv(unsigned char *iv)
+{
+	int i = (ECRYPTFS_MAX_IV_BYTES - sizeof(iv_mixer));
+	int zero_test = 0;
+
+	while ((i -= sizeof(iv_mixer)) >= 0)
+		zero_test |= ((*((int *)(iv + i))) ^=
+			      (iv_mixer *= (*(int *)(iv + i))));
+	while (unlikely(!zero_test)) {
+		get_random_bytes(iv, ECRYPTFS_MAX_IV_BYTES);
+		zero_test = 0;
+		i = ECRYPTFS_MAX_IV_BYTES / sizeof(int);
+		while (i--)
+			zero_test |= *((int *)(iv + i));
+	}
+}
+
+/**
+ * Initialize the crypt_stats structure.  This involves setting an
+ * initial IV, indicating how many header pages we have on the file by
+ * default, initializing the list of raw authentication token packets
+ * (TODO: deprecated/replaced w/ auth_tok sigs pointing to keyring
+ * structures), setting the extent size (TODO: this is the page size;
+ * as it now stands, everything falls apart if the page size is
+ * anything but 4096), and finally setting a flag to indicate that the
+ * structure is initialized.
+ *
+ * @param crypt_stats Pointer to the crypt_stats struct to
+ *                    initialize.
+ */
+void ecryptfs_init_crypt_stats(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	memset((void *)crypt_stats, 0, sizeof(struct ecryptfs_crypt_stats));
+	init_MUTEX(&crypt_stats->iv_sem);
+	down(&crypt_stats->iv_sem);
+	get_random_bytes(&crypt_stats->iv, ECRYPTFS_MAX_IV_BYTES);
+	up(&crypt_stats->iv_sem);
+	get_random_bytes(&iv_mixer, sizeof(iv_mixer));
+	crypt_stats->num_header_pages = 1;	/* TODO: Remove with policy */
+	crypt_stats->struct_initialized = 1;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Releases all memory associated with a crypt_stats struct.
+ */
+void ecryptfs_destruct_crypt_stats(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (crypt_stats->tfm) {
+		crypto_free_tfm(crypt_stats->tfm);
+		crypt_stats->tfm = NULL;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Dump hexadecimal representation of char array
+ *
+ * @param data
+ * @param bytes
+ */
+void ecryptfs_dump_hex(char *data, int bytes)
+{
+	int i = 0;
+	int pretty_print = 1;
+
+	if (bytes != 0) {
+		printk(KERN_NOTICE "0x%.2x.", (unsigned char)data[i]);
+		i++;
+	}
+	while (i < bytes) {
+		printk("0x%.2x.", (unsigned char)data[i]);
+		i++;
+		if (i % 16 == 0) {
+			printk("\n");
+			pretty_print = 0;
+		} else
+			pretty_print = 1;
+	}
+	if (pretty_print)
+		printk("\n");
+}
+
+/**
+ * Fills in a scatterlist array with page references for a passed
+ * virtual address: James Morris
+ *
+ * @param addr Virtual address
+ * @param size Size of data; should be an even multiple of the block
+ *             size
+ * @param sg Pointer to scatterlist array
+ * @param sg_size Max array size
+ * @return Number of scatterlist structs in array used
+ */
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+			int sg_size)
+{
+	int i = 0;
+	struct page *pg;
+	int offset;
+	int remainder_of_page;
+
+	while (size > 0 && i < sg_size) {
+		pg = virt_to_page(addr);
+		offset = offset_in_page(addr);
+		sg[i].page = pg;
+		sg[i].offset = offset;
+		remainder_of_page = PAGE_CACHE_SIZE - offset;
+		if (size >= remainder_of_page) {
+			sg[i].length = remainder_of_page;
+			addr += remainder_of_page;
+			size -= remainder_of_page;
+		} else {
+			sg[i].length = size;
+			addr += size;
+			size = 0;
+		}
+		i++;
+	}
+	if (size > 0)
+		return -ENOMEM;
+	return i;
+}
+
+/**
+ * @return Number of bytes encrypted; negative value on error
+ */
+static int do_encrypt_scatterlist(struct ecryptfs_crypt_stats *crypt_stats,
+				  struct scatterlist *dest_sg,
+				  struct scatterlist *src_sg, int size,
+				  unsigned char *iv)
+{
+	int rc = 0;
+
+	if (!crypt_stats || !crypt_stats->tfm
+	    || !crypt_stats->struct_initialized) {
+		ecryptfs_printk(0, KERN_ERR,
+				"Called w/ invalid crypt_stats state\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Key size [%d]; key:\n",
+			crypt_stats->key_size_bits / 8);
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	rc = crypto_cipher_setkey(crypt_stats->tfm, crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error setting key; rc = [%d]\n",
+				rc);
+		rc = -EINVAL;
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Encrypting [%d] bytes.\n", size);
+	if (crypt_stats->tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB) {
+		crypt_stats->security_warning = 1;
+		crypto_cipher_encrypt(crypt_stats->tfm, dest_sg, src_sg, size);
+	} else if (crypt_stats->tfm->crt_cipher.cit_mode
+		   == CRYPTO_TFM_MODE_CFB
+		   || crypt_stats->tfm->crt_cipher.cit_mode
+		   == CRYPTO_TFM_MODE_CBC)
+		crypto_cipher_encrypt_iv(crypt_stats->tfm, dest_sg, src_sg,
+					 size, iv);
+	else {
+		ecryptfs_printk(0, KERN_ERR,
+				"Unsupported block cipher mode: [%d]\n",
+				crypt_stats->tfm->crt_cipher.cit_mode);
+		rc = -ENOSYS;
+		goto out;
+	}
+	rc = size;
+	/* TODO: crypt_stats->iv size must be equal to the block size;
+	 * verify this*/
+out:
+	return rc;
+}
+
+int do_encrypt_page_offset(struct ecryptfs_crypt_stats *crypt_stats,
+			   struct page *dest_page, int dest_offset,
+			   struct page *src_page, int src_offset, int size,
+			   unsigned char *iv)
+{
+	struct scatterlist src_sg[2], dest_sg[2];
+
+	ecryptfs_printk(1, KERN_NOTICE, "Called with dest_page->index = [%lu], "
+			"src_page->index = [%lu], dest_offset = [%d], "
+			"src_offset = [%d]\n", dest_page->index,
+			src_page->index, dest_offset, src_offset);
+	src_sg[0].page = src_page;
+	src_sg[0].offset = src_offset;
+	src_sg[0].length = size;
+	dest_sg[0].page = dest_page;
+	dest_sg[0].offset = dest_offset;
+	dest_sg[0].length = size;
+	return do_encrypt_scatterlist(crypt_stats, dest_sg, src_sg, size, iv);;
+}
+
+int
+do_encrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+		struct page *dest_page, struct page *src_page,
+		unsigned char *iv)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Called with dest_page->index = [%lu] "
+			"and src_page->index = [%lu]\n", dest_page->index,
+			src_page->index);
+	return do_encrypt_page_offset(crypt_stats, dest_page, 0, src_page, 0,
+				      PAGE_CACHE_SIZE, iv);
+}
+
+/**
+ * Encrypt from a virtual address to a virtual address.
+ * 
+ * @return 
+ */
+int do_encrypt_virt(struct ecryptfs_crypt_stats *crypt_stats,
+		    char *dest_virt_addr, const char *src_virt_addr,
+		    int size, unsigned char *iv)
+{
+	/* TODO: 32 is a magic number */
+	struct scatterlist src_sg[32];
+	struct scatterlist dest_sg[32];
+	int rc;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Source:\n");
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex((char *)src_virt_addr, size);
+	rc = virt_to_scatterlist(src_virt_addr, size, src_sg, 32);
+	if (rc == -ENOMEM) {
+		ecryptfs_printk(0, KERN_ERR, "do_encrypt_virt: No memory for "
+				"this operation\n");
+		goto out;
+
+	}
+	rc = virt_to_scatterlist(dest_virt_addr, size, dest_sg, 32);
+	if (rc == -ENOMEM) {
+		ecryptfs_printk(0, KERN_ERR, "do_encrypt_virt: No memory for "
+				"this operation\n");
+		goto out;
+	}
+	rc = do_encrypt_scatterlist(crypt_stats, dest_sg, src_sg, size, iv);
+	ecryptfs_printk(1, KERN_NOTICE, "Destination:\n");
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex((char *)dest_virt_addr, size);
+out:
+	return rc;
+}
+
+/**
+ * @return Number of bytes decrypted; negative value on error
+ */
+static int do_decrypt_scatterlist(struct ecryptfs_crypt_stats *crypt_stats,
+				  struct scatterlist *dest_sg,
+				  struct scatterlist *src_sg, int size,
+				  unsigned char *iv)
+{
+	int rc = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	/* TODO: This should be done when the file is opened */
+	ecryptfs_printk(1, KERN_NOTICE, "Key size [%d]; key:\n",
+			crypt_stats->key_size_bits / 8);
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex(crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	rc = crypto_cipher_setkey(crypt_stats->tfm, crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error setting key; rc = [%d]\n",
+				rc);
+		rc = -EINVAL;
+		goto out;
+	}	
+	ecryptfs_printk(1, KERN_NOTICE, "Decrypting [%d] bytes.\n", size);
+	if (crypt_stats->tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB) {
+		rc = crypto_cipher_decrypt(crypt_stats->tfm, dest_sg, src_sg, 
+					   size);
+		
+	} else if (crypt_stats->tfm->crt_cipher.cit_mode
+		   == CRYPTO_TFM_MODE_CFB
+		   || crypt_stats->tfm->crt_cipher.cit_mode
+		   == CRYPTO_TFM_MODE_CBC) {
+		rc = crypto_cipher_decrypt_iv(crypt_stats->tfm, dest_sg, src_sg,
+					      size, iv);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR, "Error decrypting; rc = "
+					"[%d]\n", rc);
+			goto out;
+		}
+	} else {
+		ecryptfs_printk(0, KERN_ERR,
+				"Unsupported block cipher mode: [%d]\n",
+				crypt_stats->tfm->crt_cipher.cit_mode);
+		rc = -ENOSYS;
+		goto out;
+	}
+	rc = size;
+ out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * @return Number of bytes decrypted
+ */
+int do_decrypt_page_offset(struct ecryptfs_crypt_stats *crypt_stats,
+			   struct page *dest_page, int dest_offset,
+			   struct page *src_page, int src_offset, int size,
+			   unsigned char *iv)
+{
+	struct scatterlist src_sg[2], dest_sg[2];
+
+	src_sg[0].page = src_page;
+	src_sg[0].offset = src_offset;
+	src_sg[0].length = size;
+	dest_sg[0].page = dest_page;
+	dest_sg[0].offset = dest_offset;
+	dest_sg[0].length = size;
+	return do_decrypt_scatterlist(crypt_stats, dest_sg, src_sg, size, iv);;
+}
+
+int
+do_decrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+		struct page *dest_page, struct page *src_page,
+		unsigned char *iv)
+{
+	return do_decrypt_page_offset(crypt_stats, dest_page, 0, src_page, 0,
+				      PAGE_CACHE_SIZE, iv);
+}
+
+#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
+
+int do_decrypt_virt(struct ecryptfs_crypt_stats *crypt_stats,
+		    char *dest_virt_addr, const char *src_virt_addr,
+		    int size, unsigned char *iv)
+{
+	struct scatterlist src_sg[ECRYPTFS_MAX_SCATTERLIST_LEN];
+	struct scatterlist dest_sg[ECRYPTFS_MAX_SCATTERLIST_LEN];
+	int rc;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Source:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((char *)src_virt_addr, size);
+	rc = virt_to_scatterlist(src_virt_addr, size, src_sg,
+				 ECRYPTFS_MAX_SCATTERLIST_LEN);
+	if (rc == -ENOMEM) {
+		ecryptfs_printk(0, KERN_ERR, "do_decrypt_virt: No memory for "
+				"this operation\n");
+		goto out;
+
+	}
+	rc = virt_to_scatterlist(dest_virt_addr, size, dest_sg,
+				 ECRYPTFS_MAX_SCATTERLIST_LEN);
+	if (rc == -ENOMEM) {
+		ecryptfs_printk(0, KERN_ERR, "do_decrypt_virt: No memory for "
+				"this operation\n");
+		goto out;
+	}
+	rc = do_decrypt_scatterlist(crypt_stats, dest_sg, src_sg, size, iv);
+	ecryptfs_printk(1, KERN_NOTICE, "Destination:\n");
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex((char *)dest_virt_addr, size);
+out:
+	return rc;
+}
+
+/**
+ * Initialize the crypto context
+ *
+ * TODO: Performance: Keep a cache of initialized cipher contexts;
+ * only init if needed
+ */
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int rc = -EINVAL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (crypt_stats->cipher == NULL) {
+		ecryptfs_printk(1, KERN_NOTICE, "No cipher specified\n");
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Initializing cipher [%s]; strlen = [%d]\n",
+			crypt_stats->cipher, (int)strlen(crypt_stats->cipher));
+	if (crypt_stats->tfm != NULL) {
+		ecryptfs_printk(1, KERN_WARNING, "Crypto context already "
+				"initialized\n");
+		goto out;
+	}
+	crypt_stats->tfm = crypto_alloc_tfm(crypt_stats->cipher,
+					    CRYPTO_TFM_MODE_CBC);
+	if (crypt_stats->tfm == NULL) {
+		ecryptfs_printk(0, KERN_ERR, "cryptfs: init_crypt_ctx(): Error "
+				"initializing cipher [%s]\n",
+				crypt_stats->cipher);
+		goto out;
+	}
+	rc = 0;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static inline pgoff_t records_per_page(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	return (crypt_stats->extent_size / crypt_stats->iv_bytes);
+}
+
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	/* Default values; may be overwritten as we are parsing the
+	 * packets. */
+	crypt_stats->extent_size = PAGE_SIZE;
+	crypt_stats->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
+	crypt_stats->records_per_page = records_per_page(crypt_stats);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Default values in the event that policy does not override them.
+ */
+static void
+ecryptfs_set_default_crypt_stats_vals(struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int key_size_bits = ECRYPTFS_DEFAULT_KEY_BYTES * 8;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	strcpy(crypt_stats->cipher, ECRYPTFS_DEFAULT_CIPHER);
+	get_random_bytes(crypt_stats->key, key_size_bits / 8);
+	crypt_stats->key_size_bits = key_size_bits;
+	crypt_stats->key_valid = 1;
+	ecryptfs_printk(1, KERN_NOTICE, "Generated new session key:\n");
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex(crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	ecryptfs_set_default_sizes(crypt_stats);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * If the crypto context for the file has not yet been established,
+ * this is where we do that.  Establishing a new crypto context
+ * involves the following decisions:
+ *  - What cipher to use?
+ *  - What set of authentication tokens to use?
+ * Here we just worry about getting enough information into the
+ * authentication tokens so that we know that they are available.
+ * We associate the available authentication tokens with the new file
+ * via the set of signatures in the crypt_stats struct.  Later, when
+ * the headers are actually written out, we may again defer to
+ * userspace to perform the encryption of the session key; for the
+ * foreseeable future, this will be the case with public key packets.
+ *
+ * @param ecryptfs_dentry
+ * @return Zero on success; non-zero otherwise
+ */
+/* Associate an authentication token(s) with the file */
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stats *crypt_stats =
+	    &ECRYPTFS_INODE_TO_PRIVATE(ecryptfs_dentry->d_inode)->crypt_stats;
+	struct ecryptfs_mount_crypt_stats *mount_crypt_stats =
+	    &(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(
+		      ecryptfs_dentry->d_sb)->mount_crypt_stats);
+	int cipher_name_len;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	ecryptfs_set_default_crypt_stats_vals(crypt_stats);
+	/* See if there are mount crypt options */
+	if (mount_crypt_stats->global_auth_tok) {
+		ecryptfs_printk(1, KERN_NOTICE, "Initializing context for new "
+				"file using mount_crypt_stats\n");
+		crypt_stats->encrypted = 1;
+		crypt_stats->key_valid = 1;
+		memcpy(crypt_stats->keysigs[crypt_stats->num_keysigs++],
+		       mount_crypt_stats->global_auth_tok_sig,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		cipher_name_len =
+		    strlen(mount_crypt_stats->global_default_cipher_name);
+		memcpy(crypt_stats->cipher,
+		       mount_crypt_stats->global_default_cipher_name,
+		       cipher_name_len);
+		crypt_stats->cipher[cipher_name_len] = '\0';
+	} else
+		/* We should not encounter this scenario since we
+		 * should detect lack of global_auth_tok at mount time
+		 * TODO: Applies to 0.1 release only; remember to
+		 * remove in future release */
+		BUG();
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * @return One if marker found; zero if not found
+ */
+int contains_ecryptfs_marker(char *data)
+{
+	u32 m_1, m_2, ver;
+	
+	memcpy(&m_1, data, 4);
+	memcpy(&m_2, (data + 4), 4);
+	ver = (m_2 ^ (m_1 ^ MAGIC_ECRYPTFS_MARKER));
+	/* There is a 2^(32-4) chance for each file that a
+	 * non-eCryptfs file will be start to be mistaken for an
+	 * eCryptfs file */
+	if (ver > 15)
+		ver = 0;
+	return (int)ver;
+}
+
+/**
+ * Marker = 0x3c81b7f5
+ */
+static int write_ecryptfs_marker(char *page_virt)
+{
+	u32 m_1, m_2, ver;
+	int version = 1;
+
+	ver = (u32)version;
+	get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	m_2 = ((m_1 ^ ver) ^ MAGIC_ECRYPTFS_MARKER);
+	memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2,
+	       (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	return MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+}
+
+/**
+ * @return Zero on no match
+ */
+u16 ecryptfs_code_for_cipher_string(char *str)
+{
+	u16 rc = 0;
+	if (strcmp(str, "des3_ede") == 0) {
+		rc = 0x02;
+	} else if (strcmp(str, "cast5") == 0) {
+		rc = 0x03;
+	} else if (strcmp(str, "blowfish") == 0) {
+		rc = 0x04;
+	} else if (strcmp(str, "aes") == 0) {
+		rc = 0x07;
+	}
+	return rc;
+}
+
+/**
+ * @return Zero on success
+ */
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+{
+	int rc = 0;
+	switch(cipher_code) {
+	case 0x01:
+		/* IDEA not supported */
+		str[0] = '\0';
+		ecryptfs_printk(0, KERN_WARNING, "Cipher code not supported: "
+				"[%d]\n", cipher_code);
+		rc = -ENOSYS;
+		break;
+	case 0x02:
+		/* Choose Triple-DES */
+		strcpy(str, "des3_ede");
+		break;
+	case 0x03:
+		/* Choose CAST5 */
+		strcpy(str, "cast5");
+		break;
+	case 0x04:
+		/* Choose blowfish */
+		strcpy(str, "blowfish");
+		break;
+	case 0x07:
+		/* Choose AES-128 */
+		strcpy(str, "aes");
+		break;
+	case 0x08:
+		/* Choose AES-192 */
+		strcpy(str, "aes");
+		break;
+	case 0x09:
+		/* Choose AES-256 */
+		strcpy(str, "aes");
+		break;
+	default:
+		str[0] = '\0';
+		ecryptfs_printk(0, KERN_WARNING, "Cipher code not recognized: "
+				"[%d]\n", cipher_code);		
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+/**
+ * @return Zero on success; non-zero otherwise
+ */
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	int rc = 0;
+	struct vfsmount *mnt = NULL;
+	struct file *file = NULL;
+	mm_segment_t oldfs;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	mnt = mntget(nd->mnt);
+	file = dentry_open(dentry, mnt, O_RDONLY);
+	if (IS_ERR(file)) {
+		ecryptfs_printk(1, KERN_NOTICE, "Error opening file to "
+				"determine interpolated filesize\n");
+		mntput(mnt);
+		rc = PTR_ERR(file);
+		goto out;
+	}
+	if (!file || !file->f_op || !file->f_op->read) {
+		ecryptfs_printk(1, KERN_NOTICE, "File has no read op\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	rc = file->f_op->read(file, (char __user *)data,
+			      PAGE_CACHE_SIZE, &file->f_pos);
+	set_fs(oldfs);
+	fput(file);
+	rc = 0;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n",rc);
+	return rc;
+}
+
+kmem_cache_t *ecryptfs_header_cache_0;
+kmem_cache_t *ecryptfs_header_cache_1;
+kmem_cache_t *ecryptfs_header_cache_2;
+
+/**
+ * The file size is written along a different execution path than the
+ * rest of the headers; we treat it as a special case in eCryptfs.
+ *
+ * Proposed header format is in flux; this is the current proposal for
+ * later versions of eCryptfs, for compatibility:
+ *
+ * BYTE RANGE: DESCRIPTION
+ * -----------------------
+ * 00 - 07: File size
+ * 08 - 11: Random value (M_1)
+ * 12 - 15: M_1 ^ VER ^ MARKER
+ * 16 - 16: Hash identifier
+ * 17 - 18: Cipher identifier
+ * 19 - 19: Number of header pages
+ * 20 - 63: Reserved
+ * 64 - ..: RFC2440 packet set
+ *
+ * @return Zero on success
+ */
+int ecryptfs_write_headers_virt(char *page_virt, 
+				struct ecryptfs_crypt_stats *crypt_stats,
+				struct dentry *ecryptfs_dentry, int version)
+{
+	int ecryptfs_marker_len;
+	int rc = 0;
+	int written;
+	int offset;
+
+	offset = ECRYPTFS_FILE_SIZE_BYTES;
+	ecryptfs_marker_len = write_ecryptfs_marker(page_virt + offset);
+	offset += ecryptfs_marker_len;
+	rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stats,
+					      ecryptfs_dentry, &written);
+	if (rc)
+		ecryptfs_printk(0, KERN_WARNING, "Error generating key packet "
+				"set; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Write the file headers out.  This will likely involve a userspace
+ * callout, in which the session key is encrypted with one or more
+ * public keys and/or the passphrase necessary to do the encryption is
+ * retrieved via a prompt.  Exactly what happens at this point should
+ * be policy-dependent.
+ *
+ * @param lower_file The lower file struct, which was returned from
+ * dentry_open
+ * @return Zero on success; non-zero on error
+ */
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+			   struct file *lower_file)
+{
+	int rc = 0;
+	char *page_virt;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	mm_segment_t oldfs;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	crypt_stats = &ECRYPTFS_INODE_TO_PRIVATE(
+		ecryptfs_dentry->d_inode)->crypt_stats;
+	if (likely(1 == crypt_stats->encrypted)) {
+		if (!crypt_stats->key_valid) {
+			ecryptfs_printk(1, KERN_NOTICE, "Key is "
+					"invalid; bailing out\n");
+			rc = -EINVAL;
+			goto out;
+		}
+	} else {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_WARNING,
+				"Called with crypt_stats->encrypted == 0\n");
+		goto out;
+	}
+	/* Released in this function */
+	page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER);
+	if (!page_virt) {
+		ecryptfs_printk(0, KERN_ERR, "Out of memory\n");
+		return -ENOMEM;
+	}
+	rc = ecryptfs_write_headers_virt(page_virt, crypt_stats, 
+					 ecryptfs_dentry, 
+					 ECRYPTFS_FILE_VERSION);
+	if (unlikely(rc != 0)) {
+		ecryptfs_printk(0, KERN_ERR, "Error whilst writing headers\n");
+		goto out_free;
+	}
+	rc = 0;
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Writing key packet set to underlying file\n");
+	lower_file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	lower_file->f_op->write(lower_file, (char __user *)page_virt,
+				PAGE_CACHE_SIZE, &lower_file->f_pos);
+	set_fs(oldfs);
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Done writing key packet set to underlying file.\n");
+out_free:
+	kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * @return Zero on success
+ */
+int ecryptfs_read_headers_virt(char *page_virt,
+			       struct ecryptfs_crypt_stats* crypt_stats,
+			       struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	int offset;
+	int version;
+
+	offset = ECRYPTFS_FILE_SIZE_BYTES;
+	version = contains_ecryptfs_marker(page_virt + offset);
+	if (version == 0)
+		ecryptfs_printk(0, KERN_WARNING, "Valid eCryptfs marker not "
+				"found\n");
+	offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+	rc = ecryptfs_parse_packet_set((page_virt + offset), crypt_stats,
+				       ecryptfs_dentry, version);
+	return rc;
+}
+
+/**
+ * @return	Zero if valid headers found and parsed; non-zero otherwise
+ */
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+			  struct file *lower_file)
+{
+	int rc = 0;
+	char *page_virt;
+	mm_segment_t oldfs;
+	ssize_t bytes_read;
+	struct ecryptfs_crypt_stats *crypt_stats =
+	    &ECRYPTFS_INODE_TO_PRIVATE(ecryptfs_dentry->d_inode)->crypt_stats;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	/* Read the first page from the underlying file */
+	page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER);
+	if (!page_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Unable to allocate page_virt\n");
+		goto out;
+	}
+	lower_file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	bytes_read =
+	    lower_file->f_op->read(lower_file, (char __user *)page_virt,
+				   PAGE_CACHE_SIZE, &lower_file->f_pos);
+	set_fs(oldfs);
+	if (bytes_read != PAGE_CACHE_SIZE) {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "Expected size of header not read."
+				"Instead [%d] bytes were read\n", bytes_read);
+		goto out;
+	}
+	rc = ecryptfs_read_headers_virt(page_virt, crypt_stats,
+					ecryptfs_dentry);
+	kmem_cache_free(ecryptfs_header_cache_1, page_virt);
+	if (rc) {
+		ecryptfs_printk(1, KERN_NOTICE, "File not encrypted\n");
+		rc = -EINVAL;
+		goto out;
+	}
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * N.B. The concept of encoded filenames does not apply for 0.1 release
+ *
+ * Encrypts and encodes a filename into something that constitutes a
+ * valid filename for a filesystem, with printable characters.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stats->tfm.
+ *
+ * TODO: Implement filename encryption and encoding here, in place of
+ * memcpy.
+ *
+ * @return	Length of encoded filename; negative if error
+ */
+int
+ecryptfs_encode_filename(const char *name, int length, char **encoded_name,
+			 int skip_dots,
+			 struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int error = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; length = [%d]\n", length);
+	(*encoded_name) = kmalloc(length + 2, GFP_KERNEL);
+	if (!(*encoded_name)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	memcpy((void *)(*encoded_name), (void *)name, length);
+	(*encoded_name)[length] = '\0';
+	error = length + 1;
+      out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; error = [%d]\n", error);
+	return error;
+}
+
+/**
+ * N.B. The concept of encoded filenames does not apply for 0.1 release
+ *
+ * Decrypts and decodes the filename
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy.
+ *
+ * @return	Length of decoded filename; negative if error
+ */
+int
+ecryptfs_decode_filename(const char *name, int length, char **decrypted_name,
+			 int skip_dots,
+			 struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int error = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; length = [%d]\n", length);
+	(*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);
+	if (!(*decrypted_name)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	memcpy((void *)(*decrypted_name), (void *)name, length);
+	(*decrypted_name)[length + 1] = '\0';	/* Only for convenience
+						 * in printing out the
+						 * string in debug
+						 * messages */
+	error = length;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; error = [%d]\n", error);
+	return error;
+}
diff -urN oldtree/fs/ecryptfs/dentry.c newtree/fs/ecryptfs/dentry.c
--- oldtree/fs/ecryptfs/dentry.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/dentry.c	2006-02-18 17:24:58.716096352 +0000
@@ -0,0 +1,105 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2003 Erez Zadok
+ * Copyright (c) 2001-2003 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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/dcache.h>
+#include <linux/namei.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * called when the VFS needs to revalidate a dentry. This
+ * is called whenever a name lookup finds a dentry in the
+ * dcache. Most filesystems leave this as NULL, because all their
+ * dentries in the dcache are valid.
+ *
+ *
+ * @param dentry	ecryptfs dentry
+ * @param nd		
+ * @return 		1 if valid, 0 otherwise
+ */
+static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+	int err = 1;
+	struct dentry *lower_dentry;
+	struct dentry *saved_dentry;
+	struct vfsmount *saved_vfsmount;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name.name = [%s]\n",
+			dentry->d_name.name);
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	if (!lower_dentry) {
+		err = 0;
+		goto out;
+	}
+	if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
+		goto out;
+	/* Call the lower dentry's d_revalidate (assuming it has one) */
+	saved_dentry = nd->dentry;
+	saved_vfsmount = nd->mnt;
+	nd->dentry = lower_dentry;
+	nd->mnt = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(dentry->d_sb)->lower_mnt;
+	err = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
+	nd->dentry = saved_dentry;
+	nd->mnt = saved_vfsmount;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+kmem_cache_t *ecryptfs_dentry_info_cache;
+
+/* Notes:
+ * Called when a dentry is really deallocated
+ * Sanity check? wrapper around ecryptfs_dput()
+ */
+static void ecryptfs_d_release(struct dentry *dentry)
+{
+	struct dentry *lower_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name->name = [%s]\n",
+			dentry->d_name.name);
+	if (!dentry) {
+		ecryptfs_printk(0, KERN_ERR, "NULL dentry\n");
+		goto out;
+	}
+	if (!ECRYPTFS_DENTRY_TO_PRIVATE(dentry)) {
+		ecryptfs_printk(1, KERN_ERR, "dentry without private data: "
+				"[%*s]\n", dentry->d_name.len,
+				dentry->d_name.name);
+		goto out;
+	}
+	lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(dentry);
+	if (ECRYPTFS_DENTRY_TO_PRIVATE(dentry))
+		kmem_cache_free(ecryptfs_dentry_info_cache,
+				ECRYPTFS_DENTRY_TO_PRIVATE(dentry));
+	if (lower_dentry)
+		dput(lower_dentry);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return;
+}
+
+struct dentry_operations ecryptfs_dops = {
+	.d_revalidate = ecryptfs_d_revalidate,
+	.d_release = ecryptfs_d_release,
+};
diff -urN oldtree/fs/ecryptfs/ecryptfs_kernel.h newtree/fs/ecryptfs/ecryptfs_kernel.h
--- oldtree/fs/ecryptfs/ecryptfs_kernel.h	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/ecryptfs_kernel.h	2006-02-18 17:24:58.717096200 +0000
@@ -0,0 +1,430 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Kernel declarations.
+ *
+ * Copyright (c) 1997-2003 Erez Zadok
+ * Copyright (c) 2001-2003 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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 ECRYPTFS_KERNEL_H
+#define ECRYPTFS_KERNEL_H
+
+#include <linux/fs.h>
+#include <asm/semaphore.h>
+#include <asm/scatterlist.h>
+
+#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
+#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
+/* The original signature size is only for what is stored on disk; all
+ * in-memory representations are expanded hex, so it better adapted to
+ * be passed around or referenced on the command line */
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 16
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_DEFAULT_IV_BYTES 8
+#define ECRYPTFS_FILE_VERSION 0x01
+
+/**
+ * For convenience, we may need to pass around the encrypted session
+ * key between kernel and userspace because the authentication token
+ * may not be extractable.  For example, the TPM may not release the
+ * private key, instead requiring the encrypted data and returning the
+ * decrypted data.
+ */
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x01
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x02
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x04
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x08
+	int32_t flags;
+	int32_t encrypted_key_size;
+	int32_t decrypted_key_size;
+	uint8_t decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+	uint8_t encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+};
+
+/**
+ * States for this struct are:
+ *  - Uninstantiated: no password, but the salt, encrypted session
+ *    key, etc. are filled in
+ *  - Uninstantiated: no password, salt, etc. are filled in; at this
+ *    time, there is no reason for the auth_tok to exist and be in
+ *    this state
+ *  - Instantiated: password, but no salt, and hence no encrypted
+ *    session key, etc.  eCryptfs will generate those items when the
+ *    time come to write out the headers to disk
+ *  - Instantiated: password, salt, encrypted session key, etc.  This
+ *    is typically used to actually obtain the session key for the
+ *    file
+ */
+struct ecryptfs_password {
+	int32_t saltless;       /* If set, this is the ``seed'' token
+				 * from which other salted tokens are
+				 * derived. Note that this is _not_
+				 * the same as a token that just has
+				 * not received its salt yet. */
+	int32_t password_size;
+	int32_t hash_algo;
+	int32_t hash_iterations;
+	int32_t session_key_encryption_key_size;	/* In bytes */
+	int32_t session_key_encryption_key_set;
+	uint8_t salt[ECRYPTFS_SALT_SIZE];
+	/* Always in expanded hex */
+	uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+	uint8_t password[ECRYPTFS_MAX_PASSWORD_LENGTH];
+	/* Iterated-hash concatenation of salt and passphrase */
+	uint8_t session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+/* May be a password or a private key */
+struct ecryptfs_auth_tok {
+	int32_t instantiated;	/* When not instantiated, this struct only
+				 * contains enough information to construct
+				 * the file headers, which contain token
+				 * descriptors */
+#define ECRYPTFS_PASSWORD 0
+#define ECRYPTFS_PRIVATE_KEY 1
+	int32_t instanceof;
+	int32_t expired;
+	uid_t uid;
+	int64_t creation_time;
+	int64_t expiration_time;
+	/* This is in case we want userspace to extract the session
+	 * key */
+	struct ecryptfs_session_key session_key;
+	union {
+		struct ecryptfs_password password;
+		/* Private key is in future eCryptfs releases */
+	} token;
+};
+
+void dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
+extern void ecryptfs_to_hex(char *dst, char *src, int src_size);
+extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
+
+/* For ecryptfs_auth_tok_packet_set.packet_set_type */
+#define ECRYPTFS_PACKET_SET_TYPE_PASSWORD 0
+
+#ifndef ECRYPTFS_DEBUG
+#define ECRYPTFS_DEBUG 1
+#endif
+
+/* See RFC 2440 */
+struct ecryptfs_key_record {
+	unsigned char type;
+	unsigned char sig[ECRYPTFS_SIG_SIZE];
+	u16 enc_key_size_bits;
+	unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+};
+#define KEY_REC_SIZE(key_rec) \
+        ( sizeof(struct ecryptfs_key_record) - ECRYPTFS_MAX_KEY_BYTES \
+          + key_rec.enc_key_size_bits/8 )
+
+/* TODO: kref */
+struct ecryptfs_auth_tok_list {
+	struct ecryptfs_auth_tok *auth_tok;
+	struct list_head list;
+};
+
+/* Structure prototypes */
+struct ecryptfs_crypt_stats;
+struct ecryptfs_mount_crypt_stats;
+
+#define KEY_PAYLOAD_DATA(key) \
+	( ((struct user_key_payload*)key->payload.data)->data)
+#define KEY_PAYLOAD_LEN(key) \
+	( ((struct user_key_payload*)key->payload.data)->datalen)
+
+#define ECRYPTFS_SUPER_MAGIC 0xf15f
+#define ECRYPTFS_MAX_KEYSET_SIZE 1024
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
+#define ECRYPTFS_MAX_NUM_KEYSIGS 64	/* TODO: make it a list */
+#define ECRYPTFS_MAX_IV_BYTES 8	/* 64 bits */
+#define ECRYPTFS_SALT_BYTES 2
+#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
+#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8	/* 4*2 */
+#define ECRYPTFS_FILE_SIZE_BYTES 8
+#define ECRYPTFS_DEFAULT_CIPHER "blowfish"
+#define ECRYPTFS_DEFAULT_KEY_BYTES 16
+
+/**
+ * IV_SIZE (i.e., 8 bytes)
+ * HMAC_SIZE (i.e., 20 bytes)
+ * IVS_PER_PAGE (i.e., 512)
+ * IVS_PER_PAGE * HMAC_SIZE = TOTAL_SIZE_PER_EXTENT; 512 * 20 = 10240
+ * TOTAL_SIZE_PER_EXTENT / PAGE_SIZE = NUM_PAGES_FOR_HMACS = 2.5
+ * PIIHHHHHDx1024IIHHHHHDx1024...
+ * PIDx512IDx512...
+ * Or: [Ix146+Hx146] (wastes 8 bytes per page)
+ */
+
+/**
+ * This is the primary struct associated with each encrypted file.
+ *
+ * TODO: cache align/pack?
+ */
+struct ecryptfs_crypt_stats {
+	int struct_initialized;
+	int policy_applied;
+	int new_file;
+	int encrypted;
+	int security_warning;	/* This flag is set if something happens
+				 * that could weaken the security of the
+				 * file */
+	int iv_bytes;		/* Set to 0 if encryption not enabled */
+	int records_per_page;	/* extent_size / (iv_bytes + hmac_bytes) */
+#define ECRYPTFS_IV_ROTATE_NO 0
+#define ECRYPTFS_IV_ROTATE_INCREMENT 1
+#define ECRYPTFS_IV_ROTATE_PERMUTATE 2
+#define ECRYPTFS_IV_ROTATE_RANDOM 3
+	int rotate_iv;		/* Whether or not to rotate the IV on each
+				 * write (performance vs. security tradeoff) */
+	int encrypt_iv_pages;	/* To attempt to hide sparse regions? */
+	int num_keysigs;
+	int num_header_pages;	/* Number of pages that comprise the
+				 * header */
+	int extent_size;
+	int key_size_bits;
+	int key_valid;
+	struct crypto_tfm *tfm;
+	unsigned char iv[ECRYPTFS_MAX_IV_BYTES];
+	unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
+	char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+	struct semaphore iv_sem;
+	char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
+};
+
+/* inode private data. */
+struct ecryptfs_inode_info {
+	struct inode *wii_inode;
+	struct ecryptfs_crypt_stats crypt_stats;
+	struct inode vfs_inode;
+};
+
+/* dentry private data. */
+struct ecryptfs_dentry_info {
+	struct dentry *wdi_dentry;
+	struct ecryptfs_crypt_stats *crypt_stats;
+};
+
+/**
+ * This struct is to enable a mount-wide passphrase/salt combo. This
+ * is more or less a stopgap to provide similar functionality to other
+ * crypto filesystems like EncFS or CFS until full policy support is
+ * implemented in eCryptfs.
+ */
+struct ecryptfs_mount_crypt_stats {
+	/* N.B. Pointers to memory we do not own, do not free these */
+	struct ecryptfs_auth_tok *global_auth_tok;
+	struct key *global_auth_tok_key;
+	char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+	char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
+};
+
+/* super block private data. */
+struct ecryptfs_sb_info {
+	struct super_block *wsi_sb;
+	struct vfsmount *lower_mnt;
+	struct ecryptfs_mount_crypt_stats mount_crypt_stats;
+};
+
+/* file private data. */
+struct ecryptfs_file_info {
+	struct file *wfi_file;
+	struct ecryptfs_crypt_stats *crypt_stats;
+};
+
+/* auth_tok <=> encrypted_session_key mappings */
+struct ecryptfs_auth_tok_list_item {
+	struct list_head list;
+	struct ecryptfs_auth_tok auth_tok;
+	char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+extern inline pgoff_t 
+ecryptfs_pg_idx_to_lwr_pg_idx(struct ecryptfs_crypt_stats *crypt_stats,
+			      pgoff_t idx)
+{
+	return ((idx / crypt_stats->records_per_page) + idx
+		+ crypt_stats->num_header_pages + 1);
+}
+
+#ifndef DEFAULT_POLLMASK
+#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
+#endif				/* ndef DEFAULT_POLLMASK */
+
+#define OBSERVE_ASSERTS 1
+#ifdef OBSERVE_ASSERTS
+#define ASSERT(EX)	                                                      \
+do {	                                                                      \
+        if (unlikely(!(EX))) {                                                \
+	        printk(KERN_CRIT "ASSERTION FAILED: %s at %s:%d (%s)\n", #EX, \
+	               __FILE__, __LINE__, __FUNCTION__);	              \
+                BUG();                                                        \
+        }	                                                              \
+} while (0)
+#else
+#define ASSERT(EX) ;
+#endif				/* OBSERVE_ASSERTS */
+
+/**
+ * Halcrow: What does the kernel VFS do to ensure that there is no
+ * contention for file->private_data?
+ */
+#define ECRYPTFS_FILE_TO_PRIVATE(file) ((struct ecryptfs_file_info *) \
+                                        ((file)->private_data))
+#define ECRYPTFS_FILE_TO_PRIVATE_SM(file) ((file)->private_data)
+#define ECRYPTFS_FILE_TO_LOWER(file) \
+        ((ECRYPTFS_FILE_TO_PRIVATE(file))->wfi_file)
+#define ECRYPTFS_INODE_TO_PRIVATE(ino) ((struct ecryptfs_inode_info *) \
+                                        (ino)->u.generic_ip)
+#define ECRYPTFS_INODE_TO_PRIVATE_SM(ino) ((ino)->u.generic_ip)
+#define ECRYPTFS_INODE_TO_LOWER(ino) (ECRYPTFS_INODE_TO_PRIVATE(ino)->wii_inode)
+#define ECRYPTFS_SUPERBLOCK_TO_PRIVATE(super) ((struct ecryptfs_sb_info *) \
+                                               (super)->s_fs_info)
+#define ECRYPTFS_SUPERBLOCK_TO_PRIVATE_SM(super) ((super)->s_fs_info)
+#define ECRYPTFS_SUPERBLOCK_TO_LOWER(super) \
+        (ECRYPTFS_SUPERBLOCK_TO_PRIVATE(super)->wsi_sb)
+#define ECRYPTFS_DENTRY_TO_PRIVATE_SM(dentry) ((dentry)->d_fsdata)
+#define ECRYPTFS_DENTRY_TO_PRIVATE(dentry) ((struct ecryptfs_dentry_info *) \
+                                            (dentry)->d_fsdata)
+#define ECRYPTFS_DENTRY_TO_LOWER(dentry) \
+        (ECRYPTFS_DENTRY_TO_PRIVATE(dentry)->wdi_dentry)
+
+/*
+ * Flags for ecryptfs_{en,de}code_filename
+ * DO_DOTS means the special entries . and .. should be encoded (for symlink)
+ * SKIP_DOTS means they should be preserved intact
+ */
+#define ECRYPTFS_DO_DOTS   0
+#define ECRYPTFS_SKIP_DOTS 1
+
+/**
+ * EXTERNALS:
+ */
+extern struct file_operations ecryptfs_main_fops;
+extern struct file_operations ecryptfs_dir_fops;
+extern struct inode_operations ecryptfs_main_iops;
+extern struct inode_operations ecryptfs_dir_iops;
+extern struct inode_operations ecryptfs_symlink_iops;
+extern struct super_operations ecryptfs_sops;
+extern struct dentry_operations ecryptfs_dops;
+extern struct address_space_operations ecryptfs_aops;
+struct ecryptfs_key_record;
+struct ecryptfs_auth_tok;
+
+/**
+ * TODO: Make eCryptfs's memory usage as lean as possible
+ */
+extern kmem_cache_t *ecryptfs_auth_tok_list_item_cache;
+extern kmem_cache_t *ecryptfs_file_info_cache;
+extern kmem_cache_t *ecryptfs_dentry_info_cache;
+extern kmem_cache_t *ecryptfs_inode_info_cache;
+extern kmem_cache_t *ecryptfs_sb_info_cache;
+extern kmem_cache_t *ecryptfs_header_cache_0;
+extern kmem_cache_t *ecryptfs_header_cache_1;
+extern kmem_cache_t *ecryptfs_header_cache_2;
+extern kmem_cache_t *ecryptfs_lower_page_cache;
+
+int ecryptfs_interpose(struct dentry *hidden_dentry,
+		       struct dentry *this_dentry, struct super_block *sb,
+		       int flag);
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
+int ecryptfs_decode_filename(const char *name, int length,
+			     char **decrypted_name, int skip_dots,
+			     struct ecryptfs_crypt_stats *crypt_stats);
+int ecryptfs_encode_filename(const char *name, int length,
+			     char **encoded_name, int skip_dots,
+			     struct ecryptfs_crypt_stats *crypt_stats);
+struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
+
+void ecryptfs_copy_attr_times(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
+
+#define ecryptfs_printk(verb, type, fmt, arg...) \
+        __ecryptfs_printk((verb), type "%s: " fmt, __FUNCTION__, ## arg);
+void __ecryptfs_printk(int verb, const char *fmt, ...);
+
+extern int ecryptfs_verbosity;
+
+/* crypto */
+void ecryptfs_dump_hex(char *data, int bytes);
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+			int sg_size);
+void ecryptfs_rotate_iv(unsigned char *iv);
+void ecryptfs_init_crypt_stats(struct ecryptfs_crypt_stats *crypt_stats);
+void ecryptfs_destruct_crypt_stats(struct ecryptfs_crypt_stats *crypt_stats);
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stats *crypt_stats);
+int ecryptfs_write_inode_size_to_header(struct file *lower_file,
+					struct inode *lower_inode,
+					struct inode *inode);
+int do_encrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+		    struct page *dest_page, struct page *src_page,
+		    unsigned char *iv);
+int do_encrypt_page_offset(struct ecryptfs_crypt_stats *crypt_stats,
+			   struct page *dest_page, int dest_offset,
+			   struct page *src_page, int src_offset, int size,
+			   unsigned char *iv);
+int do_decrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+		    struct page *dest_page, struct page *src_page,
+		    unsigned char *iv);
+int do_decrypt_page_offset(struct ecryptfs_crypt_stats *crypt_stats,
+			   struct page *dest_page, int dest_offset,
+			   struct page *src_page, int src_offset, int size,
+			   unsigned char *iv);
+int do_encrypt_virt(struct ecryptfs_crypt_stats *crypt_stats,
+		    char *dest_virt_addr, const char *src_virt_addr,
+		    int size, unsigned char *iv);
+int do_decrypt_virt(struct ecryptfs_crypt_stats *crypt_stats,
+		    char *dest_virt_addr, const char *src_virt_addr,
+		    int size, unsigned char *iv);
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+			   struct file *lower_file);
+int ecryptfs_write_headers_virt(char *page_virt, 
+				struct ecryptfs_crypt_stats *crypt_stats,
+				struct dentry *ecryptfs_dentry, int version);
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+			  struct file *lower_file);
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
+int contains_ecryptfs_marker(char *data);
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+				struct nameidata *nd);
+u16 ecryptfs_code_for_cipher_string(char *str);
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stats *crypt_stats);
+int ecryptfs_generate_key_packet_set(char *dest_base,
+				     struct ecryptfs_crypt_stats *crypt_stats,
+				     struct dentry *ecryptfs_dentry, int *len);
+int process_request_key_err(long err_code);
+int ecryptfs_parse_packet_set(unsigned char *dest,
+			      struct ecryptfs_crypt_stats *crypt_stats,
+			      struct dentry *ecryptfs_dentry, int version);
+
+/* inode.c */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
+
+#endif				/* ndef ECRYPTFS_KERNEL_H */
diff -urN oldtree/fs/ecryptfs/file.c newtree/fs/ecryptfs/file.c
--- oldtree/fs/ecryptfs/file.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/file.c	2006-02-18 17:24:58.719095896 +0000
@@ -0,0 +1,710 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 2001-2004 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *   		Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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/file.h>
+#include <linux/poll.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * @param file		File we are seeking in
+ * @param offset	The offset to seek to
+ * @param origin	Where to start seek from
+ * 			(0=beginning,1=cur pos,2=end of file)
+ * @return		The position we have seeked to, or negative on error
+ */
+static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
+{
+	loff_t ret;
+	int rc;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; offset = [%lld] origin = [%d]",
+			"\n", offset, origin);
+	if (NULL != ECRYPTFS_FILE_TO_PRIVATE(file))
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	/* Intent: If our offset is past the end of our file, we're going to
+	 * need to grow it so we have a valid length of 0's */
+	if (offset > i_size_read(file->f_dentry->d_inode)) {
+		rc = ecryptfs_truncate(file->f_dentry, offset);
+		if (rc) {
+			ret = rc;
+			ecryptfs_printk(0, KERN_ERR, "Error on attempt to "
+					"truncate to (higher) offset; rc = "
+					"[%d]\n", rc);
+			goto out;
+		}
+	}
+	ret = generic_file_llseek(file, offset, origin);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; ret = [%lld]\n", ret);
+	return ret;
+}
+
+/**
+ * generic_file_read updates the atime of upper layer inode.  But, it
+ * doesn't give us a chance to update the atime of the lower layer
+ * inode.  This function is a wrapper to generic_file_read.  It
+ * updates the atime of the lower level inode if generic_file_read
+ * returns without any errors. This is to be used only for file reads.
+ * The function to be used for directory reads is ecryptfs_read.
+ */
+static ssize_t ecryptfs_read_update_atime(struct file *file, char __user * buf,
+					  size_t count, loff_t * ppos)
+{
+	int err = 0;
+	struct dentry *lower_dentry;
+	struct vfsmount *lower_vfsmount;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	err = generic_file_read(file, buf, count, ppos);
+	if (err >= 0) {
+		lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(file->f_dentry);
+		lower_vfsmount = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(
+			file->f_dentry->d_inode->i_sb)->lower_mnt;
+		touch_atime(lower_vfsmount, lower_dentry);
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return err;
+}
+
+static ssize_t
+ecryptfs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	int rc = -EINVAL;
+	struct file *lower_file = NULL;
+	loff_t pos = *ppos;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; file = [%p]\n", file);
+	if (!lower_file->f_op || !lower_file->f_op->read)
+		goto out;
+	rc = lower_file->f_op->read(lower_file, buf, count, &pos);
+	if (rc >= 0)
+		/* atime should also be updated for reads of size zero
+		 * or more */
+		ecryptfs_copy_attr_atime(file->f_dentry->d_inode,
+					 lower_file->f_dentry->d_inode);
+	lower_file->f_pos = *ppos = pos;
+	memcpy(&(file->f_ra), &(lower_file->f_ra),
+	       sizeof(struct file_ra_state));
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Directory write operation.
+ *
+ * TODO: Encrypt the directory pages also if policy calls for it
+ */
+static ssize_t ecryptfs_dir_write(struct file *file, const char __user *buf,
+				  size_t count, loff_t *ppos)
+{
+	int rc = -EINVAL;
+	struct file *lower_file = NULL;
+	struct inode *inode;
+	struct inode *lower_inode;
+	loff_t pos = *ppos;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; file = [%p]\n", file);
+	inode = file->f_dentry->d_inode;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	if (!lower_file->f_op || !lower_file->f_op->write)
+		goto out;
+	/* adjust for append -- seek to the end of the file */
+	if ((file->f_flags & O_APPEND) && (count != 0))
+		pos = i_size_read(inode);
+	if (count != 0)
+		rc = lower_file->f_op->write(lower_file, buf, count, &pos);
+	else
+		rc = 0;
+	/* copy ctime and mtime from lower layer attributes
+	 * atime is unchanged for both layers */
+	if (rc >= 0)
+		ecryptfs_copy_attr_times(inode, lower_inode);
+	/* because pwrite() does not have any way to tell us that it
+	 * is our caller, then we don't know for sure if we have to
+	 * update the file positions.  This hack relies on write()
+	 * having passed us the "real" pointer of its struct file's
+	 * f_pos field. */
+	lower_file->f_pos = *ppos = pos;
+	/* update this inode's size */
+	if (pos > i_size_read(inode))
+		i_size_write(inode, pos);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+struct ecryptfs_getdents_callback {
+	void *dirent;
+	struct dentry *dentry;
+	filldir_t filldir;
+	int err;
+	int filldir_called;
+	int entries_written;
+};
+
+/* copied from generic filldir in fs/readir.c */
+static int
+ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
+		 ino_t ino, unsigned int d_type)
+{
+	struct ecryptfs_crypt_stats *crypt_stats;
+	struct ecryptfs_getdents_callback *buf =
+	    (struct ecryptfs_getdents_callback *)dirent;
+	int rc;
+	char *decoded_name;
+	int decoded_length;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter w/ name = [%.*s]\n", namelen,
+			name);
+	/* Get the crypto stats for this file */
+	/* TODO: If filldir oopses, look here ... */
+	crypt_stats = ECRYPTFS_DENTRY_TO_PRIVATE(buf->dentry)->crypt_stats;
+	buf->filldir_called++;
+	/* TODO: Halcrow: Check the headers of the file to determine
+	 * if the filename needs decryption (or hiding, or
+	 * obfuscation, etc.) */
+	decoded_length = ecryptfs_decode_filename(name, namelen, &decoded_name,
+						  ECRYPTFS_SKIP_DOTS,
+						  crypt_stats);
+	if (decoded_length < 0)
+		return 0;
+	rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
+			  ino, d_type);
+	kfree(decoded_name);
+	if (rc >= 0)
+		buf->entries_written++;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * @param file The ecryptfs file struct
+ * @param filldir The filldir callback function
+ */
+static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	int rc = -ENOTDIR;
+	struct file *lower_file = NULL;
+	struct inode *inode;
+	struct ecryptfs_getdents_callback buf;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; file = [%p]\n", file);
+	lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	inode = file->f_dentry->d_inode;
+	buf.dirent = dirent;
+	buf.dentry = file->f_dentry;
+	buf.filldir = filldir;
+retry:
+	buf.filldir_called = 0;
+	buf.entries_written = 0;
+	buf.err = 0;
+	rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
+	if (buf.err)
+		rc = buf.err;
+	if (buf.filldir_called && !buf.entries_written)
+		goto retry;
+	file->f_pos = lower_file->f_pos;
+	if (rc >= 0)
+		ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static unsigned int ecryptfs_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask = DEFAULT_POLLMASK;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; file = [%p]\n", file);
+	if (!lower_file->f_op || !lower_file->f_op->poll)
+		goto out;
+	mask = lower_file->f_op->poll(lower_file, wait);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; mask = [%x]\n", mask);
+	return mask;
+}
+
+/**
+ * @return Zero on success; non-zero otherwise
+ */
+static int
+read_inode_size_from_header(struct file *lower_file,
+			    struct inode *lower_inode, struct inode *inode)
+{
+	int rc = 0;
+	struct page *header_page;
+	unsigned char *header_virt;
+	u64 data_size;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter w/ lower_inode = [%p]; inode = "
+			"[%p]\n", lower_inode, inode);
+	header_page = grab_cache_page(lower_inode->i_mapping, 0);
+	if (!header_page) {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "grab_cache_page for header page "
+				"failed\n");
+		goto out;
+	}
+	header_virt = kmap(header_page);
+	rc = lower_inode->i_mapping->a_ops->readpage(lower_file, header_page);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error reading header page\n");
+		goto out_unmap;
+	}
+	memcpy(&data_size, header_virt, sizeof(data_size));
+	i_size_write(inode, (loff_t) data_size);
+	ecryptfs_printk(1, KERN_NOTICE, "Read inode size from header: [%llu]\n",
+			i_size_read(inode));
+out_unmap:
+	kunmap(header_page);
+	page_cache_release(header_page);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+kmem_cache_t *ecryptfs_file_info_cache;
+
+/**
+ * Opens the file specified by inode.
+ *
+ * @param inode	inode speciying file to open
+ * @param file	Structure to return filled in
+ * @return Zero on success; non-zero otherwise
+ */
+static int ecryptfs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stats *crypt_stats = NULL;
+	struct dentry *ecryptfs_dentry = file->f_dentry;
+	struct dentry *lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(ecryptfs_dentry);
+	struct inode *lower_inode = NULL;
+	struct file *lower_file = NULL;
+	struct vfsmount *lower_mnt;
+	int lower_flags;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; i_ino = [%lu] inode = [%p] "
+			"inode->i_size = [%lld] inode->i_count = [%d] file->"
+			"f_dentry = [%p] file->f_dentry->d_name.name = [%s] "
+			"file->f_dentry->d_name.len = [%d]\n", inode->i_ino,
+			inode, atomic_read(&inode->i_count), i_size_read(inode),
+			ecryptfs_dentry, ecryptfs_dentry->d_name.name,
+			ecryptfs_dentry->d_name.len);
+
+	/* ECRYPTFS_DENTRY_TO_PRIVATE(ecryptfs_dentry) Allocated in
+	 * ecryptfs_lookup() */
+	/* Released in ecryptfs_release or end of function if failure */
+	ECRYPTFS_FILE_TO_PRIVATE_SM(file) =
+		kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+	if (!ECRYPTFS_FILE_TO_PRIVATE_SM(file)) {
+		ecryptfs_printk(0, KERN_ERR,
+				"Error attempting to allocate memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(ecryptfs_dentry);
+	crypt_stats = &(ECRYPTFS_INODE_TO_PRIVATE(inode)->crypt_stats);
+	if (!crypt_stats->policy_applied) {
+		ecryptfs_printk(1, KERN_NOTICE, "Setting flags for stats...\n");
+		/* Policy code enabled in future release */
+		crypt_stats->policy_applied = 1;
+		crypt_stats->encrypted = 1;
+	}
+	/* This mntget & dget is undone via fput when the file is released */
+	dget(lower_dentry);
+	lower_flags = file->f_flags;
+	if ((lower_flags & O_ACCMODE) == O_WRONLY)
+		lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
+	if (file->f_flags & O_APPEND)
+		lower_flags &= ~O_APPEND;
+	lower_mnt = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt;
+	mntget(lower_mnt);
+	/* Corresponding fput() in ecryptfs_release() */
+	lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags);
+	if (IS_ERR(lower_file)) {
+		rc = PTR_ERR(lower_file);
+		ecryptfs_printk(0, KERN_ERR, "Error opening lower file\n");
+		goto out_puts;
+	}
+	ECRYPTFS_FILE_TO_LOWER(file) = lower_file;
+	/* Isn't this check the same as the one in lookup? */
+	lower_inode = lower_dentry->d_inode;
+	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+		ecryptfs_printk(1, KERN_NOTICE, "This is a directory\n");
+		crypt_stats->encrypted = 0;
+		rc = 0;
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "(file->f_flags & O_CREAT) = [%d] "
+			"lower_inode->i_size = [%llu] crypt_stats->struct_"
+			"initialized = [%d] crypt_stats->key_valid = [%d]\n",
+			(file->f_flags & O_CREAT),
+			(unsigned long long)lower_inode->i_size,
+			crypt_stats->struct_initialized,
+			crypt_stats->key_valid);
+	/* TODO: This was originally used to determine if it was a new file,
+	 * but if we are allowing pass-through mode, then we couldbe opening
+	 * a 0-length normal file.. in which case, this can't cause an error
+	 * So.... what do we want to do? */
+	if (lower_inode->i_size == 0) {
+		ecryptfs_printk(0, KERN_EMERG, "Zero-length lower file; "
+				"ecryptfs_create() had a problem?\n");
+		rc = -ENOENT;
+		goto out_puts;
+	} else if (!crypt_stats->policy_applied || !crypt_stats->key_valid) {
+		/* crypto.c */
+		rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file);
+		if (rc) {
+			ecryptfs_printk(1, KERN_NOTICE,
+					"Valid headers not found\n");
+			crypt_stats->encrypted = 0;
+		} else
+			read_inode_size_from_header(lower_file, lower_inode,
+						    inode);
+	} else
+		ecryptfs_printk(1, KERN_NOTICE, "crypt_stats->struct_"
+				"initialized = [%d]; crypt_stats->key_valid = "
+				"[%d]\n", crypt_stats->struct_initialized,
+				crypt_stats->key_valid);
+	ECRYPTFS_FILE_TO_LOWER(file) = lower_file;
+	goto out;
+out_puts:
+	mntput(lower_mnt);
+	dput(lower_dentry);
+	kmem_cache_free(ecryptfs_file_info_cache,
+			ECRYPTFS_FILE_TO_PRIVATE(file));
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static int ecryptfs_flush(struct file *file)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; file = [%p]\n", file);
+	lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	if (lower_file->f_op && lower_file->f_op->flush)
+		rc = lower_file->f_op->flush(lower_file);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static int ecryptfs_release(struct inode *ecryptfs_inode, struct file *file)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+	struct inode *lower_inode;
+
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Enter; ecryptfs_inode->i_count = [%d]\n",
+			ecryptfs_inode->i_count);
+	lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	kmem_cache_free(ecryptfs_file_info_cache,
+			ECRYPTFS_FILE_TO_PRIVATE(file));
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(ecryptfs_inode);
+	fput(lower_file);
+	ecryptfs_inode->i_blocks = lower_inode->i_blocks;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static int
+ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	int rc = -EINVAL;
+	struct file *lower_file = NULL;
+	struct dentry *lower_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (NULL == file) {
+		lower_dentry = ecryptfs_lower_dentry(dentry);
+		if (lower_dentry->d_inode->i_fop
+		    && lower_dentry->d_inode->i_fop->fsync) {
+			down(&lower_dentry->d_inode->i_sem);
+			rc = lower_dentry->d_inode->i_fop->fsync(lower_file,
+								 lower_dentry,
+								 datasync);
+			up(&lower_dentry->d_inode->i_sem);
+		}
+	} else {
+		if (NULL == ECRYPTFS_FILE_TO_PRIVATE(file)) {
+			rc = -EINVAL;
+			ecryptfs_printk(0, KERN_ERR, "ECRYPTFS_FILE_TO_PRIVATE"
+					"(file=[%p]) == NULL\n", file);
+			goto out;
+		}
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+		lower_dentry = ecryptfs_lower_dentry(dentry);
+		if (lower_file->f_op && lower_file->f_op->fsync) {
+			down(&lower_dentry->d_inode->i_sem);
+			rc = lower_file->f_op->fsync(lower_file, lower_dentry,
+						     datasync);
+			up(&lower_dentry->d_inode->i_sem);
+		}
+	}
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static void locks_delete_block(struct file_lock *waiter)
+{
+	lock_kernel();
+	list_del_init(&waiter->fl_block);
+	list_del_init(&waiter->fl_link);
+	waiter->fl_next = NULL;
+	unlock_kernel();
+}
+
+static int ecryptfs_posix_lock(struct file *file, struct file_lock *fl, int cmd)
+{
+	int rc;
+
+lock_file:
+	rc = posix_lock_file(file, fl);
+	if ((rc != -EAGAIN) || (cmd == F_SETLK))
+		goto out;
+	rc = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
+	if (!rc)
+		goto lock_file;
+	locks_delete_block(fl);
+out:
+	return rc;
+}
+
+static int ecryptfs_setlk(struct file *file, int cmd, struct file_lock *fl)
+{
+	int rc = -EINVAL;
+	struct inode *inode, *lower_inode;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	inode = file->f_dentry->d_inode;
+	lower_inode = lower_file->f_dentry->d_inode;
+	/* Don't allow mandatory locks on files that may be memory mapped
+	 * and shared. */
+	if (IS_MANDLOCK(lower_inode) &&
+	    (lower_inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
+	    mapping_writably_mapped(lower_file->f_mapping)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+	if (cmd == F_SETLKW)
+		fl->fl_flags |= FL_SLEEP;
+	rc = -EBADF;
+	switch (fl->fl_type) {
+	case F_RDLCK:
+		if (!(lower_file->f_mode & FMODE_READ))
+			goto out;
+		break;
+	case F_WRLCK:
+		if (!(lower_file->f_mode & FMODE_WRITE))
+			goto out;
+		break;
+	case F_UNLCK:
+		break;
+	default:
+		rc = -EINVAL;
+		goto out;
+	}
+	fl->fl_file = lower_file;
+	rc = security_file_lock(lower_file, fl->fl_type);
+	if (rc)
+		goto out;
+	if (lower_file->f_op && lower_file->f_op->lock != NULL) {
+		rc = lower_file->f_op->lock(lower_file, cmd, fl);
+		if (rc)
+			goto out;
+		goto upper_lock;
+	}
+	rc = ecryptfs_posix_lock(lower_file, fl, cmd);
+	if (rc)
+		goto out;
+upper_lock:
+	fl->fl_file = file;
+	rc = ecryptfs_posix_lock(file, fl, cmd);
+	if (rc) {
+		fl->fl_type = F_UNLCK;
+		fl->fl_file = lower_file;
+		ecryptfs_posix_lock(lower_file, fl, cmd);
+	}
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static int ecryptfs_getlk(struct file *file, struct file_lock *fl)
+{
+	int rc = 0;
+	struct file_lock *tempfl = NULL;
+
+	if (file->f_op && file->f_op->lock) {
+		rc = file->f_op->lock(file, F_GETLK, fl);
+		if (rc < 0)
+			goto out;
+	} else
+		tempfl = posix_test_lock(file, fl);
+	if (!tempfl)
+		fl->fl_type = F_UNLCK;
+	else
+		memcpy(fl, tempfl, sizeof(struct file_lock));
+out:
+	return rc;
+}
+
+static int ecryptfs_fasync(int fd, struct file *file, int flag)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (NULL != ECRYPTFS_FILE_TO_PRIVATE(file))
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	else {
+		rc = -EINVAL;
+		goto out;
+	}
+	if (lower_file->f_op && lower_file->f_op->fasync)
+		rc = lower_file->f_op->fasync(fd, lower_file, flag);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return rc;
+}
+
+static int ecryptfs_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (ECRYPTFS_FILE_TO_PRIVATE(file) != NULL)
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	ASSERT(lower_file != NULL);
+	rc = -EINVAL;
+	if (!fl)
+		goto out;
+	fl->fl_file = lower_file;
+	switch (cmd) {
+	case F_GETLK:
+	case F_GETLK64:
+		rc = ecryptfs_getlk(lower_file, fl);
+		break;
+	case F_SETLK:
+	case F_SETLKW:
+	case F_SETLK64:
+	case F_SETLKW64:
+		fl->fl_file = file;
+		rc = ecryptfs_setlk(file, cmd, fl);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	fl->fl_file = file;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return rc;
+}
+
+static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
+				 size_t count, read_actor_t actor, void *target)
+{
+	struct file *lower_file = NULL;
+	int rc = -EINVAL;
+
+	if (ECRYPTFS_FILE_TO_PRIVATE(file) != NULL)
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	ASSERT(lower_file != NULL);
+	/* TODO: Is this a superfluous check for f_op? */
+	if (lower_file->f_op && lower_file->f_op->sendfile)
+		rc = lower_file->f_op->sendfile(lower_file, ppos, count,
+						actor, target);
+
+	return rc;
+}
+
+static int ecryptfs_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg);
+
+struct file_operations ecryptfs_dir_fops = {
+	.read = ecryptfs_read,
+	.write = ecryptfs_dir_write,
+	.readdir = ecryptfs_readdir,
+	.poll = ecryptfs_poll,
+	.ioctl = ecryptfs_ioctl,
+	.mmap = generic_file_mmap,
+	.open = ecryptfs_open,
+	.flush = ecryptfs_flush,
+	.release = ecryptfs_release,
+	.fsync = ecryptfs_fsync,
+	.fasync = ecryptfs_fasync,
+	.lock = ecryptfs_lock,
+	.sendfile = ecryptfs_sendfile,
+};
+
+struct file_operations ecryptfs_main_fops = {
+	.llseek = ecryptfs_llseek,
+	.read = ecryptfs_read_update_atime,
+	.write = generic_file_write,
+	.readdir = ecryptfs_readdir,
+	.poll = ecryptfs_poll,
+	.ioctl = ecryptfs_ioctl,
+	.mmap = generic_file_mmap,
+	.open = ecryptfs_open,
+	.flush = ecryptfs_flush,
+	.release = ecryptfs_release,
+	.fsync = ecryptfs_fsync,
+	.fasync = ecryptfs_fasync,
+	.lock = ecryptfs_lock,
+	.sendfile = ecryptfs_sendfile,
+};
+
+/**
+ * TODO: sysfs
+ */
+static int
+ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	       unsigned long arg)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+	if (ECRYPTFS_FILE_TO_PRIVATE(file) != NULL)
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
+		rc = lower_file->f_op->ioctl(ECRYPTFS_INODE_TO_LOWER(inode),
+					     lower_file, cmd, arg);
+	else
+		rc = -ENOTTY;
+	return rc;
+}
diff -urN oldtree/fs/ecryptfs/inode.c newtree/fs/ecryptfs/inode.c
--- oldtree/fs/ecryptfs/inode.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/inode.c	2006-02-18 17:24:58.721095592 +0000
@@ -0,0 +1,1084 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 2001-2004 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompsion <mcthomps@us.ibm.com>
+ *
+ * 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/file.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+	struct dentry *dir;
+
+	dir = dget(dentry->d_parent);
+	down(&(dir->d_inode->i_sem));
+	return dir;
+}
+
+static inline void unlock_parent(struct dentry *dentry)
+{
+	up(&(dentry->d_parent->d_inode->i_sem));
+	dput(dentry->d_parent);
+}
+
+static inline void unlock_dir(struct dentry *dir)
+{
+	up(&dir->d_inode->i_sem);
+	dput(dir);
+}
+
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	ecryptfs_printk(1, KERN_NOTICE, "src->i_size = [%lld]\n", src->i_size);
+	ecryptfs_printk(1, KERN_NOTICE, "src->i_blocks = [%lu]\n",
+			src->i_blocks);
+	i_size_write(dst, i_size_read((struct inode *)src));
+	dst->i_blocks = src->i_blocks;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
+{
+	ASSERT(dest != NULL);
+	ASSERT(src != NULL);
+	dest->i_atime = src->i_atime;
+}
+
+void ecryptfs_copy_attr_times(struct inode *dest, const struct inode *src)
+{
+	ASSERT(dest != NULL);
+	ASSERT(src != NULL);
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+}
+
+static void ecryptfs_copy_attr_timesizes(struct inode *dest,
+					 const struct inode *src)
+{
+	ASSERT(dest != NULL);
+	ASSERT(src != NULL);
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+	ecryptfs_copy_inode_size(dest, src);
+}
+
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	ASSERT(dest != NULL);
+	ASSERT(src != NULL);
+	dest->i_mode = src->i_mode;
+	dest->i_nlink = src->i_nlink;
+	dest->i_uid = src->i_uid;
+	dest->i_gid = src->i_gid;
+	dest->i_rdev = src->i_rdev;
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+	dest->i_blksize = src->i_blksize;
+	ecryptfs_printk(1, KERN_NOTICE, "src->i_blksize = [%lu]\n",
+			src->i_blksize);
+	dest->i_blkbits = src->i_blkbits;
+	dest->i_flags = src->i_flags;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Creates our file in the lower file system
+ *
+ * @param lower_dir_inode   inode of the parent in the lower fs of the new file
+ * @param lower_dentry	    New file's dentry in the lower fs
+ * @param ecryptfs_dentry   New file's dentry in ecryptfs
+ * @param mode		    The mode of the new file
+ * @param nd		    nameidata of ecryptfs' parent's dentry & vfsmnt
+ * @return		    0 on success; non-zero on error condition
+ */
+static int
+ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
+				struct dentry *lower_dentry,
+				struct dentry *ecryptfs_dentry, int mode,
+				struct nameidata *nd)
+{
+	int rc;
+	struct dentry *saved_dentry = NULL;
+	struct vfsmount *saved_vfsmount = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	saved_dentry = nd->dentry;
+	saved_vfsmount = nd->mnt;
+	nd->dentry = lower_dentry;
+	nd->mnt = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(
+		ecryptfs_dentry->d_sb)->lower_mnt;
+	rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
+	nd->dentry = saved_dentry;
+	nd->mnt = saved_vfsmount;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Creates the underlying file and the eCryptfs inode which will link to
+ * it. It will also update the eCryptfs directory inode to mimic the
+ * stats of the lower directory inode
+ *
+ * @param directory_inode   inode of the new file's dentry's parent in ecryptfs
+ * @param ecryptfs_dentry   New file's dentry in ecryptfs
+ * @param mode		    The mode of the new file
+ * @param nd		    nameidata of ecryptfs' parent's dentry & vfsmnt
+ * @return		    0 on success; non-zero on error condition
+ */
+static int
+ecryptfs_do_create(struct inode *directory_inode,
+		   struct dentry *ecryptfs_dentry, int mode,
+		   struct nameidata *nd)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(ecryptfs_dentry);
+	if (IS_ERR(lower_dentry)) {
+		ecryptfs_printk(0, KERN_ERR, "ecryptfs dentry doesn't know"
+				"about its lower counterpart\n");
+		rc = PTR_ERR(lower_dentry);
+		goto out;
+	}
+	lower_dir_dentry = lock_parent(lower_dentry);
+	if (unlikely(IS_ERR(lower_dir_dentry))) {
+		ecryptfs_printk(0, KERN_ERR, "Error locking directory of "
+				"dentry\n");
+		rc = PTR_ERR(lower_dir_dentry);
+		goto out;
+	}
+	rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
+					     lower_dentry, ecryptfs_dentry,
+					     mode, nd);
+	if (unlikely(rc)) {
+		ecryptfs_printk(0, KERN_ERR,
+				"Failure to create underlying file\n");
+		goto out_lock;
+	}
+	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
+				directory_inode->i_sb, 0);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Failure in ecryptfs_interpose\n");
+		goto out_lock;
+	}
+	ecryptfs_copy_attr_timesizes(directory_inode,
+				     lower_dir_dentry->d_inode);
+out_lock:
+	unlock_dir(lower_dir_dentry);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * This is the code which will grow the file to be 8192 or
+ * 12288, depending on whether the file derived-IV or
+ * written-IV formatted.
+ */
+static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
+		     struct inode *inode, struct inode *lower_inode)
+{
+	int rc = 0;
+	struct file fake_file;
+
+	memset(&fake_file, 0, sizeof(fake_file));
+	fake_file.f_dentry = ecryptfs_dentry;
+	ECRYPTFS_FILE_TO_PRIVATE_SM(&fake_file) =
+		kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+	if (!(ECRYPTFS_FILE_TO_PRIVATE_SM(&fake_file))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	ECRYPTFS_FILE_TO_LOWER(&fake_file) = lower_file;
+	ecryptfs_fill_zeros(&fake_file, 1);
+	kmem_cache_free(ecryptfs_file_info_cache,
+			ECRYPTFS_FILE_TO_PRIVATE(&fake_file));
+	i_size_write(inode, 0);
+	ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+	ECRYPTFS_INODE_TO_PRIVATE(inode)->crypt_stats.new_file = 1;
+out:
+	return rc;
+}
+
+/**
+ * Force the file to be changed from a basic empty file to an ecryptfs file
+ * with a header, 1st IV page & 1st data page
+ *
+ * @return Zero on success
+ */
+static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	int lower_flags;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	struct dentry *lower_dentry;
+	struct dentry *tlower_dentry = NULL;
+	struct file *lower_file;
+	struct inode *inode, *lower_inode;
+	struct vfsmount *lower_mnt;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name.name = [%s]\n",
+			ecryptfs_dentry->d_name.name);
+
+	lower_dentry = ecryptfs_lower_dentry(ecryptfs_dentry);
+	if (IS_ERR(lower_dentry)) {
+		ecryptfs_printk(0, KERN_ERR, "ecryptfs dentry doesn't know"
+				"about its lower counterpart\n");
+		rc = PTR_ERR(lower_dentry);
+		goto out;
+	}
+
+	ecryptfs_printk(1, KERN_NOTICE, "lower_dentry->d_name.name = [%s]\n",
+			lower_dentry->d_name.name);
+
+	/* This code is migrated from ecryptfs_open... 
+	 * there is no reason that this shouldn't just "work"
+	 * The flags and mode for the file passed into ecryptfs_open is:
+	 * f->f_flags = flags;
+	 * f->f_mode = ((flags+1) & O_ACCMODE) 
+	 *                      | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
+	 * 
+	 * Where flags = O_CREAT | O_WRONLY | O_TRUNC &
+	 *      ( #if BITS_PER_LONG != 32 ; flags |= O_LARGEFILE; #endif )
+	 *
+	 * Code to initialize the file to be a valid ecryptfs file
+	 */
+	inode = ecryptfs_dentry->d_inode;
+	crypt_stats = &(ECRYPTFS_INODE_TO_PRIVATE(inode)->crypt_stats);
+	/* TODO: Initialization is done in alloc_inode, BUG if its not done */
+	if (!crypt_stats->struct_initialized)
+		BUG();
+	tlower_dentry = dget(lower_dentry);
+	if (!tlower_dentry) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Error dget'ing lower_dentry\n");
+		goto out;
+	}
+	lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR;
+#if BITS_PER_LONG != 32
+	lower_flags |= O_LARGEFILE;
+#endif
+	lower_mnt = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt;
+	mntget(lower_mnt);
+	/* Corresponding fput() at end of func */
+	lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags);
+	if (IS_ERR(lower_file)) {
+		rc = PTR_ERR(lower_file);
+		ecryptfs_printk(0, KERN_ERR,
+				"Error opening dentry; rc = [%i]\n", rc);
+		goto out;
+	}
+	/* fput(lower_file) should handle the puts if we do this */
+	lower_file->f_dentry = tlower_dentry;
+	lower_file->f_vfsmnt = lower_mnt;
+	lower_inode = tlower_dentry->d_inode;
+	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+		ecryptfs_printk(1, KERN_NOTICE, "This is a directory\n");
+		crypt_stats->encrypted = 0;
+		goto out_fput;
+	}
+	crypt_stats->new_file = 1;
+	ecryptfs_printk(1, KERN_NOTICE, "Initializing crypto context\n");
+	rc = ecryptfs_new_file_context(ecryptfs_dentry);	/* crypto.c */
+	if (rc) {
+		ecryptfs_printk(1, KERN_NOTICE, "Error creating new file "
+				"context\n");
+		goto out_fput;
+	}
+	rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file);
+	if (rc) {
+		ecryptfs_printk(1, KERN_NOTICE, "Error writing headers\n");
+		goto out_fput;
+	}
+	rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
+out_fput:
+	fput(lower_file);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Creates a new file.
+ *
+ * @param dir The inode of the directory in which to create the file.
+ * @param dentry The eCryptfs dentry
+ * @param mode The mode of the new file.
+ * @param nd nameidata
+ * @return 0 on success; non-zero on error condition
+ */
+static int
+ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
+		int mode, struct nameidata *nd)
+{
+	int rc;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; ecryptfs_dentry->d_name.name = "
+			"[%s], directory_inode=[%p], ecryptfs_dentry->d_parent"
+			"->d_inode=[%p], nd->dentry=[%p], nd->last.name=[%s], "
+			"ecryptfs_dentry=[%p]\n", ecryptfs_dentry->d_name.name,
+			directory_inode, ecryptfs_dentry->d_parent->d_inode,
+			nd->dentry, nd->last.name, ecryptfs_dentry);
+
+	rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
+	if (unlikely(rc)) {
+		ecryptfs_printk(0, KERN_WARNING, "Failed to create file in"
+				"lower filesystem\n");
+		goto out;
+	}
+	/* At this point, a file exists on "disk", we need to make sure
+	 * that this on disk file is prepared to be an ecryptfs file */
+	rc = ecryptfs_initialize_file(ecryptfs_dentry);
+      out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Find a file on disk. If the file does not exist, then we'll add it to the
+ * dentry cache and continue on to read it from the disk.
+ *
+ * @param dir	 inode
+ * @param dentry dentry
+ * @param nd	 nameidata; may be NULL
+ */
+static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
+				      struct nameidata *nd)
+{
+	int err = 0;
+	struct dentry *lower_dir_dentry;
+	struct dentry *lower_dentry;
+	struct dentry *tlower_dentry = NULL;
+	char *encoded_name;
+	unsigned int encoded_namelen;
+	struct ecryptfs_crypt_stats *crypt_stats = NULL;
+	char *page_virt = NULL;
+	struct inode *lower_inode;
+	unsigned long long file_size;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dir = [%p], dentry->d_name.nam"
+			"e = [%s], nd = [%p]\n", dir, dentry->d_name.name, nd);
+
+	lower_dir_dentry = ecryptfs_lower_dentry(dentry->d_parent);
+	dentry->d_op = &ecryptfs_dops;
+
+	/* Sanity Check: Make sure we can operate on the file */
+	if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
+	    || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, "..")))
+		goto out_drop;
+
+	encoded_namelen = ecryptfs_encode_filename(dentry->d_name.name,
+						   dentry->d_name.len,
+						   &encoded_name,
+						   ECRYPTFS_SKIP_DOTS,
+						   crypt_stats);
+	if (encoded_namelen < 0) {
+		err = encoded_namelen;
+		goto out_drop;
+	}
+	/* TODO: pretty sure we need to do a dput(lower_dentry) to
+	 * counter */
+	ecryptfs_printk(1, KERN_NOTICE, "encoded_name = [%s]; encoded_namelen "
+			"= [%d]\n", encoded_name, encoded_namelen);
+	/* TODO: BUG: What to do on symlink to directory? */
+	lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
+				      encoded_namelen - 1);
+	kfree(encoded_name);
+	if (IS_ERR(lower_dentry)) {
+		ecryptfs_printk(0, KERN_ERR, "ERR from lower_dentry\n");
+		err = PTR_ERR(lower_dentry);
+		goto out_drop;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "lower_dentry = [%p]; lower_dentry->"
+       		"d_name.name = [%s]\n", lower_dentry,
+		lower_dentry->d_name.name);
+	lower_inode = lower_dentry->d_inode;
+	ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
+
+	/* Sanity check */
+	ASSERT(atomic_read(&lower_dentry->d_count));
+
+	/* Private allocation */
+	ECRYPTFS_DENTRY_TO_PRIVATE_SM(dentry) =
+		kmem_cache_alloc(ecryptfs_dentry_info_cache, SLAB_KERNEL);
+	if (!ECRYPTFS_DENTRY_TO_PRIVATE_SM(dentry)) {
+		err = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Out of memory whilst attempting "
+				"to allocate ecryptfs_dentry_info struct\n");
+		goto out_dput;
+	}
+
+	ECRYPTFS_DENTRY_TO_LOWER(dentry) = lower_dentry;
+	if (!lower_dentry->d_inode) {
+		/* We want to add because we couldn't find in lower */
+		d_add(dentry, NULL);
+		goto out;
+	}
+	err = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1);
+	if (err) {
+		ecryptfs_printk(0, KERN_ERR, "Error interposing\n");
+		goto out_dput;
+	}
+	/* Do we want to just get a handle to the directory and its lower
+	 * and not abort with puts?
+	 */
+	if (S_ISDIR(lower_inode->i_mode)) {
+		ecryptfs_printk(1, KERN_NOTICE, "Is a directory; returning\n");
+		goto out;
+	}
+	if (S_ISLNK(lower_inode->i_mode)) {
+		ecryptfs_printk(1, KERN_NOTICE, "Is a symlink; returning\n");
+		goto out;
+	}
+	/* We have a NULL dentry, can we just skip over the read here? */
+	if (!nd) {
+		ecryptfs_printk(1, KERN_NOTICE, "We have a NULL nd, just leave"
+				"as we *think* we are about to unlink\n");
+		goto out;
+	}
+	tlower_dentry = dget(lower_dentry);
+	if (!tlower_dentry || IS_ERR(tlower_dentry)) {
+		err = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Cannot dget lower_dentry\n");
+		goto out_dput;
+	}
+	/* Released in this function */
+	page_virt =
+	    (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
+				     SLAB_USER);
+	if (!page_virt) {
+		err = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR,
+				"Cannot ecryptfs_kmalloc a page\n");
+		goto out_dput;
+	}
+
+	/* Use the file's "header" to determine if its an ecryptfs file */
+	err = ecryptfs_read_header_region(page_virt, tlower_dentry, nd);
+	/* Force default values if we haven't parsed the header */
+	crypt_stats = 
+		&(ECRYPTFS_INODE_TO_PRIVATE(dentry->d_inode)->crypt_stats);
+	if (!crypt_stats->policy_applied)
+		ecryptfs_set_default_sizes(crypt_stats);
+
+	if (err) {
+		err = 0;
+		ecryptfs_printk(1, KERN_WARNING, "Error reading header region;"
+				" assuming unencrypted\n");
+	} else {
+		if (!contains_ecryptfs_marker(page_virt
+					      + ECRYPTFS_FILE_SIZE_BYTES)) {
+			ecryptfs_printk(0, KERN_WARNING, "Underlying file "
+					"lacks recognizable eCryptfs marker\n");
+		}
+		memcpy(&file_size, page_virt, sizeof(file_size));
+		dentry->d_inode->i_size = file_size;
+	}
+	kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+	goto out;
+
+out_dput:
+	dput(lower_dentry);
+	if (tlower_dentry)
+		dput(tlower_dentry);
+out_drop:
+	d_drop(dentry);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return ERR_PTR(err);
+}
+
+static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
+			 struct dentry *new_dentry)
+{
+	int err;
+	struct dentry *lower_old_dentry;
+	struct dentry *lower_new_dentry;
+	struct dentry *lower_dir_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_old_dentry = ecryptfs_lower_dentry(old_dentry);
+	lower_new_dentry = ecryptfs_lower_dentry(new_dentry);
+	dget(lower_old_dentry);
+	dget(lower_new_dentry);
+	lower_dir_dentry = lock_parent(lower_new_dentry);
+	err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
+		       lower_new_dentry);
+	if (err || !lower_new_dentry->d_inode)
+		goto out_lock;
+	err = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
+	if (err)
+		goto out_lock;
+	ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
+	old_dentry->d_inode->i_nlink =
+	    ECRYPTFS_INODE_TO_LOWER(old_dentry->d_inode)->i_nlink;
+out_lock:
+	unlock_dir(lower_dir_dentry);
+	dput(lower_new_dentry);
+	dput(lower_old_dentry);
+	if (!new_dentry->d_inode)
+		d_drop(new_dentry);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	int rc = 0;
+	struct dentry *lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(dentry);
+	struct inode *lower_dir_inode = ECRYPTFS_INODE_TO_LOWER(dir);
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name = [%s]\n",
+			dentry->d_name.name);
+	lock_parent(lower_dentry);
+	rc = vfs_unlink(lower_dir_inode, lower_dentry);
+	if (rc) {
+		ecryptfs_printk(1, KERN_ERR, "Error in vfs_unlink\n");
+		goto out_unlock;
+	}
+	ecryptfs_copy_attr_times(dir, lower_dir_inode);
+	dentry->d_inode->i_nlink = 
+		ECRYPTFS_INODE_TO_LOWER(dentry->d_inode)->i_nlink;
+        dentry->d_inode->i_ctime = dir->i_ctime;	
+out_unlock:	
+	unlock_parent(lower_dentry);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]",rc);
+	return rc;
+}
+
+static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
+			    const char *symname)
+{
+	int err;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+	umode_t mode;
+	char *encoded_symname;
+	unsigned int encoded_symlen;
+	struct ecryptfs_crypt_stats *crypt_stats = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	dget(lower_dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	mode = S_IALLUGO;
+	encoded_symlen = ecryptfs_encode_filename(symname, strlen(symname),
+						  &encoded_symname,
+						  ECRYPTFS_DO_DOTS,
+						  crypt_stats);
+	if (encoded_symlen < 0) {
+		err = encoded_symlen;
+		goto out_lock;
+	}
+	err = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
+			  encoded_symname, mode);
+	kfree(encoded_symname);
+	if (err || !lower_dentry->d_inode)
+		goto out_lock;
+	err = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (err)
+		goto out_lock;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out_lock:
+	unlock_dir(lower_dir_dentry);
+	dput(lower_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	return err;
+}
+
+static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int err;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	err = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+	if (err || !lower_dentry->d_inode)
+		goto out;
+	err = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (err)
+		goto out;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+out:
+	unlock_dir(lower_dir_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	int err = 0;
+	struct dentry *tdentry = NULL;
+	struct dentry *lower_dentry;
+	struct dentry *tlower_dentry = NULL;
+	struct dentry *lower_dir_dentry;
+	struct dentry *tlower_dir_dentry = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	if (!(tdentry = dget(dentry))) {
+		err = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "Error dget'ing dentry [%p]\n",
+				dentry);
+		goto out;
+	}
+	lower_dir_dentry = lock_parent(lower_dentry);
+	if (!(tlower_dentry = dget(lower_dentry))) {
+		err = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "Error dget'ing lower_dentry "
+				"[%p]\n", lower_dentry);
+		goto out;
+	}
+	err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+	if (!err) {
+		d_delete(tlower_dentry);
+		tlower_dentry = NULL;
+	}
+	ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+	unlock_dir(lower_dir_dentry);
+	if (!err)
+		d_drop(dentry);
+out:
+	if (tdentry)
+		dput(tdentry);
+	if (tlower_dentry)
+		dput(tlower_dentry);
+	if (tlower_dir_dentry)
+		dput(tlower_dir_dentry);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+static int
+ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+	int err;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	err = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+	if (err || !lower_dentry->d_inode)
+		goto out;
+	err = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (err)
+		goto out;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out:
+	unlock_dir(lower_dir_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	return err;
+}
+
+static int
+ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		struct inode *new_dir, struct dentry *new_dentry)
+{
+	int err;
+	struct dentry *lower_old_dentry;
+	struct dentry *lower_new_dentry;
+	struct dentry *lower_old_dir_dentry;
+	struct dentry *lower_new_dir_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_old_dentry = ecryptfs_lower_dentry(old_dentry);
+	lower_new_dentry = ecryptfs_lower_dentry(new_dentry);
+	dget(lower_old_dentry);
+	dget(lower_new_dentry);
+	lower_old_dir_dentry = dget_parent(lower_old_dentry);
+	lower_new_dir_dentry = dget_parent(lower_new_dentry);
+	lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+	err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
+			 lower_new_dir_dentry->d_inode, lower_new_dentry);
+	if (err)
+		goto out_lock;
+	ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+	if (new_dir != old_dir)
+		ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+out_lock:
+	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+	dput(lower_new_dentry);
+	dput(lower_old_dentry);
+	return err;
+}
+
+static int
+ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
+{
+	int err;
+	struct dentry *lower_dentry;
+	char *decoded_name;
+	char *lower_buf;
+	mm_segment_t old_fs;
+	struct ecryptfs_crypt_stats *crypt_stats;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	if (!lower_dentry->d_inode->i_op ||
+	    !lower_dentry->d_inode->i_op->readlink) {
+		err = -EINVAL;
+		goto out;
+	}
+	/* Released in this function */
+	lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+	if (lower_buf == NULL) {
+		ecryptfs_printk(0, KERN_ERR, "Out of memory\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ecryptfs_printk(1, KERN_NOTICE, "Calling readlink w/ "
+			"lower_dentry->d_name.name = [%s]\n",
+			lower_dentry->d_name.name);
+	err = lower_dentry->d_inode->i_op->readlink(lower_dentry, 
+						    (char __user *)lower_buf,
+						    bufsiz);
+	set_fs(old_fs);
+	if (err >= 0) {
+		crypt_stats = NULL;
+		err = ecryptfs_decode_filename(lower_buf, err,
+					       &decoded_name,
+					       ECRYPTFS_DO_DOTS, crypt_stats);
+		if (err == -ENOMEM)
+			goto out_free_lower_buf;
+		if (err > 0) {
+			ecryptfs_printk(1, KERN_NOTICE, "Copying [%d] bytes "
+					"to userspace: [%*s]\n", err, err,
+					decoded_name);
+			if (copy_to_user(buf, decoded_name, err))
+				err = -EFAULT;
+		}
+		kfree(decoded_name);
+		ecryptfs_copy_attr_atime(dentry->d_inode,
+					 lower_dentry->d_inode);
+	}
+out_free_lower_buf:
+	kfree(lower_buf);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *buf;
+	int len = PAGE_SIZE, rc;
+	mm_segment_t old_fs;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name.name = [%s]\n",
+			dentry->d_name.name);
+	/* Released in ecryptfs_put_link(); only release here on error */
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ecryptfs_printk(1, KERN_NOTICE, "Calling readlink w/ "
+			"dentry->d_name.name = [%s]\n", dentry->d_name.name);
+	rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
+	buf[rc] = '\0';
+	set_fs(old_fs);
+	if (rc < 0)
+		goto out_free;
+	rc = 0;
+	nd_set_link(nd, buf);
+	goto out;
+out_free:
+	kfree(buf);
+out:
+	return ERR_PTR(rc);
+}
+
+static inline void
+ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+	/* Free the char* */
+	kfree(nd_get_link(nd));
+}
+
+/**
+ * Calculate the requried size of the lower file based on the specified size
+ * of the upper file. This calculation is based on the number of headers in
+ * the underlying file, the number of records (IV/HMAC/IV+HMAC) per page
+ * that can be stored, and the extent size of the underlying file (page size).
+ *
+ * @param crypt_stats crypt_stats associated with file
+ * @param upper_size size of the upper file
+ * @return calculated size of the lower file.
+ */
+static loff_t
+upper_size_to_lower_size(struct ecryptfs_crypt_stats *crypt_stats,
+			 loff_t upper_size)
+{
+	int upper_idx = 0;
+	int lower_idx;
+	loff_t lower_size = upper_size;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; upper_size = [%lld]\n",
+			upper_size);
+	/* TODO: Does this need to be based on the extent size? */
+	if (likely(upper_size > 0))
+		upper_idx = (upper_size - 1) >> PAGE_CACHE_SHIFT;
+	else if (!upper_size)
+		upper_idx = 0;
+	else /* Sanity check, size shouldn't be negative */
+		BUG();
+	lower_idx = ecryptfs_pg_idx_to_lwr_pg_idx(crypt_stats, upper_idx);
+	lower_size = ((lower_idx + 1) << PAGE_CACHE_SHIFT);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; lower_size = [%lld]\n",
+			lower_size);
+	return lower_size;
+}
+
+/**
+ * Function to handle truncations modifying the size of the file. Note
+ * that the file sizes are interpolated. When expanding, we are simply
+ * writing strings of 0's out. When truncating, we need to modify the
+ * underlying file size accordingly to the page index interpolations.
+ *
+ * N.B. No claims are made about integrety of the encrypted data when
+ * 	shrinking a file. (But its probably going to be lost)
+ *
+ * TODO: Support holes. Should we also be supporting preservation of
+ * 	 the encrypted data?
+ *
+ * @param dentry	The ecryptfs layer dentry
+ * @param new_length	The length to expand the file to
+ * @return		Zero on success; non-zero otherwise
+ */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+{
+	int rc = 0;
+	struct inode *inode = dentry->d_inode;
+	struct dentry *lower_dentry;
+	struct file fake_ecryptfs_file, *lower_file = NULL;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	loff_t i_size = i_size_read(inode);
+	loff_t lower_size_before_truncate;
+	loff_t lower_size_after_truncate;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry = [%p], new_length = "
+			"[%lld], i_size_read(inode) = [%lld]\n",
+			dentry, new_length, i_size);
+	/* Sanity checks */
+	if (unlikely((new_length == i_size)))
+		goto out;
+	crypt_stats = &ECRYPTFS_INODE_TO_PRIVATE(dentry->d_inode)->crypt_stats;
+	if (unlikely(!crypt_stats)) {
+		ecryptfs_printk(0, KERN_ERR, "NULL crypt_stats on dentry with "
+				"d_name.name = [%s]\n", dentry->d_name.name);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Set up a fake ecryptfs file, this is used to interface with the file
+	 * in the underlying filesystem so that the truncation has an effect
+	 * there as well. */
+	memset(&fake_ecryptfs_file, 0, sizeof(struct file));
+	fake_ecryptfs_file.f_dentry = dentry;
+	/* Released at out_free: */
+	ECRYPTFS_FILE_TO_PRIVATE_SM(&fake_ecryptfs_file) =
+		kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+	if (unlikely(!ECRYPTFS_FILE_TO_PRIVATE(&fake_ecryptfs_file))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	/* This dget & mntget is released through fput at out_fput: */
+	dget(lower_dentry);
+	mntget(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt);
+	lower_file = dentry_open(
+		lower_dentry,
+		ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt, O_RDWR);
+	if (unlikely(IS_ERR(lower_file))) {
+		rc = PTR_ERR(lower_file);
+		goto out_free;
+	}
+	ECRYPTFS_FILE_TO_LOWER(&fake_ecryptfs_file) = lower_file;
+
+	/* Switch on growing or shrinking file */
+	if (new_length > i_size) {
+		rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR,
+					"Problem with fill_zeros\n");
+			goto out_fput;
+		}
+		i_size_write(inode, new_length);
+		rc = ecryptfs_write_inode_size_to_header(lower_file,
+							 lower_dentry->d_inode,
+							 inode);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR,
+					"Problem with ecryptfs_write"
+					"_inode_size\n");
+			goto out_fput;
+		}
+	} else {		/* new_length < i_size_read(inode) */
+		vmtruncate(inode, new_length);
+		ecryptfs_write_inode_size_to_header(lower_file,
+						    lower_dentry->d_inode,
+						    inode);
+		/* We are reducing the size of the ecryptfs file, and need to
+		 * know if we need to reduce the size of the lower file. */
+		lower_size_before_truncate =
+		    upper_size_to_lower_size(crypt_stats, i_size);
+		lower_size_after_truncate =
+		    upper_size_to_lower_size(crypt_stats, new_length);
+		if (lower_size_after_truncate < lower_size_before_truncate)
+			vmtruncate(lower_dentry->d_inode,
+				   lower_size_after_truncate);
+	}
+	/* Update the access times */
+	lower_dentry->d_inode->i_mtime = CURRENT_TIME;
+	lower_dentry->d_inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+out_fput:
+	/* TODO: Determine which of these need to really be called.
+	 * filp_close() will call fput(), but do we need to do the extra work
+	 * that filp_close() provides?
+	 if (lower_file)
+	 filp_close(lower_file, NULL);
+	 */
+	fput(lower_file);
+out_free:
+	if (ECRYPTFS_FILE_TO_PRIVATE(&fake_ecryptfs_file))
+		kmem_cache_free(ecryptfs_file_info_cache,
+				ECRYPTFS_FILE_TO_PRIVATE(&fake_ecryptfs_file));
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static int
+ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	struct inode *lower_inode;
+	int rc = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; inode = [%p], mask=[%d], nd ="
+			"[%p]\n", inode, mask, nd);
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	if (nd)
+		ecryptfs_printk(1, KERN_NOTICE, "nd->dentry = [%p]\n",
+				nd->dentry);
+	rc = permission(lower_inode, mask, nd);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Updates the metadata of an inode. If the update is to the size
+ * i.e. truncation, then ecryptfs_truncate will handle the size modification
+ * of both the ecryptfs inode and the lower inode.
+ * 
+ * All other metadata changes will be passed right to the lower filesystem,
+ * and we will just update our inode to look like the lower.
+ *
+ * @param dentry	dentry handle to the inode to modify
+ * @param ia		structure with flags of what to change and values
+ */
+static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+	int err = 0;
+	struct dentry *lower_dentry;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dentry->d_name.name = [%s]\n",
+			dentry->d_name.name);
+	crypt_stats = &ECRYPTFS_INODE_TO_PRIVATE(dentry->d_inode)->crypt_stats;
+	lower_dentry = ecryptfs_lower_dentry(dentry);
+	inode = dentry->d_inode;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	if (ia->ia_valid & ATTR_SIZE) {
+		ecryptfs_printk(1, KERN_NOTICE,
+				"ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
+				ia->ia_valid, ATTR_SIZE);
+		err = ecryptfs_truncate(dentry, ia->ia_size);
+		/* ecryptfs_truncate handles resizing of the lower file */
+		ia->ia_valid &= ~ATTR_SIZE;
+		ecryptfs_printk(1, KERN_NOTICE, "ia->ia_valid = [%x]\n",
+				ia->ia_valid);
+		if (err < 0)
+			goto out;
+	}
+	err = notify_change(lower_dentry, ia);
+out:
+	ecryptfs_copy_attr_all(inode, lower_inode);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n");
+	return err;
+}
+
+struct inode_operations ecryptfs_symlink_iops = {
+	.readlink = ecryptfs_readlink,
+	.follow_link = ecryptfs_follow_link,
+	.put_link = ecryptfs_put_link,
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+};
+
+struct inode_operations ecryptfs_dir_iops = {
+	.create = ecryptfs_create,
+	.lookup = ecryptfs_lookup,
+	.link = ecryptfs_link,
+	.unlink = ecryptfs_unlink,
+	.symlink = ecryptfs_symlink,
+	.mkdir = ecryptfs_mkdir,
+	.rmdir = ecryptfs_rmdir,
+	.mknod = ecryptfs_mknod,
+	.rename = ecryptfs_rename,
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+};
+
+struct inode_operations ecryptfs_main_iops = {
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+};
diff -urN oldtree/fs/ecryptfs/keystore.c newtree/fs/ecryptfs/keystore.c
--- oldtree/fs/ecryptfs/keystore.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/keystore.c	2006-02-18 17:24:58.722095440 +0000
@@ -0,0 +1,820 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * In-kernel key management code.  Includes functions to parse and
+ * write authentication token-related packets with the underlying
+ * file.
+ *
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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/string.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * request_key returned an error instead of a valid key address;
+ * determine the type of error, make appropriate log entries, and
+ * return an error code.
+ */
+int process_request_key_err(long err_code)
+{
+	int rc = 0;
+
+	switch (err_code) {
+	case ENOKEY:
+		ecryptfs_printk(0, KERN_WARNING, "No key\n");
+		rc = -ENOENT;
+		break;
+	case EKEYEXPIRED:
+		ecryptfs_printk(0, KERN_WARNING, "Key expired\n");
+		rc = -ETIME;
+		break;
+	case EKEYREVOKED:
+		ecryptfs_printk(0, KERN_WARNING, "Key revoked\n");
+		rc = -EINVAL;
+		break;
+	default:
+		ecryptfs_printk(0, KERN_WARNING, "Unknown error code: "
+				"[%lu]\n", err_code);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
+{
+	char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
+	char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+	ecryptfs_printk(1, KERN_NOTICE, "Auth tok at mem loc [%p]:\n",
+			auth_tok);
+	ecryptfs_printk(1, KERN_NOTICE, " * instanceof = [%d]\n",
+			auth_tok->instanceof);
+	ecryptfs_printk(1, KERN_NOTICE, " * instantiated = [%d]\n",
+			auth_tok->instantiated);
+	switch (auth_tok->instanceof) {
+	case ECRYPTFS_PASSWORD:
+		ecryptfs_printk(1, KERN_NOTICE, " * password = [%s]\n",
+				auth_tok->token.password.password);
+		ecryptfs_printk(1, KERN_NOTICE, " * password_size = [%d]\n",
+				auth_tok->token.password.password_size);
+		ecryptfs_to_hex(salt, auth_tok->token.password.salt,
+				ECRYPTFS_SALT_SIZE);
+		salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
+		ecryptfs_printk(1, KERN_NOTICE, " * salt = [%s]\n", salt);
+		ecryptfs_printk(1, KERN_NOTICE, " * saltless = [%d]\n",
+				auth_tok->token.password.saltless);
+		memcpy(sig, auth_tok->token.password.signature,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+		ecryptfs_printk(1, KERN_NOTICE, " * signature = [%s]\n", sig);
+		break;
+	case ECRYPTFS_PRIVATE_KEY:
+		ecryptfs_printk(1, KERN_NOTICE, " * (NO PRIVATE KEY SUPPORT "
+				"IN ECRYPTFS VERSION 0.1)\n");
+		break;
+	default:
+		ecryptfs_printk(1, KERN_NOTICE, " * Unrecognized instanceof\n");
+	}
+	ecryptfs_printk(1, KERN_NOTICE, " * session_key.flags = [0x%x]\n",
+			auth_tok->session_key.flags);
+	if (auth_tok->session_key.flags
+	    & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
+		ecryptfs_printk(1, KERN_NOTICE,
+				" * Userspace decrypt request set\n");
+	if (auth_tok->session_key.flags
+	    & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
+		ecryptfs_printk(1, KERN_NOTICE,
+				" * Userspace encrypt request set\n");
+	if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
+		ecryptfs_printk(1, KERN_NOTICE, " * Contains decrypted key\n");
+		ecryptfs_printk(1, KERN_NOTICE,
+				" * session_key.decrypted_key_size = [0x%x]\n",
+				auth_tok->session_key.decrypted_key_size);
+		ecryptfs_printk(1, KERN_NOTICE, " * Decrypted session key "
+				"dump:\n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
+					  ECRYPTFS_DEFAULT_KEY_BYTES);
+	}
+	if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
+		ecryptfs_printk(1, KERN_NOTICE, " * Contains encrypted key\n");
+		ecryptfs_printk(1, KERN_NOTICE,
+				" * session_key.encrypted_key_size = [0x%x]\n",
+				auth_tok->session_key.encrypted_key_size);
+		ecryptfs_printk(1, KERN_NOTICE, " * Encrypted session key "
+				"dump:\n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
+					  auth_tok->session_key.
+					  encrypted_key_size);
+	}
+}
+
+static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
+{
+	struct list_head *walker;
+	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	walker = auth_tok_list_head->next;
+	while (walker != auth_tok_list_head) {
+		auth_tok_list_item =
+		    list_entry(walker, struct ecryptfs_auth_tok_list_item,
+			       list);
+		walker = auth_tok_list_item->list.next;
+		kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+				auth_tok_list_item);
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+kmem_cache_t *ecryptfs_auth_tok_list_item_cache;
+
+/**
+ * @return Zero on success
+ */
+static int parse_packet_length(unsigned char *data, int *offset, int *size)
+{
+	int rc = 0;
+
+	if (data[(*offset)] < 192) {
+		/* One-byte length */
+		(*size) = data[(*offset)++];
+	} else if (data[(*offset)] < 224) {
+		/* Two-byte length */
+		(*size) = ((data[(*offset)++] - 192) * 256);
+		(*size) += (data[(*offset)++] + 192);
+	} else if (data[(*offset)] == 255) {
+		/* Three-byte length; we're not supposed to see this */
+		ecryptfs_printk(0, KERN_ERR, "Three-byte packet length not "
+				"supported\n");
+		rc = -EINVAL;
+		goto out;
+	} else {
+		ecryptfs_printk(0, KERN_ERR, "Error parsing packet length\n");
+		rc = -EINVAL;
+		goto out;
+	}
+out:
+	return rc;
+}
+
+static int write_packet_length(char *dest, int *dest_offset, int size)
+{
+	int rc = 0;
+
+	if (size < 192) {
+		dest[(*dest_offset)] = size;
+		(*dest_offset)++;
+	} else if (size < 65536) {
+		dest[(*dest_offset)] = (((size - 192) / 256) + 192);
+		(*dest_offset)++;
+		dest[(*dest_offset)] = ((size - 192) % 256);
+		(*dest_offset)++;
+	} else {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_WARNING,
+				"Unsupported packet size: [%d]\n", size);
+	}
+	return rc;
+}
+
+/**
+ * Passphrase packet.
+ *
+ * @return New offset in the packet set page; error value on error.
+ */
+static int
+parse_tag_3_packet(struct ecryptfs_crypt_stats *crypt_stats,
+		   unsigned char *data, struct list_head *auth_tok_list)
+{
+	int i = 0;
+	int rc = 0;
+	int body_size = 0;
+	struct ecryptfs_auth_tok *auth_tok;
+	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (data[i++] != 0x8c) {
+		ecryptfs_printk(0, KERN_ERR, "Enter w/ first byte != 0x8c\n");
+		rc = -EINVAL;
+		goto out_no_mem;
+	}
+	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
+	 * at end of function upon failure */
+	auth_tok_list_item =
+	    kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache,
+			     SLAB_KERNEL);
+	if (!auth_tok_list_item) {
+		ecryptfs_printk(0, KERN_ERR, "Unable to allocate memory\n");
+		rc = -ENOMEM;
+		goto out_no_mem;
+	}
+	auth_tok = &auth_tok_list_item->auth_tok;
+	memset(auth_tok, 0, sizeof(struct ecryptfs_auth_tok));
+	/* TODO: Make *sure* it's encrypted; do this w/ policy tokens.
+	 * Actually, this is probably not the right place to set this
+	 * flag. If the eCryptfs marker matches, then we probably have
+	 * a real tag 3 packet, and hence the file is most likely
+	 * encrypted. */
+	rc = parse_packet_length(data, &i, &body_size);
+	if (rc)
+		goto out;
+	auth_tok->session_key.encrypted_key_size =
+	    body_size - (0x05 + ECRYPTFS_SALT_SIZE);
+	ecryptfs_printk(1, KERN_NOTICE, "Encrypted key size = [%d]\n",
+			auth_tok->session_key.encrypted_key_size);
+	if (data[i++] != 0x04) {
+		ecryptfs_printk(1, KERN_NOTICE, "Unknown version number "
+				"[%d]\n", data[i - 1]);
+		rc = -EINVAL;
+		goto out;
+	}
+	ecryptfs_cipher_code_to_string(crypt_stats->cipher, (u16)data[i]);
+	switch(data[i++]) {
+	case 0x07:
+		crypt_stats->key_size_bits = 128;
+		break;
+	case 0x08:
+		crypt_stats->key_size_bits = 192;
+		break;
+	case 0x09:
+		crypt_stats->key_size_bits = 256;
+		break;
+	}
+	ecryptfs_init_crypt_ctx(crypt_stats);
+	if (data[i++] != 0x03) {
+		ecryptfs_printk(0, KERN_ERR, "Only S2K ID 3 is currently "
+				"supported\n");
+		rc = -ENOSYS;
+		goto out;
+	}
+	/* TODO: finish the hash mapping */
+	switch (data[i++]) {
+	case 0x01:
+		/* Choose MD5 */
+		memcpy(auth_tok->token.password.salt, &data[i],
+		       ECRYPTFS_SALT_SIZE);
+		i += ECRYPTFS_SALT_SIZE;
+		auth_tok->token.password.hash_iterations =
+		    ((u32) 16 + (data[i] & 15)) << ((data[i] >> 4) + 6);
+		i++;
+		memcpy(auth_tok->session_key.encrypted_key, &data[i],
+		       auth_tok->session_key.encrypted_key_size);
+		i += auth_tok->session_key.encrypted_key_size;
+		auth_tok->session_key.flags &= ~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+		auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
+		auth_tok->token.password.hash_algo = 0x01;
+		break;
+	default:
+		ecryptfs_printk(0, KERN_ERR, "Unsupported hash algorithm: "
+				"[%d]\n", data[i - 1]);
+		rc = -ENOSYS;
+		goto out;
+	}
+	/* TODO: Use the keyring */
+	auth_tok->uid = current->uid;
+	auth_tok->instanceof = ECRYPTFS_PASSWORD;
+	if (data[i++] != 0xed) {
+		ecryptfs_printk(0, KERN_ERR, "No (ecryptfs-specific) literal "
+				"packet containing authentication token "
+				"signature found after tag 3 packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	if (data[i++] != (ECRYPTFS_SIG_SIZE + 13)) {
+		ecryptfs_printk(0, KERN_ERR, "Unrecognizable packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	if (data[i++] != 0x62) {
+		ecryptfs_printk(0, KERN_ERR, "Unrecognizable packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	if (data[i++] != 0x08) {
+		ecryptfs_printk(0, KERN_ERR, "Unrecognizable packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	i += 12;		/* We don't care about the filename or the timestamp */
+	/* TODO: Parametarize; we might actually want userspace to
+	 * decrypt the session key. */
+	auth_tok->session_key.flags &=
+	    ~ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT;
+	auth_tok->session_key.flags &=
+	    ~ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT;
+	ecryptfs_to_hex(auth_tok->token.password.signature, &data[i],
+			ECRYPTFS_SIG_SIZE);
+	auth_tok->token.password.signature[ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
+	rc = i;
+	list_add(&auth_tok_list_item->list, auth_tok_list);
+	crypt_stats->encrypted = 1;
+	goto out_success;
+out:
+	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+			auth_tok_list_item);
+out_no_mem:
+out_success:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Decrypt the session key with the given auth_tok.
+ *
+ * TODO: Performance: This is a good candidate for optimization.
+ *
+ * @param auth_tok
+ * @return 0 on success; non-zero error otherwise
+ */
+static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+			       struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int rc = 0;
+	struct ecryptfs_password *password_s_ptr;
+	struct crypto_tfm *tfm = NULL;
+	struct scatterlist src_sg[2], dst_sg[2];
+	/* TODO: Use virt_to_scatterlist for these */
+	char *encrypted_session_key;
+	char *session_key;
+
+	password_s_ptr = &auth_tok->token.password;
+	if (password_s_ptr->session_key_encryption_key_set)
+		ecryptfs_printk(1, KERN_NOTICE, "Session key encryption key "
+				"set; skipping key generation\n");
+	ecryptfs_printk(1, KERN_NOTICE, "Session key encryption key (size [%d])"
+			":\n", password_s_ptr->session_key_encryption_key_size);
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key,
+				  password_s_ptr->
+				  session_key_encryption_key_size);
+	tfm = crypto_alloc_tfm(crypt_stats->cipher, 0);
+	if (!tfm) {
+		ecryptfs_printk(0, KERN_ERR, "Error allocating crypto "
+				"context\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	crypto_cipher_setkey(tfm, password_s_ptr->session_key_encryption_key,
+			     password_s_ptr->session_key_encryption_key_size);
+	/* TODO: virt_to_scatterlist */
+	encrypted_session_key = (char *)__get_free_page(GFP_KERNEL);
+	if (!encrypted_session_key) {
+		ecryptfs_printk(0, KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	session_key = (char *)__get_free_page(GFP_KERNEL);
+	if (!session_key) {
+		kfree(encrypted_session_key);
+		ecryptfs_printk(0, KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key,
+	       auth_tok->session_key.encrypted_key_size);
+	src_sg[0].page = virt_to_page(encrypted_session_key);
+	src_sg[0].offset = 0;
+	/* TODO: key_size < PAGE_CACHE_SIZE */
+	src_sg[0].length = auth_tok->session_key.encrypted_key_size;
+	dst_sg[0].page = virt_to_page(session_key);
+	dst_sg[0].offset = 0;
+	auth_tok->session_key.decrypted_key_size =
+	    auth_tok->session_key.encrypted_key_size;
+	dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
+	/* TODO: Handle error condition */
+	crypto_cipher_decrypt(tfm, dst_sg, src_sg,
+			      auth_tok->session_key.encrypted_key_size);
+	auth_tok->session_key.decrypted_key_size =
+	    auth_tok->session_key.encrypted_key_size;
+	memcpy(auth_tok->session_key.decrypted_key, session_key,
+	       auth_tok->session_key.decrypted_key_size);
+	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+	memcpy(crypt_stats->key, auth_tok->session_key.decrypted_key,
+	       auth_tok->session_key.decrypted_key_size);
+	crypt_stats->key_valid = 1;
+	crypt_stats->key_size_bits =
+	    auth_tok->session_key.decrypted_key_size * 8;
+	ecryptfs_printk(1, KERN_NOTICE, "Decrypted session key:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	free_page((unsigned long)encrypted_session_key);
+	free_page((unsigned long)session_key);
+out:
+	if (tfm)
+		crypto_free_tfm(tfm);
+	return rc;
+}
+
+/**
+ * N.B. This comment is applicable to 0.2 release (and later) only.
+ * Extract the authentication token signatures.  eCryptfs expects this
+ * function to recover the symmetric key of the crypt_stats structure
+ * if at all possible, given the current packet set.  Authentication
+ * tokens are composed of the tokens themselves and their descriptors.
+ * It is possible to have an authentication token object in the
+ * keyring that only has a descriptor and not a token component.  Each
+ * eCryptfs file header contains a concatenation of descriptors.  For
+ * each descriptor, this function assures that an authentication token
+ * object is instantiated in the keyring.  This instantiation takes
+ * place in the request_key callout application.  Thus, the callout
+ * application requires the complete descriptor.  The crypt_stats
+ * object contains a set of descriptors that apply to this file.  When
+ * the headers are written out, they are re-constructed from the set
+ * of authentication token descriptors.
+ *
+ * If at any point we have a problem parsing the packets, we will -EIO and
+ * just bail out.
+ *
+ * GOAL: Get crypt_stats to have the file's session key.
+ * 
+ * @param dest	The header page in memory
+ * @param version Version of file format, to guide parsing behavior
+ * @return	0 if a valid authentication token was retrieved and processed;
+ * 		negative value for file not encrypted or for error conditions
+ */
+int ecryptfs_parse_packet_set(unsigned char *dest,
+			      struct ecryptfs_crypt_stats *crypt_stats,
+			      struct dentry *ecryptfs_dentry, int version)
+{
+	int i = 0;
+	int rc = 0;
+	int found_auth_tok = 0;
+	int next_packet_is_auth_tok_packet;
+	char sig[ECRYPTFS_SIG_SIZE_HEX];
+	struct list_head auth_tok_list;
+	struct list_head *walker;
+	struct ecryptfs_auth_tok *chosen_auth_tok = NULL;
+	struct ecryptfs_mount_crypt_stats *mount_crypt_stats =
+	    &(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(
+		      ecryptfs_dentry->d_sb)->mount_crypt_stats);
+	struct ecryptfs_auth_tok *candidate_auth_tok = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	ecryptfs_set_default_sizes(crypt_stats);
+	INIT_LIST_HEAD(&auth_tok_list);
+
+	/* Parse the header to find as many packets as we can, these will be
+	 * added the our &auth_tok_list */
+	next_packet_is_auth_tok_packet = 1;
+	while (next_packet_is_auth_tok_packet)
+		switch (dest[i]) {
+		case 0x8c:	/* tag 3 packet; s2k */
+			rc = parse_tag_3_packet(crypt_stats,
+						(unsigned char *)&dest[i],
+						&auth_tok_list);
+			if (rc != -EINVAL && rc != -ENOMEM) {
+				i += rc;
+				rc = 0;
+			} else {
+				ecryptfs_printk(0, KERN_ERR, "Error parsing "
+						"tag 3 packet\n");
+				rc = -EIO;
+				goto out_wipe_list;
+			}
+			break;
+		default:
+			ecryptfs_printk(1, KERN_NOTICE, "No packet at offset "
+					"[%d] of the file header; hex value of "
+					"character is [0x%.2x]\n", i, dest[i]);
+			next_packet_is_auth_tok_packet = 0;
+		}
+	if (list_empty(&auth_tok_list)) {
+		rc = -EINVAL;	/* Do not support non-encrypted files */
+		goto out;
+	}
+
+	/* If we have a global auth tok, then use it should be tried */
+	if (mount_crypt_stats->global_auth_tok) {
+		memcpy(sig, mount_crypt_stats->global_auth_tok_sig,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		chosen_auth_tok = mount_crypt_stats->global_auth_tok;
+	} else
+		BUG();		/* This should not be the case in 0.1 release */
+	/* Scan list to see if our chosen_auth_tok works */
+	list_for_each(walker, &auth_tok_list) {
+		struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+		auth_tok_list_item =
+		    list_entry(walker, struct ecryptfs_auth_tok_list_item,
+			       list);
+		candidate_auth_tok = &auth_tok_list_item->auth_tok;
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(1, KERN_NOTICE,
+					"Considering cadidate auth tok:\n");
+			ecryptfs_dump_auth_tok(candidate_auth_tok);
+		}
+		/* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */
+		if ((candidate_auth_tok->instanceof == ECRYPTFS_PASSWORD) &&
+		    !strncmp(candidate_auth_tok->token.password.signature,
+			     sig, ECRYPTFS_SIG_SIZE_HEX)) {
+			found_auth_tok = 1;
+			goto leave_list;
+			/* TODO: Transfer the common salt into the
+			 * crypt_stats salt */
+		}
+	}
+leave_list:
+	if (!found_auth_tok) {
+		ecryptfs_printk(0, KERN_ERR, "Could not find authentication "
+				"token on temporary list for sig [%.*s]\n",
+				ECRYPTFS_SIG_SIZE_HEX, sig);
+		goto out_wipe_list;
+	} else {
+		memcpy(&(candidate_auth_tok->token.password),
+		       &(chosen_auth_tok->token.password),
+		       sizeof(struct ecryptfs_password));
+		decrypt_session_key(candidate_auth_tok, crypt_stats);
+	}
+
+out_wipe_list:
+	wipe_auth_tok_list(&auth_tok_list);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Write passphrase packet
+ *
+ * @param dest Buffer into which to write the packet
+ * @param max Maximum number of bytes that can be writtn
+ * @return Number of bytes written; 0 on error
+ */
+static int
+write_tag_3_packet(char *dest, int dest_offset, int max,
+		   struct ecryptfs_auth_tok *auth_tok,
+		   struct ecryptfs_crypt_stats *crypt_stats)
+{
+	int rc = 0;
+	struct ecryptfs_key_record key_rec;
+	int i;
+	int signature_is_valid = 0;
+	int encrypted_session_key_valid = 0;
+	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+	struct scatterlist dest_sg[2];
+	struct scatterlist src_sg[2];
+	struct crypto_tfm *tfm = NULL;
+	int key_rec_size;
+	int offset_save = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; dest_offset = [%d]\n",
+			dest_offset);
+	/* Check for a valid signature on the auth_tok */
+	for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++)
+		signature_is_valid |= auth_tok->token.password.signature[i];
+	if (!signature_is_valid)
+		BUG();
+	ecryptfs_from_hex(key_rec.sig, auth_tok->token.password.signature,
+			  ECRYPTFS_SIG_SIZE);
+	key_rec.enc_key_size_bits = crypt_stats->key_size_bits;
+	key_rec.type = ECRYPTFS_PACKET_SET_TYPE_PASSWORD;
+
+	encrypted_session_key_valid = 0;
+	if (auth_tok->session_key.encrypted_key_size == 0)
+		auth_tok->session_key.encrypted_key_size =
+		    ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES;
+	for (i = 0; i < auth_tok->session_key.encrypted_key_size; i++)
+		encrypted_session_key_valid |=
+		    auth_tok->session_key.encrypted_key[i];
+	if (auth_tok->session_key.encrypted_key_size == 0) {
+		ecryptfs_printk(0, KERN_WARNING, "auth_tok->session_key."
+				"encrypted_key_size == 0");
+		auth_tok->session_key.encrypted_key_size =
+		    ECRYPTFS_DEFAULT_KEY_BYTES;
+	}
+	if (encrypted_session_key_valid) {
+		memcpy(key_rec.enc_key,
+		       auth_tok->session_key.encrypted_key,
+		       auth_tok->session_key.encrypted_key_size);
+		goto encrypted_session_key_set;
+	}
+	if (auth_tok->token.password.session_key_encryption_key_set) {
+		ecryptfs_printk(1, KERN_NOTICE, "Using previously generated "
+				"session key encryption key of size [%d]\n",
+				auth_tok->token.password.
+				session_key_encryption_key_size);
+		memcpy(session_key_encryption_key,
+		       auth_tok->token.password.session_key_encryption_key,
+		       auth_tok->token.password.
+		       session_key_encryption_key_size);
+		ecryptfs_printk(1, KERN_NOTICE,
+				"Cached session key " "encryption key: \n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(session_key_encryption_key, 16);
+		goto session_key_encryption_key_set;
+	}
+      session_key_encryption_key_set:
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(1, KERN_NOTICE, "Session key encryption key:"
+				"\n");
+		ecryptfs_dump_hex(session_key_encryption_key, 16);
+	}
+	/* Encrypt the key with the key encryption key */
+	/* Set up the scatterlists */
+	rc = virt_to_scatterlist(crypt_stats->key,
+				 crypt_stats->key_size_bits / 8, src_sg, 2);
+	if (!rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error generating scatterlist "
+				"for crypt_stats session key\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	rc = virt_to_scatterlist(key_rec.enc_key,
+				 key_rec.enc_key_size_bits / 8, dest_sg, 2);
+	if (!rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error generating scatterlist "
+				"for crypt_stats encrypted session key\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	/* Initialize the key encryption context */
+	ASSERT(crypt_stats->cipher);
+	if ((tfm = crypto_alloc_tfm(crypt_stats->cipher, 0)) == NULL) {
+		ecryptfs_printk(0, KERN_ERR, "Could not initialize crypto "
+				"context for cipher [%s]\n",
+				crypt_stats->cipher);
+		rc = 0;
+		goto out;
+	}
+	/* Set the key encryption key */
+	rc = crypto_cipher_setkey(tfm, session_key_encryption_key,
+				  ECRYPTFS_DEFAULT_KEY_BYTES);
+	if (rc < 0) {
+		ecryptfs_printk(0, KERN_ERR, "Error setting key for crypto "
+				"context\n");
+		rc = 0;
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Encrypting [%d] bytes of the key\n",
+			crypt_stats->key_size_bits / 8);
+	crypto_cipher_encrypt(tfm, dest_sg, src_sg,
+			      crypt_stats->key_size_bits / 8);
+
+	ecryptfs_printk(1, KERN_NOTICE, "This should be the encrypted key:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(key_rec.enc_key, 
+				  key_rec.enc_key_size_bits / 8);
+encrypted_session_key_set:
+	/* Now we have a valid key_rec.  Append it to the
+	 * key_rec set. */
+	key_rec_size = KEY_REC_SIZE(key_rec);
+	if ((dest_offset + key_rec_size) >= ECRYPTFS_MAX_KEYSET_SIZE) {
+		ecryptfs_printk(0, KERN_ERR, "Keyset too large\n");
+		rc = 0;
+		goto out;
+	}
+	offset_save = dest_offset;
+	if ((dest_offset + 0x05 + ECRYPTFS_SALT_SIZE
+	     + (key_rec.enc_key_size_bits / 8)) >= PAGE_CACHE_SIZE) {
+		ecryptfs_printk(0, KERN_ERR, "Too many authentication tokens; "
+				"cryptfs does not yet support this many\n");
+		rc = 0;
+		goto out;
+	}
+	/* This format is inspired by OpenPGP; see RFC 2440
+	 * packet tag 3 */
+	*(dest + (dest_offset++)) = 0x8c;	/* tag 3 */
+	/* ver+cipher+s2k+hash+salt+iter+enc_key */
+	rc = write_packet_length(dest, &dest_offset,
+				 (0x05 + ECRYPTFS_SALT_SIZE
+				  + (key_rec.enc_key_size_bits / 8)));
+	*(dest + (dest_offset++)) = 0x04;	/* version 4 */
+	
+	rc = ecryptfs_code_for_cipher_string(crypt_stats->cipher);
+	if (rc == 0) {
+		ecryptfs_printk(0, KERN_WARNING, "Unable to generate code for "
+				"cipher [%s]\n", crypt_stats->cipher);
+		goto out;
+	}
+	if (rc == 0x07) {
+		switch (crypt_stats->key_size_bits) {
+		case 128:
+			break;
+		case 192:
+			rc = 0x08;	/* AES-192 */
+			break;
+		case 256:
+			rc = 0x09;	/* AES-256 */
+			break;
+		default:
+			rc = -EINVAL;
+			ecryptfs_printk(0, KERN_WARNING, "Unsupported AES key "
+					"size: [%d]\n", 
+					crypt_stats->key_size_bits);
+			goto out;
+		}		
+	}
+	*(dest + (dest_offset++)) = rc;
+	rc = 0;
+	*(dest + (dest_offset++)) = 0x03;	/* S2K */
+	*(dest + (dest_offset++)) = 0x01;	/* MD5 (TODO) */
+	memcpy((dest + dest_offset), auth_tok->token.password.salt,
+	       ECRYPTFS_SALT_SIZE);
+	dest_offset += ECRYPTFS_SALT_SIZE;	/* salt */
+	*(dest + (dest_offset++)) = 0x60;	/* hash iterations */
+	memcpy((dest + dest_offset), key_rec.enc_key,
+	       key_rec.enc_key_size_bits / 8);
+	dest_offset += (key_rec.enc_key_size_bits / 8);
+	/* Write auth tok signature packet */
+	*(dest + (dest_offset++)) = 0xed;	/* tag 11 */
+	*(dest + (dest_offset++)) = ECRYPTFS_SIG_SIZE + 13;	/* packet
+								 * length */
+	*(dest + (dest_offset++)) = 0x62;	/* binary type */
+	*(dest + (dest_offset++)) = 0x08;	/* filename length */
+	strncpy((dest + dest_offset), "_CONSOLE", 0x08);
+	dest_offset += 0x08;
+	memset((dest + dest_offset), 0, 4);
+	dest_offset += 4;
+	memcpy((dest + dest_offset), key_rec.sig, ECRYPTFS_SIG_SIZE);
+	dest_offset += ECRYPTFS_SIG_SIZE;
+	*(dest + (dest_offset)) = 0x00;	/* NULL terminator */
+	rc = dest_offset;
+out:
+	if (tfm)
+		crypto_free_tfm(tfm);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Generates a key packet set and writes it to the virtual address
+ * passed in.
+ *
+ * @param dest		Page to which to write the key record set
+ * @param crypt_stats	The cryptographic context from which the authentication
+ * 			tokens will be retrieved
+ * @param len           The amount written
+ * @return		Zero on success
+ */
+int
+ecryptfs_generate_key_packet_set(char *dest_base,
+				 struct ecryptfs_crypt_stats *crypt_stats,
+				 struct dentry *ecryptfs_dentry, int *len)
+{
+	int rc = 0;
+	struct ecryptfs_auth_tok *auth_tok;
+	int dest_offset = 0;
+	struct ecryptfs_mount_crypt_stats *mount_crypt_stats =
+	    &(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(
+		      ecryptfs_dentry->d_sb)->mount_crypt_stats);
+	int written;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	(*len) = 0;
+	if (mount_crypt_stats->global_auth_tok) {
+		auth_tok = mount_crypt_stats->global_auth_tok;
+		switch (auth_tok->instanceof) {
+		case ECRYPTFS_PASSWORD:
+			written = write_tag_3_packet(dest_base, dest_offset,
+						     PAGE_CACHE_SIZE, auth_tok,
+						     crypt_stats);
+			break;
+		default:
+			ecryptfs_printk(0, KERN_WARNING, "Unknown "
+					"authentication token type [%d]\n",
+					auth_tok->instanceof);
+			rc = -EINVAL;
+			goto out;
+		}
+		if (written == 0) {
+			ecryptfs_printk(1, KERN_WARNING, "Error writing "
+					"authentication token packet with sig "
+					"= [%s]\n",
+					mount_crypt_stats->global_auth_tok_sig);
+			rc = -EIO;
+			goto out;
+		} else {
+			dest_offset += written;
+			(*len) += written;
+		}
+	} else
+		BUG();
+      out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
diff -urN oldtree/fs/ecryptfs/main.c newtree/fs/ecryptfs/main.c
--- oldtree/fs/ecryptfs/main.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/main.c	2006-02-18 17:24:58.724095136 +0000
@@ -0,0 +1,734 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2003 Erez Zadok
+ * Copyright (c) 2001-2003 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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/dcache.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/parser.h>
+#include <keys/user-type.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * Module parameter that defines the ecryptfs_verbosity level.
+ */
+int ecryptfs_verbosity = 1;
+
+module_param(ecryptfs_verbosity, int, 0);
+MODULE_PARM_DESC(ecryptfs_verbosity,
+		 "Initial verbosity level (0 or 1; defaults to "
+		 "0, which is Quiet)");
+
+void __ecryptfs_printk(int verb, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	if ((ecryptfs_verbosity >= verb) && printk_ratelimit())
+		vprintk(fmt, args);
+	va_end(args);
+}
+
+/**
+ * Interposes upper and lower dentries.
+ * This function will call an ecryptfs_inode into existance through the call to
+ * iget(sb, lower_inode->i_ino).
+ * 
+ * @param lower_dentry	existing dentry in the lower filesystem
+ * @param dentry	ecryptfs' dentry
+ * @param sb		eCryptfs's super_block
+ * @param flag		If set to true, then d_add is called, else d_instantiate
+ * 			is called.
+ * @return		Zero on success; non-zero otherwise
+ */
+int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
+		       struct super_block *sb, int flag)
+{
+	struct inode *lower_inode;
+	int err = 0;
+	struct inode *inode;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; lower_dentry = [%p], "
+			"lower_dentry->d_name.name = [%s], dentry = "
+			"[%p], dentry->d_name.name = [%s], sb = [%p]; "
+			"flag = [%.4x]; lower_dentry->d_count "
+			"= [%d]; dentry->d_count = [%d]\n", lower_dentry,
+			lower_dentry->d_name.name, dentry, dentry->d_name.name,
+			sb, flag, atomic_read(&lower_dentry->d_count),
+			atomic_read(&dentry->d_count));
+	lower_inode = lower_dentry->d_inode;
+	if (lower_inode->i_sb != ECRYPTFS_SUPERBLOCK_TO_LOWER(sb)) {
+		err = -EXDEV;
+		goto out;
+	}
+	inode = iget(sb, lower_inode->i_ino);
+	if (!inode) {
+		err = -EACCES;
+		goto out;
+	}
+	/* This check is required here because if we failed to allocated the
+	 * required space for an inode_info_cache struct, then the only way
+	 * we know we failed, is by the pointer being NULL */
+	if (!ECRYPTFS_INODE_TO_PRIVATE(inode)) {
+		ecryptfs_printk(1, KERN_ERR, "Out of memory. Failure to "
+				"allocate memory in ecryptfs_read_inode.\n");
+		err = -ENOMEM;
+		BUG();
+		goto out;
+	}
+
+	if (NULL == ECRYPTFS_INODE_TO_LOWER(inode)) {
+		ECRYPTFS_INODE_TO_LOWER(inode) = igrab(lower_inode);
+		/* If we are still NULL at this point, igrab failed.
+		 * We are _NOT_ supposed to be failing here */
+		if (NULL == ECRYPTFS_INODE_TO_LOWER(inode)) {
+			BUG();
+			err = -EINVAL;
+			goto out;
+		}
+	}
+	if (S_ISLNK(lower_inode->i_mode))
+		inode->i_op = &ecryptfs_symlink_iops;
+	else if (S_ISDIR(lower_inode->i_mode))
+		inode->i_op = &ecryptfs_dir_iops;
+	if (S_ISDIR(lower_inode->i_mode))
+		inode->i_fop = &ecryptfs_dir_fops;
+	/* TODO: Is there a better way to identify if the inode is
+	 * special? */
+	if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
+	    S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
+		init_special_inode(inode, lower_inode->i_mode,
+				   lower_inode->i_rdev);
+	dentry->d_op = &ecryptfs_dops;
+	if (flag)
+		d_add(dentry, inode);
+	else
+		d_instantiate(dentry, inode);
+	ecryptfs_copy_attr_all(inode, lower_inode);
+	/* This size will be overwritten for real files w/ headers and
+	 * other metadata */
+	ecryptfs_copy_inode_size(inode, lower_inode);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = %d\n", err);
+	return err;
+}
+
+/**
+ * For rvalue references; better to just use the macro.
+ */
+inline struct dentry *ecryptfs_lower_dentry(struct dentry *dentry)
+{
+	ASSERT(dentry);
+	return ECRYPTFS_DENTRY_TO_LOWER(dentry);
+}
+
+enum { ecryptfs_opt_sig, ecryptfs_opt_debug, ecryptfs_opt_cipher,
+	ecryptfs_opt_err
+};
+
+static match_table_t tokens = {
+	{ecryptfs_opt_sig, "sig=%s"},
+	{ecryptfs_opt_debug, "debug=%u"},
+	{ecryptfs_opt_cipher, "cipher=%s"},
+	{ecryptfs_opt_err, NULL}
+};
+
+/**
+ * Parse mount options:
+ * debug=N 	   - ecryptfs_verbosity level for debug output
+ * sig=XXX	   - description(signature) of the key to use
+ * 
+ * Returns the dentry object of the lower-level (lower/interposed)
+ * directory; We want to mount our stackable file system on top of
+ * that lower directory.
+ *
+ * N.B. The signature of the key to use must be the description of a key
+ * 	already in the keyring. Mounting will fail if the key can not be
+ * 	found.
+ *
+ * @param sb
+ * @param options
+ * @return Zero on success; non-zero on error
+ */
+static int ecryptfs_parse_options(struct super_block *sb, char *options)
+{
+	char *p;
+	int rc = 0;
+	int sig_set = 0;
+	int cipher_name_set = 0;
+	struct key *auth_tok_key = NULL;
+	struct ecryptfs_auth_tok *auth_tok = NULL;
+	struct ecryptfs_mount_crypt_stats *mount_crypt_stats =
+		&(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb)->mount_crypt_stats);
+	substring_t args[MAX_OPT_ARGS];
+	int token;
+	char *sig_src;
+	char *sig_dst;
+	char *debug_src;
+	char *cipher_name_dst;
+	char *cipher_name_src;
+	int cipher_name_len;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; options = [%s]\n", options);
+	if (!options) {
+		rc = -EINVAL;
+		goto out;
+	}
+	while ((p = strsep(&options, ",")) != NULL) {
+		if (!*p)
+			continue;
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case ecryptfs_opt_sig:
+			sig_src = args[0].from;
+			sig_dst =
+				mount_crypt_stats->global_auth_tok_sig;
+			memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
+			sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+			ecryptfs_printk(1, KERN_NOTICE,
+					"The mount_crypt_stats "
+					"global_auth_tok_sig set to: "
+					"[%s]\n", sig_dst);
+			sig_set = 1;
+			break;
+		case ecryptfs_opt_debug:
+			debug_src = args[0].from;
+			ecryptfs_verbosity =
+				(int)simple_strtol(debug_src, &debug_src,
+						   0);
+			ecryptfs_printk(1, KERN_NOTICE,
+					"Verbosity set to [%d]" "\n",
+					ecryptfs_verbosity);
+			break;
+		case ecryptfs_opt_cipher:
+			cipher_name_src = args[0].from;
+			cipher_name_dst =
+				mount_crypt_stats->
+				global_default_cipher_name;
+			strncpy(cipher_name_dst, cipher_name_src,
+				ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+			ecryptfs_printk(1, KERN_NOTICE,
+					"The mount_crypt_stats "
+					"global_default_cipher_name set to: "
+					"[%s]\n", cipher_name_dst);
+			cipher_name_set = 1;
+			break;
+		case ecryptfs_opt_err:
+		default:
+			ecryptfs_printk(1, KERN_WARNING,
+					"eCryptfs: unrecognized option '%s'\n",
+					options);
+		}
+	}
+	/* Do not support lack of mount-wide signature in 0.1
+	 * release */
+	if (!sig_set) {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "You must supply a valid "
+				"passphrase auth tok signature as a mount "
+				"parameter; see the eCryptfs README\n");
+		goto out;
+	}
+	if (!cipher_name_set) {
+		cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
+		if (unlikely(cipher_name_len 
+			     >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
+			rc = -EINVAL;
+			BUG();
+			goto out;
+		}
+		memcpy(mount_crypt_stats->global_default_cipher_name,
+		       ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
+		mount_crypt_stats->global_default_cipher_name[cipher_name_len]
+		    = '\0';
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Requesting the key with description: "
+			"[%s]\n", mount_crypt_stats->global_auth_tok_sig);
+	/* N.B. The reference to this key is held until umount is done
+	 * The call to key_put is done in ecryptfs_put_super() */
+	auth_tok_key = request_key(&key_type_user,
+				   mount_crypt_stats->global_auth_tok_sig,
+				   NULL);
+	if (!auth_tok_key || IS_ERR(auth_tok_key)) {
+		ecryptfs_printk(0, KERN_ERR, "Could not find key with "
+				"description: [%s]\n",
+				mount_crypt_stats->global_auth_tok_sig);
+		process_request_key_err(PTR_ERR(auth_tok_key));
+		rc = -EINVAL;
+		goto out;
+	}
+	auth_tok = (struct ecryptfs_auth_tok *)KEY_PAYLOAD_DATA(auth_tok_key);
+	if (auth_tok->instanceof != ECRYPTFS_PASSWORD) {
+		ecryptfs_printk(0, KERN_ERR, "Invalid auth_tok structure "
+				"returned from key");
+		rc = -EINVAL;
+		goto out;
+	}
+	mount_crypt_stats->global_auth_tok_key = auth_tok_key;
+	mount_crypt_stats->global_auth_tok = auth_tok;
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+kmem_cache_t *ecryptfs_sb_info_cache;
+
+/**
+ * Preform the cleanup for ecryptfs_read_super()
+ */
+static inline void ecryptfs_cleanup_read_super(struct super_block *sb)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; sb = [%p], sb->s_root = [%p] "
+			"ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb) = [%p] "
+			"sb->s_root.d_name->name = [%s]\n", sb,
+			sb->s_root, ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb),
+			sb->s_root->d_name.name);
+	up_write(&sb->s_umount);
+	deactivate_super(sb);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Sets up what we can of the sb, rest is done in ecryptfs_read_super
+ *
+ * @param sb		The ecryptfs super block
+ * @param raw_data	The options passed to mount
+ * @param silent	Not used but required by function prototype
+ * @return 		Zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
+{
+	int err = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; sb = [%p] raw_data = [%s] "
+			"silent = [%d]\n", sb, (char *)raw_data, silent);
+	/* Released in ecryptfs_put_super() */
+	ECRYPTFS_SUPERBLOCK_TO_PRIVATE_SM(sb) =
+		kmem_cache_alloc(ecryptfs_sb_info_cache, SLAB_KERNEL);
+	if (!ECRYPTFS_SUPERBLOCK_TO_PRIVATE_SM(sb)) {
+		ecryptfs_printk(0, KERN_WARNING, "Out of memory\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb), 0, 
+	       sizeof(struct ecryptfs_sb_info));
+	sb->s_op = &ecryptfs_sops;
+	/* Released through deactivate_super(sb) from get_sb_nodev */
+	sb->s_root = d_alloc(NULL, &(const struct qstr) {
+			     .hash = 0,.name = "/",.len = 1});
+	if (!sb->s_root) {
+		ecryptfs_printk(0, KERN_ERR, "d_alloc failed\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	sb->s_root->d_op = &ecryptfs_dops;
+	sb->s_root->d_sb = sb;
+	sb->s_root->d_parent = sb->s_root;
+	/* Released in d_release when dput(sb->s_root) is called */
+	/* through deactivate_super(sb) from get_sb_nodev() */
+	ECRYPTFS_DENTRY_TO_PRIVATE_SM(sb->s_root) =
+		(struct ecryptfs_dentry_info *)
+		kmem_cache_alloc(ecryptfs_dentry_info_cache, SLAB_KERNEL);
+	if (!ECRYPTFS_DENTRY_TO_PRIVATE_SM(sb->s_root)) {
+		ecryptfs_printk(0, KERN_ERR,
+				"dentry_info_cache alloc failed\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	memset(ECRYPTFS_DENTRY_TO_PRIVATE(sb->s_root), 0,
+	       sizeof(struct ecryptfs_dentry_info));
+	err = 0;
+out:
+	/* Should be able to rely on deactive_super called from get_sb_nodev */
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+/**
+ * Read the super block of the lower filesystem, and use ecryptfs_interpose
+ * to create our initial inode and super block struct
+ */
+static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
+{
+	int err;
+	struct nameidata nd;
+	struct dentry *lower_root;
+
+	memset(&nd, 0, sizeof(struct nameidata));
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; sb = [%p], dev_name = [%s]\n",
+			sb, dev_name);
+	err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+	if (err) {
+		ecryptfs_printk(0, KERN_WARNING, "path_lookup() failed\n");
+		goto out_free;
+	}
+	lower_root = nd.dentry;
+	ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb)->lower_mnt = nd.mnt;
+	if (!lower_root->d_inode) {
+		ecryptfs_printk(0, KERN_WARNING,
+				"No directory to interpose on\n");
+		err = -ENOENT;
+		goto out_free;
+	}
+	ECRYPTFS_SUPERBLOCK_TO_LOWER(sb) = lower_root->d_sb;
+	sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
+	ECRYPTFS_DENTRY_TO_LOWER(sb->s_root) = lower_root;
+	if ((err = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
+		goto out_free;
+	err = 0;
+	goto out;
+out_free:
+	path_release(&nd);
+	ecryptfs_cleanup_read_super(sb);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n", err);
+	return err;
+}
+
+/**
+ * The whole ecryptfs_get_sb process is broken into 4 functions:
+ * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
+ * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
+ *                        with as much information as it can before needing
+ *                        the lower filesystem.
+ * ecryptfs_read_super(): this accesses the lower filesystem and uses
+ *                        ecryptfs_interpolate to perform most of the linking
+ * ecryptfs_interpolate(): links the lower filesystem into ecryptfs 
+ */
+static struct super_block *ecryptfs_get_sb(struct file_system_type *fs_type,
+					   int flags, const char *dev_name,
+					   void *raw_data)
+{
+	int err;
+	struct super_block *sb = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; fs_type = [%p], flags = [%d],"
+			" dev_name = [%s], raw_data = [%s]\n",
+			fs_type, flags, dev_name, (char *)raw_data);
+	sb = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super);
+	if (IS_ERR(sb)) {
+		ecryptfs_printk(0, KERN_ERR, "Getting sb failed. "
+				"sb = [%p]\n", sb);
+		goto out;
+	}
+	err = ecryptfs_parse_options(sb, raw_data);
+	if (err) {
+		sb = ERR_PTR(err);
+		goto out;
+	}
+	err = ecryptfs_read_super(sb, dev_name);
+	if (err) {
+		sb = ERR_PTR(err);
+		ecryptfs_printk(0, KERN_ERR, "Reading sb failed. "
+				"sb = [%p]\n", sb);
+	}
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%p]\n", sb);
+	return sb;
+}
+
+/**
+ * Used to bring the superblock down and free the private data.
+ * Private data is free'd in ecryptfs_put_super()
+ */
+static void ecryptfs_kill_block_super(struct super_block *sb)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; sb = [%p], sb->s_root = [%p] "
+			"ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb) = [%p]\n", sb,
+			sb->s_root, ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb));
+	generic_shutdown_super(sb);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+static struct file_system_type ecryptfs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "ecryptfs",
+	.get_sb = ecryptfs_get_sb,
+	.kill_sb = ecryptfs_kill_block_super,
+	.fs_flags = 0
+};
+
+/**
+ * Initializes the ecryptfs_inode_info_cache when it is created
+ */
+static void
+inode_info_init_once(void *vptr, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+
+/* This provides a means of backing out cache creations out of the kernel
+ * so that we can elegantly fail should we run out of memory.
+ */
+#define ECRYPTFS_AUTH_TOK_LIST_ITEM_CACHE 	0x0001
+#define ECRYPTFS_AUTH_TOK_PKT_SET_CACHE         0x0002
+#define ECRYPTFS_AUTH_TOK_REQUEST_CACHE         0x0004
+#define ECRYPTFS_AUTH_TOK_REQUEST_BLOB_CACHE    0x0008
+#define ECRYPTFS_FILE_INFO_CACHE 		0x0010
+#define ECRYPTFS_DENTRY_INFO_CACHE 		0x0020
+#define ECRYPTFS_INODE_INFO_CACHE 		0x0040
+#define ECRYPTFS_SB_INFO_CACHE 			0x0080
+#define ECRYPTFS_HEADER_CACHE_0 		0x0100
+#define ECRYPTFS_HEADER_CACHE_1 		0x0200
+#define ECRYPTFS_HEADER_CACHE_2 		0x0400
+#define ECRYPTFS_LOWER_PAGE_CACHE 		0x0800
+#define ECRYPTFS_CACHE_CREATION_SUCCESS		0x0FF1
+
+static short ecryptfs_allocated_caches;
+
+/**
+ * @return Zero on success; non-zero otherwise
+ *
+ * Sets ecryptfs_allocated_caches with flags so that we can
+ * free created caches should we run out of memory during
+ * creation period.
+ *
+ * The overhead for doing this is offset by the fact that we
+ * only do this once, and that should there be insufficient
+ * memory, then we can elegantly fail, and not leave extra
+ * caches around, or worse, panic the kernel trying to free
+ * something that's not there.
+ */
+static int ecryptfs_init_kmem_caches(void)
+{
+	int rc = 0;
+
+	ecryptfs_auth_tok_list_item_cache =
+	    kmem_cache_create("ecryptfs_auth_tok_list_item",
+			      sizeof(struct ecryptfs_auth_tok_list_item),
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_auth_tok_list_item_cache)
+		rc |= ECRYPTFS_AUTH_TOK_LIST_ITEM_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_auth_tok_list_item "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_file_info_cache =
+	    kmem_cache_create("ecryptfs_file_cache",
+			      sizeof(struct ecryptfs_file_info),
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_file_info_cache)
+		rc |= ECRYPTFS_FILE_INFO_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_file_cache "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_dentry_info_cache =
+	    kmem_cache_create("ecryptfs_dentry_cache",
+			      sizeof(struct ecryptfs_dentry_info),
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_dentry_info_cache)
+		rc |= ECRYPTFS_DENTRY_INFO_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_dentry_cache "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_inode_info_cache =
+	    kmem_cache_create("ecryptfs_inode_cache",
+			      sizeof(struct ecryptfs_inode_info), 0,
+			      SLAB_HWCACHE_ALIGN, inode_info_init_once, NULL);
+	if (ecryptfs_inode_info_cache)
+		rc |= ECRYPTFS_INODE_INFO_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_inode_cache "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_sb_info_cache =
+	    kmem_cache_create("ecryptfs_sb_cache",
+			      sizeof(struct ecryptfs_sb_info),
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_sb_info_cache)
+		rc |= ECRYPTFS_SB_INFO_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_sb_cache "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_header_cache_0 =
+	    kmem_cache_create("ecryptfs_headers_0", PAGE_CACHE_SIZE,
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_header_cache_0)
+		rc |= ECRYPTFS_HEADER_CACHE_0;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_headers_0 "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_header_cache_1 =
+	    kmem_cache_create("ecryptfs_headers_1", PAGE_CACHE_SIZE,
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_header_cache_1)
+		rc |= ECRYPTFS_HEADER_CACHE_1;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_headers_1 "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_header_cache_2 =
+	    kmem_cache_create("ecryptfs_headers_2", PAGE_CACHE_SIZE,
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_header_cache_2)
+		rc |= ECRYPTFS_HEADER_CACHE_2;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_headers_2 "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_lower_page_cache =
+	    kmem_cache_create("ecryptfs_lower_page_cache", PAGE_CACHE_SIZE,
+			      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (ecryptfs_lower_page_cache)
+		rc |= ECRYPTFS_LOWER_PAGE_CACHE;
+	else
+		ecryptfs_printk(0, KERN_WARNING, "ecryptfs_lower_page_cache "
+				"kmem_cache_create failed\n");
+
+	ecryptfs_allocated_caches = rc;
+	rc = ECRYPTFS_CACHE_CREATION_SUCCESS ^ rc;
+	return rc;
+}
+
+/**
+ * @return Zero on success; non-zero otherwise
+ */
+static int ecryptfs_free_kmem_caches(void)
+{
+	int rc = 0;
+	int err;
+
+	if (ecryptfs_allocated_caches & ECRYPTFS_AUTH_TOK_LIST_ITEM_CACHE) {
+		rc = kmem_cache_destroy(ecryptfs_auth_tok_list_item_cache);
+		if (rc)
+			ecryptfs_printk(0, KERN_WARNING,
+					"Not all ecryptfs_auth_tok_"
+					"list_item_cache structures were "
+					"freed\n");
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_FILE_INFO_CACHE) {
+		err = kmem_cache_destroy(ecryptfs_file_info_cache);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING,
+					"Not all ecryptfs_file_info_"
+					"cache regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_DENTRY_INFO_CACHE) {
+		err = kmem_cache_destroy(ecryptfs_dentry_info_cache);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING,
+					"Not all ecryptfs_dentry_info_"
+					"cache regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_INODE_INFO_CACHE) {
+		err = kmem_cache_destroy(ecryptfs_inode_info_cache);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING,
+					"Not all ecryptfs_inode_info_"
+					"cache regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_SB_INFO_CACHE) {
+		err = kmem_cache_destroy(ecryptfs_sb_info_cache);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING,
+					"Not all ecryptfs_sb_info_"
+					"cache regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_HEADER_CACHE_0) {
+		err = kmem_cache_destroy(ecryptfs_header_cache_0);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING, "Not all ecryptfs_"
+					"header_cache_0 regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_HEADER_CACHE_1) {
+		err = kmem_cache_destroy(ecryptfs_header_cache_1);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING, "Not all ecryptfs_"
+					"header_cache_1 regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_HEADER_CACHE_2) {
+		err = kmem_cache_destroy(ecryptfs_header_cache_2);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING, "Not all ecryptfs_"
+					"header_cache_2 regions were freed\n");
+		rc |= err;
+	}
+	if (ecryptfs_allocated_caches & ECRYPTFS_LOWER_PAGE_CACHE) {
+		err = kmem_cache_destroy(ecryptfs_lower_page_cache);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING, "Not all ecryptfs_"
+					"lower_page_cache regions were "
+					"freed\n");
+		rc |= err;
+	}
+	return rc;
+}
+
+static int __init init_ecryptfs_fs(void)
+{
+	int rc;
+
+	rc = ecryptfs_init_kmem_caches();
+	if (rc) {
+		ecryptfs_printk(0, KERN_EMERG, "Failure occured while "
+				"attempting to create caches [CREATED: %x]."
+				"Now freeing caches.\n",
+				ecryptfs_allocated_caches);
+		ecryptfs_free_kmem_caches();
+		return -ENOMEM;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Registering eCryptfs\n");
+	return register_filesystem(&ecryptfs_fs_type);
+}
+
+static void __exit exit_ecryptfs_fs(void)
+{
+	int rc;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Unregistering eCryptfs\n");
+	unregister_filesystem(&ecryptfs_fs_type);
+	rc = ecryptfs_free_kmem_caches();
+	if (rc)
+		ecryptfs_printk(0, KERN_EMERG, "Failure occured while "
+				"attempting to free caches: [%d]\n", rc);
+}
+
+MODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>");
+MODULE_DESCRIPTION("eCryptfs");
+
+MODULE_LICENSE("GPL");
+
+module_init(init_ecryptfs_fs)
+module_exit(exit_ecryptfs_fs)
diff -urN oldtree/fs/ecryptfs/mmap.c newtree/fs/ecryptfs/mmap.c
--- oldtree/fs/ecryptfs/mmap.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/mmap.c	2006-02-18 17:24:58.726094832 +0000
@@ -0,0 +1,1153 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * This is where eCryptfs handles the bulk encryption and decryption,
+ * with upper-lower file index interpolations.
+ *
+ * Copyright (c) 1997-2003 Erez Zadok
+ * Copyright (c) 2001-2003 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/page-flags.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+static int ecryptfs_commit_write(struct file *file, struct page *page,
+				 unsigned from, unsigned to);
+static int ecryptfs_prepare_write(struct file *file, struct page *page,
+				  unsigned from, unsigned to);
+
+kmem_cache_t *ecryptfs_lower_page_cache;
+
+static inline pgoff_t
+record_idx(struct ecryptfs_crypt_stats *crypt_stats, pgoff_t idx)
+{
+	return (idx % crypt_stats->records_per_page);
+}
+
+static inline pgoff_t
+last_records_page_idx(struct ecryptfs_crypt_stats *crypt_stats, pgoff_t idx)
+{
+	pgoff_t lower_data_idx;
+	pgoff_t lower_record_idx;
+
+	lower_data_idx = ecryptfs_pg_idx_to_lwr_pg_idx(crypt_stats, idx);
+	lower_record_idx = record_idx(crypt_stats, idx);
+	return (lower_data_idx - lower_record_idx - 1);
+}
+
+/**
+ * Get one page from cache or lower f/s, return error otherwise.
+ *
+ * @return Unlocked and up-to-date page (if ok), with increased
+ *         refcnt.
+ */
+static struct page *ecryptfs_get1page(struct file *file, int index)
+{
+	struct page *page;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct address_space *mapping;
+	int rc;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
+	mapping = inode->i_mapping;
+	if (index < 0) {
+		ecryptfs_printk(1, KERN_ERR, "BUG: index=%d\n", index);
+		page = ERR_PTR(-EIO);
+		goto out;
+	}
+	page = read_cache_page(mapping, index,
+			       (filler_t *) mapping->a_ops->readpage,
+			       (void *)file);
+	if (IS_ERR(page))
+		goto out;
+	wait_on_page_locked(page);
+	if (!PageUptodate(page)) {
+		lock_page(page);
+		rc = mapping->a_ops->readpage(file, page);
+		if (rc) {
+			page = ERR_PTR(rc);
+			goto out;
+		}
+		wait_on_page_locked(page);
+		if (!PageUptodate(page)) {
+			page = ERR_PTR(-EIO);
+			goto out;
+		}
+	}
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return page;
+}
+
+/**
+ * Write a specified number of zero's to a page.
+ * 
+ * N.B. (start + num_zeros) _must_ be less than or equal to PAGE_CACHE_SIZE
+ *
+ * @param file		The ecryptfs file
+ * @param index		The index in which we are writing
+ * @param start		The position after the last block of data
+ * @param num_zeros	The number of zeros to write
+ */
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
+{
+	int rc = 0;
+	struct page *tmp_page;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; index = [%lu], start offset = "
+			"[%d] num_zeros = [%d]\n", index, start, num_zeros);
+	tmp_page = ecryptfs_get1page(file, index);
+	if (IS_ERR(tmp_page)) {
+		ecryptfs_printk(0, KERN_ERR, "Error getting page at index "
+				"[%lu]\n", index);
+		rc = PTR_ERR(tmp_page);
+		goto out;
+	}
+	kmap(tmp_page);
+	memset(((char *)page_address(tmp_page) + start), 0, num_zeros);
+	rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error preparing to write zero's "
+				"to remainder of page at index [%lu]\n", index);
+		kunmap(tmp_page);
+		page_cache_release(tmp_page);
+		goto out;
+	}
+	rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
+	if (rc < 0) {
+		ecryptfs_printk(0, KERN_ERR, "Error attempting to write zero's "
+				"to remainder of page at index [%lu]\n", index);
+		kunmap(tmp_page);
+		page_cache_release(tmp_page);
+		goto out;
+	}
+	rc = 0;
+	kunmap(tmp_page);
+	page_cache_release(tmp_page);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return rc;
+}
+
+/**
+ * Function for handling creation of holes when lseek-ing past the end
+ * of the file and then writing some data.
+ *
+ * N.B.
+ * This function does NOT support shrinking, only growing a file.
+ * The code _will_ BUG() if this requirement is not met.
+ * The new_length _myust_ be greater than the current length.
+ *
+ * @param file	     The ecryptfs file
+ * @param new_length The new length of the data in the underlying file;
+ * 		     everything between the prior end of the file and the new
+ * 		     end of the file will be filled with zero's.
+ * 		     N.B. new_length must be greater than current length
+ * @return	     Zero on success; non-zero otherwise 
+ */
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
+{
+	int rc = 0;
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	pgoff_t old_end_page_index = 0;
+	pgoff_t index = old_end_page_index;
+	int old_end_pos_in_page = -1;
+	pgoff_t new_end_page_index;
+	int new_end_pos_in_page;
+	loff_t cur_length = i_size_read(inode);
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; inode->i_size = [%llu]; "
+			"new_length = [%llu]\n", cur_length, new_length);
+	/* Sanity check */
+	if (cur_length >= new_length) {
+		ecryptfs_printk(0, KERN_ERR, "Called with new_length less than "
+				"or equal to the current length, this is "
+				"against function restrictions!\n");
+		BUG();
+	}
+	/* N.B. Notes on index calculations
+	 * It is important to note that the size of the file will always be 1
+	 * greater than the last block of data's position added to the data's
+	 * index shifted by the page cache size.
+	 *      size = index * PAGE_CACHE_SIZE + pos + 1
+	 *
+	 * Example, a file with 1 block of data in the 0th index at the 0th
+	 * position will be a file of size 1. Likewise, a file of 100 blocks
+	 * of data will have it's last block in the 99th position.
+	 *
+	 * Therefore, a file of size page with PAGE_CACHE_SIZE blocks of data
+	 * will have its last block of data in the (PAGE_CACHE_SIZE-1)th 
+	 * position, in the 0th index. A file with (PAGE_CACHE_SIZE + 1) blocks
+	 * of data will have its last block of data in the 0th position of the
+	 * 1st index. This calculation can be shown as:
+	 *      position = (size - 1) & ~PAGE_CACHE_MASK 
+	 *      index    =  (size - 1) >> PAGE_CACHE_SHIFT
+	 * 
+	 * Example:
+	 * PAGE_CACHE_SHIFT = 12
+	 * PAGE_CACHE_SIZE = (1UL << PAGE_CACHE_SHIFT) [or 4096]
+	 * PAGE_CACHE_MASK = (~(PAGE_CACHE_SIZE-1)) [or ~(4096-1)]
+	 *
+	 * A size of 4095 yields:
+	 *      position = (4095 - 1) & ~PAGE_CACHE_MASK => 4094
+	 *      index    = (4095 - 1) >> 12              => 0
+	 *
+	 * A size of 4096 yields:
+	 *      position = (4096 - 1) & ~PAGE_CACHE_MASK => 4095
+	 *      index    = (4096 - 1) >> 12              => 0
+	 *
+	 * A size of 4097 yields:
+	 *      position = (4097 - 1) & ~PAGE_CACHE_MASK => 0
+	 *      index    = (4097 - 1) >> 12              => 1
+	 *      
+	 * From these examples, you can see that the logic that a
+	 * file's last block of data is at the (size - 1)th position
+	 * follows.
+	 *
+	 * A 0-length file is by this logic, undefined if positions
+	 * and indicies are required to be positive integers. However,
+	 * this is intuative, as a 0-length file has no data which to
+	 * give a position and index to.  However, to make our
+	 * calculations work, we will use the default value of -1 if
+	 * the size is 0. The following will apply:
+	 *      old size = 0
+	 *      old position = -1
+	 *      old index = 0
+	 *      new size = 1
+	 *      new position = 0
+	 *      new index = 0
+	 *
+	 *      write_zeros(file,0,(-1+1) => 0, ((size-1) - (-1)) => size)
+	 *
+	 * Therefore, if the current size of the file is 0, then
+	 * setting our index and position to -1 will result in valid
+	 * calculations for the new index and position for the new
+	 * size.
+	 */
+	if (cur_length != 0) {
+		index = old_end_page_index =
+		    ((cur_length - 1) >> PAGE_CACHE_SHIFT);
+		old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
+	}
+	new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
+	new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
+
+	ecryptfs_printk(1, KERN_NOTICE, "old_end_page_index = [%lu]; "
+			"old_end_pos_in_page = [%d]; "
+			"new_end_page_index = [%lu]; "
+			"new_end_pos_in_page = [%d]\n",
+			old_end_page_index, old_end_pos_in_page,
+			new_end_page_index, new_end_pos_in_page);
+	if (old_end_page_index == new_end_page_index) {
+		/* Start and end are in the same page; we just need to
+		 * set a portion of the existing page to zero's */
+		rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+				 (new_end_pos_in_page - old_end_pos_in_page));
+		if (rc)
+			ecryptfs_printk(0, KERN_ERR, "write_zeros(file=[%p], "
+					"index=[%lu], old_end_pos_in_page=[d], "
+					"(PAGE_CACHE_SIZE - new_end_pos_in_page"
+					"=[%d]"
+					")=[d]) returned [%d]\n", file, index,
+					old_end_pos_in_page,
+					new_end_pos_in_page,
+					(PAGE_CACHE_SIZE - new_end_pos_in_page),
+					rc);
+		goto out;
+	}
+	/* Else, new position is outside of the current index.
+	 * Fill remainder of current page with zeros.
+	 * For each page after that page, will entire page with zeros.
+	 * Upon reaching new last page, write as many zeros as required
+	 * to fullfil the new size. */
+	/* Fill the remainder of the previous last page with zeros */
+	rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+			 ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "write_zeros(file=[%p], "
+				"index=[%lu], old_end_pos_in_page=[d], "
+				"(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
+				"returned [%d]\n", file, index,
+				old_end_pos_in_page,
+				(PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
+		goto out;
+	}
+	index++;
+	while (index < new_end_page_index) {
+		/* Fill all intermediate pages with zeros */
+		rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR, "write_zeros(file=[%p], "
+					"index=[%lu], old_end_pos_in_page=[d], "
+					"(PAGE_CACHE_SIZE - new_end_pos_in_page"
+					"=[%d]"
+					")=[d]) returned [%d]\n", file, index,
+					old_end_pos_in_page,
+					new_end_pos_in_page,
+					(PAGE_CACHE_SIZE - new_end_pos_in_page),
+					rc);
+			goto out;
+		}
+		index++;
+	}
+	/* Fill the portion at the beginning of the last new page with
+	 * zero's */
+	rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "write_zeros(file="
+				"[%p], index=[%lu], 0, "
+				"new_end_pos_in_page=[%d]"
+				"returned [%d]\n", file, index,
+				new_end_pos_in_page, rc);
+		goto out;
+	}
+out:
+	ecryptfs_printk((rc == 0 ? 1 : 0), KERN_NOTICE, "Exit; rc = [%d]\n",
+			rc);
+	return rc;
+}
+
+/**
+ * @param lower_file Can be NULL
+ * @return Zero on success
+ */
+static int 
+ecryptfs_read_rotate_write_iv(char *iv, struct inode *inode,
+			      int lower_iv_idx, struct file *lower_file, 
+			      struct page *page)
+{
+	int rc = 0;
+	pgoff_t records_page_index;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	struct page *records_page;
+	char *records_virt;
+	int lower_file_needs_fput = 0;
+	struct address_space_operations *lower_a_ops;
+	struct inode *lower_inode;
+
+	crypt_stats = &(ECRYPTFS_INODE_TO_PRIVATE(inode)->crypt_stats);
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+ 	lower_a_ops = lower_inode->i_mapping->a_ops;
+	records_page_index = last_records_page_idx(crypt_stats, page->index);
+	ecryptfs_printk(1, KERN_NOTICE, "records_page_index = [%lu]\n",
+			records_page_index);
+	records_page = grab_cache_page(lower_inode->i_mapping,
+				       records_page_index);
+	if (!records_page) {
+                        ecryptfs_printk(0, KERN_ERR, "records_page == NULL "
+                                        "after grab_cache_page at index [%lu]"
+                                        "\n", records_page_index);
+                        rc = -EIO;
+                        goto out;
+	}
+	/* TODO: Assume encrypted only for version 0.1 */
+	ecryptfs_printk(1, KERN_NOTICE, "lower_iv_idx = [%d]\n", lower_iv_idx);
+	records_virt = kmap(records_page);
+	if (!records_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(1, KERN_NOTICE, "Error in kmap\n");
+		goto out_unlock_and_release;
+	}
+	if (!lower_file) {
+		struct dentry *lower_dentry;
+		struct vfsmount *lower_mnt;
+
+		if (!lower_inode->i_dentry.next) {
+			rc = -EINVAL;
+			ecryptfs_printk(1, KERN_NOTICE, "No dentry for "
+					"lower_inode\n");
+			goto out_unmap;
+		}
+		lower_dentry = list_entry(lower_inode->i_dentry.next, 
+					  struct dentry, d_alias);
+		mntget(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt);
+		lower_mnt =
+			ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt;
+		lower_file = dentry_open(lower_dentry, lower_mnt, FMODE_READ);
+		if (IS_ERR(lower_file)) {
+			rc = PTR_ERR(lower_file);
+			ecryptfs_printk(0, KERN_ERR,
+					"Error opening dentry; rc = [%i]\n",
+					rc);
+			mntput(ECRYPTFS_SUPERBLOCK_TO_PRIVATE(inode->i_sb)->lower_mnt);
+			goto out_unmap;
+		}
+		lower_file_needs_fput = 1;
+	}
+	rc = lower_a_ops->prepare_write(lower_file, records_page, lower_iv_idx,
+					(lower_iv_idx + crypt_stats->iv_bytes));
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error in lower prepare_write() "
+				"call: rc = [%d]\n", rc);
+		goto out_unmap;
+	}
+	down(&crypt_stats->iv_sem);
+	ecryptfs_rotate_iv(crypt_stats->iv);
+	memcpy(iv, crypt_stats->iv, crypt_stats->iv_bytes);
+	up(&crypt_stats->iv_sem);
+	memcpy(records_virt + lower_iv_idx, crypt_stats->iv,
+	       crypt_stats->iv_bytes);
+	rc = lower_a_ops->commit_write(lower_file, records_page, lower_iv_idx, 
+				       (lower_iv_idx + crypt_stats->iv_bytes));
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error in lower commit_write() "
+				"call: rc = [%d]\n", rc);
+		goto out_unmap;
+	}
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	ecryptfs_printk(1, KERN_NOTICE, "Unlocking page with index = "
+			"[%lu]\n", records_page->index);
+out_unmap:
+	kunmap(records_page);
+out_unlock_and_release:
+	unlock_page(records_page);
+	page_cache_release(records_page);
+	ecryptfs_printk(1, KERN_NOTICE, "After committing IV write, "
+			"lower_inode->i_blocks = [%lu]\n",
+			lower_inode->i_blocks);	
+out:
+	if (lower_file_needs_fput)
+		fput(lower_file);
+	return rc;
+}
+
+/**
+ * @return Zero on success; negative on error
+ */
+static int encrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+			struct page *page, struct page *lower_page, char *iv)
+{
+	int rc = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Calling do_encrypt_page()\n");
+	ecryptfs_printk(1, KERN_NOTICE, "Encrypting page with iv:\n");
+	if (unlikely(ecryptfs_verbosity > 0))
+		ecryptfs_dump_hex(iv, crypt_stats->iv_bytes);
+	ecryptfs_printk(1, KERN_NOTICE, "First 8 bytes before "
+			"encryption:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((char *)page_address(page), 8);
+	rc = do_encrypt_page_offset(crypt_stats, lower_page, 0,
+				    page, 0, crypt_stats->extent_size, iv);
+	ecryptfs_printk(1, KERN_NOTICE, "Encrypted [%d] bytes\n", rc);
+	ecryptfs_printk(1, KERN_NOTICE, "First 8 bytes after " "encryption:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((char *)page_address(lower_page), 8);
+	if (rc > 0)
+		rc = 0;
+	return rc;
+}
+
+/**
+ * @param page Page that is locked before this call is made
+ */
+static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	int rc = -EIO;
+	int err = 0;
+	unsigned long lower_index;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct page *lower_page;
+	char *kaddr, *lower_kaddr;
+	struct ecryptfs_crypt_stats *crypt_stats;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; page->index = [%ld]; "
+			"page->mapping->host = [%p]\n", page->index,
+			page->mapping->host);
+	inode = page->mapping->host;
+	crypt_stats = &(ECRYPTFS_INODE_TO_PRIVATE(inode)->crypt_stats);
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	lower_index = ecryptfs_pg_idx_to_lwr_pg_idx(crypt_stats, page->index);
+	ecryptfs_printk(1, KERN_NOTICE, "Grab lower_idx = [%ld]\n",
+			lower_index);
+	lower_page = grab_cache_page(lower_inode->i_mapping, lower_index);
+	if (!lower_page) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	kaddr = (char *)kmap(page);
+	if (!kaddr) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	lower_kaddr = (char *)kmap(lower_page);
+	if (!lower_kaddr) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	if (crypt_stats->encrypted) {
+		char iv[ECRYPTFS_MAX_IV_BYTES];
+		int record_byte_offset;
+		/* TODO: HMAC: Include HMAC bytes in the record size */
+		record_byte_offset = (record_idx(crypt_stats, page->index)
+				      * crypt_stats->iv_bytes);
+		rc = ecryptfs_read_rotate_write_iv(iv, inode,
+						   record_byte_offset, NULL,
+						   page);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR, "Error rotating "
+					"IV; write failure. Assuming "
+					"IV page corruption; writing "
+					"0's to associated data extent"
+					".\n");
+			memset(lower_kaddr, 0, crypt_stats->extent_size);
+			err = -EIO;
+			goto do_lower_write;
+		}
+		ecryptfs_printk(1, KERN_NOTICE, "Encrypting page with iv:\n");
+		if (unlikely(ecryptfs_verbosity > 0))
+			ecryptfs_dump_hex(iv, crypt_stats->iv_bytes);
+		err = encrypt_page(crypt_stats, page, lower_page, iv);
+		if (err)
+			ecryptfs_printk(0, KERN_WARNING, "Error encrypting "
+					"page (upper index [%llu])\n", 
+					page->index);
+	} else
+		memcpy(lower_kaddr, kaddr, crypt_stats->extent_size);
+do_lower_write:
+	kunmap(page);
+	kunmap(lower_page);
+	rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
+	if (rc)
+		ecryptfs_printk(0, KERN_ERR, "Error calling lower writepage(); "
+				"rc = [%d]\n", rc);
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	page_cache_release(lower_page);
+	if (rc)
+		ClearPageUptodate(page);
+	else
+		SetPageUptodate(page);
+	unlock_page(page);
+out:
+	if (err)
+		rc = err;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Reads the data from the lower file file at index lower_page_index
+ * and copies that data into page.
+ *
+ * @param page	Page to fill
+ * @param lower_page_index Index of the page in the lower file to get
+ */
+static int ecryptfs_do_readpage(struct file *file, struct page *page,
+				pgoff_t lower_page_index)
+{
+	int rc = -EIO;
+	struct dentry *dentry;
+	struct file *lower_file;
+	struct dentry *lower_dentry;
+	struct inode *inode;
+	struct inode *lower_inode;
+	char *page_data;
+	struct page *lower_page = NULL;
+	char *lower_page_data;
+	struct address_space_operations *lower_a_ops;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; lower_page_index = [%lu]\n",
+			lower_page_index);
+	dentry = file->f_dentry;
+	if (NULL == ECRYPTFS_FILE_TO_PRIVATE_SM(file)) {
+		rc = -ENOENT;
+		ecryptfs_printk(0, KERN_ERR, "No lower file info\n");
+		goto out;
+	}
+	lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	lower_dentry = ECRYPTFS_DENTRY_TO_LOWER(dentry);
+	inode = dentry->d_inode;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
+				     (filler_t *) lower_a_ops->readpage,
+				     (void *)lower_file);
+	if (IS_ERR(lower_page)) {
+		rc = PTR_ERR(lower_page);
+		lower_page = NULL;
+		ecryptfs_printk(0, KERN_ERR, "Error reading from page cache\n");
+		goto out;
+	}
+	wait_on_page_locked(lower_page);
+	if (!PageUptodate(lower_page)) {
+		lock_page(lower_page);
+		rc = lower_a_ops->readpage(lower_file, lower_page);
+		if (rc) {
+			lower_page = NULL;
+			rc = -EIO;
+			ecryptfs_printk(0, KERN_ERR, "Error reading lower "
+					"page at index=[%lu]\n",
+					lower_page_index);
+			goto out;
+		}
+		wait_on_page_locked(lower_page);
+		if (!PageUptodate(lower_page)) {
+			rc = -EIO;
+			ecryptfs_printk(0, KERN_ERR, "Error reading lower "
+					"page at index=[%lu]\n",
+					lower_page_index);
+			goto out;
+		}
+	}
+	page_data = (char *)kmap(page);
+	if (!page_data) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Error mapping page\n");
+		goto out;
+	}
+	lower_page_data = (char *)kmap(lower_page);
+	if (!lower_page_data) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Error mapping page\n");
+		kunmap(page);
+		goto out;
+	}
+	/* TODO: Copy sub-page amount of data? */
+	memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
+	kunmap(lower_page);
+	kunmap(page);
+	rc = 0;
+      out:
+	if (likely(lower_page))
+		page_cache_release(lower_page);
+	if (rc == 0)
+		SetPageUptodate(page);
+	else
+		ClearPageUptodate(page);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/* Action descriptor for decrypt_page() */
+#define ECRYPTFS_ACTION_COPY 0
+#define ECRYPTFS_ACTION_DECRYPT 1
+
+/**
+ * Decrypt a page of data
+ *
+ * @return Zero on success
+ */
+static int decrypt_page(struct ecryptfs_crypt_stats *crypt_stats,
+			struct file *file, char *iv, struct page *page,
+			pgoff_t lower_page_index, int decrypt)
+{
+	int rc = 0;
+	char *lower_page_encrypted_virt;
+	struct page *lower_page_encrypted;
+	int decrypt_to;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; lower_page_index = [%d]\n",
+			lower_page_index);
+	lower_page_encrypted_virt =
+	    kmem_cache_alloc(ecryptfs_lower_page_cache, SLAB_KERNEL);
+	if (!lower_page_encrypted_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Error getting page for "
+				"encrypted lower page\n");
+		ClearPageUptodate(page);
+		goto out;
+	}
+	lower_page_encrypted = virt_to_page(lower_page_encrypted_virt);
+	rc = ecryptfs_do_readpage(file, lower_page_encrypted, lower_page_index);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error reading lower encrypted "
+				"page\n");
+		ClearPageUptodate(page);
+		goto out;
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "Decrypting page with iv:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(iv, crypt_stats->iv_bytes);
+	ecryptfs_printk(1, KERN_NOTICE, "Using session key encryption key:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(crypt_stats->key,
+				  crypt_stats->key_size_bits / 8);
+	decrypt_to = crypt_stats->extent_size;
+	ecryptfs_printk(1, KERN_NOTICE, "Decrypting to: [%d]\n", decrypt_to);
+	ecryptfs_printk(1, KERN_NOTICE, "First 8 bytes before decryption:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((char *)page_address(lower_page_encrypted),
+				  8);
+	if (decrypt)
+		do_decrypt_page_offset(crypt_stats, page,
+				       0, lower_page_encrypted,
+				       0, decrypt_to, iv);
+	else
+		memcpy(page, lower_page_encrypted_virt, decrypt_to);
+	ecryptfs_printk(1, KERN_NOTICE, "First 8 bytes after decryption:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((char *)page_address(page), 8);
+	kmem_cache_free(ecryptfs_lower_page_cache, lower_page_encrypted_virt);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * Read in a page
+ *
+ * @param file	This is an ecryptfs file
+ * @param page	ecryptfs associated page to stick the read data into
+ * @return Zero on success; non-zero on error
+ */
+static int ecryptfs_readpage(struct file *file, struct page *page)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stats *crypt_stats = NULL;
+	char iv[ECRYPTFS_MAX_IV_BYTES];
+	int iv_is_nonzero = 0;
+	char *records_virt;
+	struct page *records_page;
+	int record_byte_offset;
+	int iv_byte_offset;
+	int i;
+	pgoff_t records_page_index;
+	pgoff_t lower_page_index;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; page->index = [%ld]\n",
+			page->index);
+	ASSERT(file && file->f_dentry && file->f_dentry->d_inode);
+	crypt_stats = 
+		&ECRYPTFS_INODE_TO_PRIVATE(file->f_dentry->d_inode)->crypt_stats;
+	/* If the file is neither encrypted nor HMAC-verified, then we
+	 * have passthrough mode. */
+	if (!crypt_stats || !crypt_stats->encrypted) {
+		ecryptfs_printk(1, KERN_NOTICE,
+				"Passing through unencrypted page\n");
+		rc = ecryptfs_do_readpage(file, page, page->index);
+		goto out;
+	}
+	/* The file is encrypted, hmac verified, or both. */
+	ecryptfs_printk(1, KERN_NOTICE,
+			"crypt_stats->iv_bytes = [%d]\n",
+			crypt_stats->iv_bytes);
+	ecryptfs_printk(1, KERN_NOTICE,
+			"crypt_stats->records_per_page = [%d]\n",
+			crypt_stats->records_per_page);
+
+	/* Get the relevant IV/HMAC page */
+	records_page_index = last_records_page_idx(crypt_stats, page->index);
+	ecryptfs_printk(1, KERN_NOTICE, "records_page_index = [%lu]\n",
+			records_page_index);
+	records_virt = (char *)__get_free_page(GFP_KERNEL);
+	if (!records_virt) {
+		ecryptfs_printk(0, KERN_ERR, "Error getting free page");
+		rc = -ENOMEM;
+		ClearPageUptodate(page);
+		goto out;
+	}
+	records_page = virt_to_page(records_virt);
+	rc = ecryptfs_do_readpage(file, records_page, records_page_index);
+	if (rc) {
+		ecryptfs_printk(0, KERN_ERR, "Error reading IV/HMAC page");
+		ClearPageUptodate(page);
+		goto out;
+	}
+	/* TODO: HMAC: Include HMAC bytes in the record size */
+	record_byte_offset = (record_idx(crypt_stats, page->index) 
+			      * crypt_stats->iv_bytes);
+	iv_byte_offset = -1;
+	if (crypt_stats->encrypted) {
+		iv_byte_offset = record_byte_offset;
+		iv_is_nonzero = 0;
+		for (i = 0; i < crypt_stats->iv_bytes; i++)
+			iv_is_nonzero |= (records_virt + iv_byte_offset)[i];
+		memcpy(iv, (records_virt + iv_byte_offset),
+		       crypt_stats->iv_bytes);
+	}
+	ecryptfs_printk(1, KERN_NOTICE, "record_byte_offset = [%d]\n",
+			record_byte_offset);
+	ecryptfs_printk(1, KERN_NOTICE, "iv_byte_offset = [%d]\n",
+			iv_byte_offset);
+	free_page((unsigned long)records_virt);
+	lower_page_index = ecryptfs_pg_idx_to_lwr_pg_idx(crypt_stats,
+							 page->index);
+	ecryptfs_printk(1, KERN_NOTICE, "lower_page_index = [%lu]\n",
+			lower_page_index);
+	ecryptfs_printk(1, KERN_NOTICE, "iv_is_nonzero = [%d]\n",
+			iv_is_nonzero);
+	if (crypt_stats->encrypted && iv_is_nonzero) {
+		rc = decrypt_page(crypt_stats, file, iv, page,
+				  lower_page_index, ECRYPTFS_ACTION_DECRYPT);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR, "Error decrypting "
+					"page; rc = [%d]\n", rc);
+			goto out;
+		}
+	} else {
+		ecryptfs_printk(1, KERN_NOTICE,
+				"Passing through unencrypted page\n");
+		rc = ecryptfs_do_readpage(file, page, lower_page_index);
+	}
+	SetPageUptodate(page);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Unlocking page with index = [%lu]\n",
+			page->index);
+	unlock_page(page);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static void fill_zeros_to_end_of_page(struct page *page, unsigned to)
+{
+	struct inode *inode = page->mapping->host;
+	int end_byte_in_page;
+	char *page_virt;
+
+	if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) {
+		end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
+		if (to > end_byte_in_page)
+			end_byte_in_page = to;
+		page_virt = kmap(page);
+		if (!page_virt) {
+			goto out;
+		}
+		memset((page_virt + end_byte_in_page), 0,
+		       (PAGE_CACHE_SIZE - end_byte_in_page));
+		kunmap(page);
+	}
+out:
+	return;
+}
+
+static int ecryptfs_prepare_write(struct file *file, struct page *page,
+				  unsigned from, unsigned to)
+{
+	int err = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; page->index = [%lu]; from = "
+			"[%d]; to = [%d]\n", page->index, from, to);
+	kmap(page);
+	if (from == 0 && to == PAGE_CACHE_SIZE)
+		goto out;	/* If we are writing a full page, it will be
+				   up to date. */
+	if (!PageUptodate(page))
+		err = ecryptfs_do_readpage(file, page, page->index);
+out:
+	return err;
+}
+
+/**
+ * @return Zero on success
+ */
+int
+ecryptfs_write_inode_size_to_header(struct file *lower_file,
+				    struct inode *lower_inode,
+				    struct inode *inode)
+{
+	int rc = 0;
+	struct page *header_page;
+	char *header_virt;
+	struct address_space_operations *lower_a_ops;
+	unsigned long long file_size;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	header_page = grab_cache_page(lower_inode->i_mapping, 0);
+	if (!header_page) {
+		rc = -EINVAL;
+		ecryptfs_printk(0, KERN_ERR, "grab_cache_page for header page "
+				"failed\n");
+		goto out;
+	}
+	header_virt = kmap(header_page);
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+	file_size = (unsigned long long)i_size_read(inode);
+	memcpy(header_virt, &file_size, 8);
+	rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
+	if (rc < 0)
+		ecryptfs_printk(0, KERN_ERR, "Error commiting header page "
+				"write\n");
+	kunmap(header_page);
+	ecryptfs_printk(1, KERN_NOTICE, "Unlocking page with index = [%lu]\n",
+			header_page->index);
+	unlock_page(header_page);
+	page_cache_release(header_page);
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * This is where we encrypt the data and pass the encrypted data to
+ * the lower filesystem.  In OpenPGP-compatible mode, we operate on
+ * entire underlying packets.
+ *
+ * @param file The eCryptfs file object
+ * @param page The eCryptfs page
+ * @param from Ignored (we rotate the page IV on each write)
+ * @param to Ignored
+ * @return 
+ */
+static int ecryptfs_commit_write(struct file *file, struct page *page,
+				 unsigned from, unsigned to)
+{
+	int rc = -ENOMEM;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct page *lower_page = NULL;
+	struct file *lower_file = NULL;
+	loff_t pos;
+	unsigned bytes = to - from;
+	struct ecryptfs_crypt_stats *crypt_stats;
+	pgoff_t lower_page_index;
+	struct address_space_operations *lower_a_ops;
+	struct dentry *ecryptfs_dentry;
+
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Enter; page->index = [%lu]; from = [%d]; to = [%d]\n",
+			page->index, from, to);
+	ecryptfs_dentry = file->f_dentry;
+	inode = page->mapping->host;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	down(&lower_inode->i_sem);
+	if (!(lower_inode->i_mapping
+	      && lower_inode->i_mapping->a_ops
+	      && lower_inode->i_mapping->a_ops->prepare_write
+	      && lower_inode->i_mapping->a_ops->commit_write)) {
+		ecryptfs_printk(0, KERN_ERR,
+				"a_ops of lower inode not valid\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	ASSERT(file && file->f_dentry && file->f_dentry->d_inode);
+	crypt_stats = 
+		&ECRYPTFS_INODE_TO_PRIVATE(file->f_dentry->d_inode)->crypt_stats;
+	if (NULL != ECRYPTFS_FILE_TO_PRIVATE(file))
+		lower_file = ECRYPTFS_FILE_TO_LOWER(file);
+	if (!crypt_stats) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = ecryptfs_init_crypt_ctx(crypt_stats);
+	if (rc)
+		ecryptfs_printk(1, KERN_NOTICE, "Problem with "
+				"initializing crypto context\n");
+	if (crypt_stats->new_file) {
+		struct page *header_page;
+		char *header_virt;
+
+		crypt_stats->new_file = 0;
+		header_page = grab_cache_page(lower_inode->i_mapping, 0);
+		if (!header_page) {
+			rc = -EINVAL;
+			ecryptfs_printk(0, KERN_ERR, "grab_cache_page for "
+					"header page failed\n");
+			goto out;
+		}
+		header_virt = kmap(header_page);
+		rc = lower_a_ops->prepare_write(lower_file, header_page,
+						0, crypt_stats->extent_size);
+		rc = ecryptfs_write_headers_virt(header_virt, crypt_stats,
+						 ecryptfs_dentry, 
+						 ECRYPTFS_FILE_VERSION);
+		if (rc) {
+			ecryptfs_printk(0, KERN_WARNING, "Error generating "
+					"header; rc = [%d]\n", rc);
+			rc = -EIO;
+			goto out;
+		}
+		memset(header_virt, 0, 8);
+		rc = lower_a_ops->commit_write(lower_file, header_page,
+					       0, crypt_stats->extent_size);
+		if (rc < 0)
+			ecryptfs_printk(0, KERN_ERR, "Error commiting header "
+					"page write\n");
+		kunmap(header_page);
+		ecryptfs_printk(1, KERN_NOTICE,
+				"Unlocking header page with index = " "[%lu]\n",
+				header_page->index);
+		unlock_page(header_page);
+		page_cache_release(header_page);
+		if (rc < 0)
+			goto out;
+		rc = 0;
+		ecryptfs_printk(1, KERN_NOTICE, "lower_inode->i_blocks = "
+				"[%lu]\n", lower_inode->i_blocks);
+		i_size_write(inode, 0);
+		lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty_sync(inode);
+	} else
+		ecryptfs_printk(1, KERN_NOTICE, "Not a new file\n");
+	/* Translate the page index */
+	lower_page_index = ecryptfs_pg_idx_to_lwr_pg_idx(crypt_stats,
+							 page->index);
+	ecryptfs_printk(1, KERN_NOTICE, "lower_page_index = [%lu]\n",
+			lower_page_index);
+	lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index);
+	if (!lower_page) {
+		ecryptfs_printk(0, KERN_ERR, "grab_cache_page for "
+				"lower_page_index=[%lu] failed\n",
+				lower_page_index);
+		goto out;
+	}
+	kmap(lower_page);
+	rc = lower_a_ops->prepare_write(lower_file, lower_page,
+					0, crypt_stats->extent_size);
+	if (rc)
+		goto out_unlock_lower;
+	fill_zeros_to_end_of_page(page, to);
+	if (!crypt_stats->encrypted) {
+		/* TODO: aops */
+		memcpy((char *)page_address(lower_page),
+		       (char *)page_address(page), crypt_stats->extent_size);
+	} else {
+		/* The file is either encrypted or HMAC'd */
+		char iv[ECRYPTFS_MAX_IV_BYTES];
+		int record_byte_offset;
+		ecryptfs_printk(1, KERN_NOTICE,
+				"crypt_stats->iv_bytes = [%d]\n",
+				crypt_stats->iv_bytes);
+		/* TODO: HMAC: Include HMAC bytes in the record size */	
+		record_byte_offset = (record_idx(crypt_stats, page->index) 
+				      * crypt_stats->iv_bytes);
+		rc = ecryptfs_read_rotate_write_iv(iv, inode, 
+						   record_byte_offset, 
+						   lower_file, page);
+		if (rc) {
+			ecryptfs_printk(0, KERN_ERR, "Error rotating IV\n");
+			goto out_unlock_lower;
+		}
+		ecryptfs_printk(1, KERN_NOTICE, "Encrypting page with iv:\n");
+		if (unlikely(ecryptfs_verbosity > 0))
+			ecryptfs_dump_hex(iv, crypt_stats->iv_bytes);
+		rc = encrypt_page(crypt_stats, page, lower_page, iv);
+		if (rc) {
+			ecryptfs_printk(0, KERN_WARNING, "Error encrypting "
+					"page (upper index [%llu])\n", 
+					page->index);
+			goto out;
+		}
+	}
+	rc = lower_a_ops->commit_write(lower_file, lower_page, 0,
+				       crypt_stats->extent_size);
+	if (rc < 0) {
+		ecryptfs_printk(0, KERN_ERR,
+				"Error committing write; rc = [%d]\n", rc);
+		goto out_unlock_lower;
+	}
+	rc = bytes;
+	inode->i_blocks = lower_inode->i_blocks;
+	pos = (page->index << PAGE_CACHE_SHIFT) + to;
+	if (pos > i_size_read(inode)) {
+		i_size_write(inode, pos);
+		ecryptfs_printk(1, KERN_NOTICE, "Expanded file size to "
+				"[%lld]\n", i_size_read(inode));
+	}
+	ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+	
+out_unlock_lower:
+	kunmap(lower_page);
+	ecryptfs_printk(1, KERN_NOTICE,
+			"Unlocking lower page with index = [%lu]\n",
+			lower_page->index);
+	unlock_page(lower_page);
+	page_cache_release(lower_page);
+	kunmap(page);		/* mapped in prepare_write */
+out:
+	if (rc < 0)
+		ClearPageUptodate(page);
+	else
+		SetPageUptodate(page);
+	up(&lower_inode->i_sem);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; rc = [%d]\n", rc);
+	return rc;
+}
+
+static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
+{
+	int rc = 0;
+	struct inode *inode;
+	struct inode *lower_inode;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	inode = (struct inode *)mapping->host;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	if (lower_inode->i_mapping->a_ops->bmap)
+		rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
+							 block);
+	return rc;
+}
+
+/**
+ * This function is copied verbatim from mm/filemap.c.  It should be
+ * simply moved to some header file instead.
+ */
+static int sync_page(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
+		return mapping->a_ops->sync_page(page);
+	return 0;
+}
+
+static int ecryptfs_sync_page(struct page *page)
+{
+	int rc = 0;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct page *lower_page;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	inode = page->mapping->host;
+	lower_inode = ECRYPTFS_INODE_TO_LOWER(inode);
+	lower_page = grab_cache_page(lower_inode->i_mapping, page->index);
+	if (!lower_page) {
+		rc = -ENOMEM;
+		ecryptfs_printk(0, KERN_ERR, "Error from grab_cache_page "
+				"(no mem?)\n");
+		goto out;
+	}
+	rc = sync_page(lower_page);
+	ecryptfs_printk(1, KERN_NOTICE, "Unlocking page with index = [%lu]\n",
+			lower_page->index);
+	unlock_page(lower_page);
+	page_cache_release(lower_page);
+out:
+	return rc;
+}
+
+struct address_space_operations ecryptfs_aops = {
+	.writepage = ecryptfs_writepage,
+	.readpage = ecryptfs_readpage,
+	.prepare_write = ecryptfs_prepare_write,
+	.commit_write = ecryptfs_commit_write,
+	.bmap = ecryptfs_bmap,
+	.sync_page = ecryptfs_sync_page,
+};
diff -urN oldtree/fs/ecryptfs/super.c newtree/fs/ecryptfs/super.c
--- oldtree/fs/ecryptfs/super.c	1970-01-01 00:00:00.000000000 +0000
+++ newtree/fs/ecryptfs/super.c	2006-02-18 17:24:58.727094680 +0000
@@ -0,0 +1,250 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (c) 1997-2003 Erez Zadok
+ * Copyright (c) 2001-2003 Stony Brook University
+ * Copyright (c) 2004 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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/fs.h>
+#include <linux/mount.h>
+#include <linux/key.h>
+#include "ecryptfs_kernel.h"
+
+kmem_cache_t *ecryptfs_inode_info_cache;
+
+/**
+ * Called to bring an inode into existence.
+ *
+ * Note that setting the self referencing pointer doesn't work here:
+ * 	i.e. ECRYPTFS_INODE_TO_PRIVATE_SM(inode)=ei;
+ *
+ * Only handle allocation, setting up structures should be done in
+ * ecryptfs_read_inode. This is because the kernel, between now and
+ * then, will 0 out the private data pointer.
+ *
+ * @param sb	Pointer to the super block of the filesystem
+ * @return	Pointer to a newly allocated inode, NULL otherwise
+ */
+static struct inode *ecryptfs_alloc_inode(struct super_block *sb) {
+	struct ecryptfs_inode_info *ecryptfs_inode = NULL;
+	struct inode *inode = NULL;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; sb = [%p]\n", sb);
+	ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
+					  SLAB_KERNEL);
+	if (unlikely(!ecryptfs_inode)) {
+		ecryptfs_printk(1, KERN_WARNING,
+				"Failed to allocate new inode\n");
+		goto out;
+	}
+	ecryptfs_init_crypt_stats(&(ecryptfs_inode->crypt_stats));
+	inode = &(ecryptfs_inode->vfs_inode);
+ out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; inode = [%p]\n", inode);
+	return inode;
+}
+
+/**
+ * This is used during the final destruction of the inode.
+ * All allocation of memory related to the inode, including allocated
+ * memory in the crypt_stats struct, will be released here.
+ * There should be no chance that this deallocation will be missed.
+ */
+static void ecryptfs_destroy_inode(struct inode *inode) {
+	struct ecryptfs_crypt_stats *crypt_stats;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; inode = [%p]\n", inode);
+	crypt_stats = &(ECRYPTFS_INODE_TO_PRIVATE(inode))->crypt_stats;
+	ecryptfs_destruct_crypt_stats(crypt_stats);
+	kmem_cache_free(ecryptfs_inode_info_cache,
+			ECRYPTFS_INODE_TO_PRIVATE(inode));
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Return a pointer to our ecryptfs_inode_info struct.
+ * This is specified by the kernel documentation for the alloc_inode &
+ * destroy_inode change. We use this function to get a handle to our
+ * ecryptfs specific data.
+ *
+ * @param inode	The inode component of the ecryptfs_inode_info we want to find
+ * @return	Handle to our ecryptfs_inode_info
+ */
+static inline struct ecryptfs_inode_info *ECRYPTFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct ecryptfs_inode_info, vfs_inode);
+}
+
+/**
+ * Set up the ecryptfs inode.
+ */
+static void ecryptfs_read_inode(struct inode *inode)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; inode = [%p]\n", inode);
+	/* This is where we setup the self-reference in the vfs_inode's
+	 * u.generic_ip. That way we don't have to walk the list again. */
+	ECRYPTFS_INODE_TO_PRIVATE_SM(inode) = ECRYPTFS_I(inode);
+	ECRYPTFS_INODE_TO_LOWER(inode) = NULL;
+	inode->i_version++;
+	inode->i_op = &ecryptfs_main_iops;
+	inode->i_fop = &ecryptfs_main_fops;
+	inode->i_mapping->a_ops = &ecryptfs_aops;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+
+/**
+ * This is called through iput_final().
+ * This is function will replace generic_drop_inode. The end result of which
+ * is we are skipping the check in inode->i_nlink, which we do not use.
+ */
+static void ecryptfs_drop_inode(struct inode *inode) {
+	generic_delete_inode(inode);
+}
+
+/**
+ * Final actions when unmounting a file system.
+ * This will handle deallocation and release of our private data.
+ */
+static void ecryptfs_put_super(struct super_block *sb)
+{
+	struct ecryptfs_sb_info *sb_info = ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb);
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	mntput(sb_info->lower_mnt);
+	key_put(sb_info->mount_crypt_stats.global_auth_tok_key);
+	kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
+	ECRYPTFS_SUPERBLOCK_TO_PRIVATE_SM(sb) = NULL;
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Get the filesystem statistics. Currently, we let this pass right through
+ * to the lower filesystem and take no action ourselves
+ * 
+ * TODO: Any stats need to be transposed?
+ */
+static int ecryptfs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+	int err = 0;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	err = vfs_statfs(ECRYPTFS_SUPERBLOCK_TO_LOWER(sb), buf);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; err = [%d]\n",err);
+	return err;
+}
+
+/**
+ * TODO: Not implemented.
+ * Called to ask filesystem to change mount options.
+ */
+static int ecryptfs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+	return -ENOSYS;
+}
+
+/**
+ * Called by iput() when the inode reference count reached zero
+ * and the inode is not hashed anywhere.  Used to clear anything
+ * that needs to be, before the inode is completely destroyed and put
+ * on the inode free list. We use this to drop out reference to the
+ * lower inode.
+ *
+ * TODO: Why do we just not drop the reference to the lower inode in
+ *      ecryptfs_destroy_inode?
+ */
+static void ecryptfs_clear_inode(struct inode *inode)
+{
+	ecryptfs_printk(1, KERN_NOTICE, "Enter; inode = [%p]; i_ino = [%lu]\n",
+			inode, inode->i_ino);
+	iput(ECRYPTFS_INODE_TO_LOWER(inode));
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/**
+ * Called in do_umount() if the MNT_FORCE flag was used and this
+ * function is defined.  See comment in linux/fs/super.c:do_umount().
+ * Used only in nfs, to kill any pending RPC tasks, so that subsequent
+ * code can actually succeed and won't leave tasks that need handling.
+ *
+ * PS. I wonder if this is somehow useful to undo damage that was
+ * left in the kernel after a user level file server (such as amd)
+ * dies.
+ */
+static void ecryptfs_umount_begin(struct super_block *sb)
+{
+	struct super_block *lower_sb;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	/* TODO: Explain why we are umounting the lower superblock */
+	lower_sb = ECRYPTFS_SUPERBLOCK_TO_LOWER(sb);
+	if (lower_sb->s_op->umount_begin)
+		lower_sb->s_op->umount_begin(lower_sb);
+	ecryptfs_printk(1, KERN_NOTICE, "Exit\n");
+}
+
+/* TODO: Where is this normally declared? */
+int seq_printf(struct seq_file *m, const char *f, ...);
+
+/**
+ * Prints the directory we are currently mounted over
+ * 
+ * @return Zero on success; non-zero otherwise
+ */
+static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct super_block *sb = mnt->mnt_sb;
+	int ret = 0;
+	char *tmp = NULL;
+	char *path;
+
+	ecryptfs_printk(1, KERN_NOTICE, "Enter\n");
+	tmp = (char *)__get_free_page(GFP_KERNEL);
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	/* TODO: wrap? */
+	path = d_path(ECRYPTFS_DENTRY_TO_LOWER(sb->s_root),
+		      ECRYPTFS_SUPERBLOCK_TO_PRIVATE(sb)->lower_mnt, tmp,
+		      PAGE_SIZE);
+	seq_printf(m, ",dir=%s", path);
+	free_page((unsigned long)tmp);
+ out:
+	ecryptfs_printk(1, KERN_NOTICE, "Exit; ret = [%d]\n",ret);
+	return ret;
+}
+
+/* TODO: Provide operations? (quota stuff, dirty, sync) */
+struct super_operations ecryptfs_sops = {
+	.alloc_inode = ecryptfs_alloc_inode,
+	.destroy_inode = ecryptfs_destroy_inode,
+	.read_inode = ecryptfs_read_inode,
+	.drop_inode = ecryptfs_drop_inode,
+	.put_super = ecryptfs_put_super,
+	.statfs = ecryptfs_statfs,
+	.remount_fs = ecryptfs_remount_fs,
+	.clear_inode = ecryptfs_clear_inode,
+	.umount_begin = ecryptfs_umount_begin,
+	.show_options = ecryptfs_show_options
+};
