eCryptfs: set up and destroy persistent lower file
authorMichael Halcrow <mhalcrow@us.ibm.com>
Tue, 16 Oct 2007 08:28:09 +0000 (01:28 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 16 Oct 2007 16:43:12 +0000 (09:43 -0700)
This patch sets up and destroys the persistent lower file for each eCryptfs
inode.

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/ecryptfs/inode.c
fs/ecryptfs/main.c
fs/ecryptfs/super.c

index 7192a810bbe64433c255994307a7492fc7f83261..c746b5d8a3361c86fd498ced6439b49e2cea702c 100644 (file)
@@ -119,10 +119,23 @@ ecryptfs_do_create(struct inode *directory_inode,
        }
        rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
                                             ecryptfs_dentry, mode, nd);
-       if (unlikely(rc)) {
-               ecryptfs_printk(KERN_ERR,
-                               "Failure to create underlying file\n");
-               goto out_lock;
+       if (rc) {
+               struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;
+               struct ecryptfs_inode_info *inode_info =
+                       ecryptfs_inode_to_private(ecryptfs_inode);
+
+               printk(KERN_WARNING "%s: Error creating underlying file; "
+                      "rc = [%d]; checking for existing\n", __FUNCTION__, rc);
+               if (inode_info) {
+                       mutex_lock(&inode_info->lower_file_mutex);
+                       if (!inode_info->lower_file) {
+                               mutex_unlock(&inode_info->lower_file_mutex);
+                               printk(KERN_ERR "%s: Failure to set underlying "
+                                      "file; rc = [%d]\n", __FUNCTION__, rc);
+                               goto out_lock;
+                       }
+                       mutex_unlock(&inode_info->lower_file_mutex);
+               }
        }
        rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
                                directory_inode->i_sb, 0);
@@ -252,6 +265,8 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
 {
        int rc;
 
+       /* ecryptfs_do_create() calls ecryptfs_interpose(), which opens
+        * the crypt_stat->lower_file (persistent file) */
        rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
        if (unlikely(rc)) {
                ecryptfs_printk(KERN_WARNING, "Failed to create file in"
index 49545951912f44ce21e6f1206a3231bc691f621a..fb9d85b5c7b835076e4428995114ea277e34556d 100644 (file)
@@ -98,6 +98,64 @@ void __ecryptfs_printk(const char *fmt, ...)
        va_end(args);
 }
 
+/**
+ * ecryptfs_init_persistent_file
+ * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with
+ *                   the lower dentry and the lower mount set
+ *
+ * eCryptfs only ever keeps a single open file for every lower
+ * inode. All I/O operations to the lower inode occur through that
+ * file. When the first eCryptfs dentry that interposes with the first
+ * lower dentry for that inode is created, this function creates the
+ * persistent file struct and associates it with the eCryptfs
+ * inode. When the eCryptfs inode is destroyed, the file is closed.
+ *
+ * The persistent file will be opened with read/write permissions, if
+ * possible. Otherwise, it is opened read-only.
+ *
+ * This function does nothing if a lower persistent file is already
+ * associated with the eCryptfs inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+{
+       struct ecryptfs_inode_info *inode_info =
+               ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
+       int rc = 0;
+
+       mutex_lock(&inode_info->lower_file_mutex);
+       if (!inode_info->lower_file) {
+               struct dentry *lower_dentry;
+               struct vfsmount *lower_mnt =
+                       ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+
+               lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+               /* Corresponding dput() and mntput() are done when the
+                * persistent file is fput() when the eCryptfs inode
+                * is destroyed. */
+               dget(lower_dentry);
+               mntget(lower_mnt);
+               inode_info->lower_file = dentry_open(lower_dentry,
+                                                    lower_mnt,
+                                                    (O_RDWR | O_LARGEFILE));
+               if (IS_ERR(inode_info->lower_file))
+                       inode_info->lower_file = dentry_open(lower_dentry,
+                                                            lower_mnt,
+                                                            (O_RDONLY
+                                                             | O_LARGEFILE));
+               if (IS_ERR(inode_info->lower_file)) {
+                       printk(KERN_ERR "Error opening lower persistent file "
+                              "for lower_dentry [0x%p] and lower_mnt [0x%p]\n",
+                              lower_dentry, lower_mnt);
+                       rc = PTR_ERR(inode_info->lower_file);
+                       inode_info->lower_file = NULL;
+               }
+       }
+       mutex_unlock(&inode_info->lower_file_mutex);
+       return rc;
+}
+
 /**
  * ecryptfs_interpose
  * @lower_dentry: Existing dentry in the lower filesystem
@@ -155,6 +213,13 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
        /* This size will be overwritten for real files w/ headers and
         * other metadata */
        fsstack_copy_inode_size(inode, lower_inode);
+       rc = ecryptfs_init_persistent_file(dentry);
+       if (rc) {
+               printk(KERN_ERR "%s: Error attempting to initialize the "
+                      "persistent file for the dentry with name [%s]; "
+                      "rc = [%d]\n", __FUNCTION__, dentry->d_name.name, rc);
+               goto out;
+       }
 out:
        return rc;
 }
index 18d77f8aa7cdecf915072b473f1cfdbe144bb564..b97e2106f670a6def24d4ed208785dd4a20e12e7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mount.h>
 #include <linux/key.h>
 #include <linux/seq_file.h>
+#include <linux/file.h>
 #include <linux/crypto.h>
 #include "ecryptfs_kernel.h"
 
@@ -63,9 +64,10 @@ out:
  * ecryptfs_destroy_inode
  * @inode: The ecryptfs 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_stat struct, will be released here.
+ * This is used during the final destruction of the inode.  All
+ * allocation of memory related to the inode, including allocated
+ * memory in the crypt_stat struct, will be released here. This
+ * function also fput()'s the persistent file for the lower inode.
  * There should be no chance that this deallocation will be missed.
  */
 static void ecryptfs_destroy_inode(struct inode *inode)
@@ -73,6 +75,20 @@ static void ecryptfs_destroy_inode(struct inode *inode)
        struct ecryptfs_inode_info *inode_info;
 
        inode_info = ecryptfs_inode_to_private(inode);
+       mutex_lock(&inode_info->lower_file_mutex);
+       if (inode_info->lower_file) {
+               struct dentry *lower_dentry =
+                       inode_info->lower_file->f_dentry;
+
+               BUG_ON(!lower_dentry);
+               if (lower_dentry->d_inode) {
+                       fput(inode_info->lower_file);
+                       inode_info->lower_file = NULL;
+                       d_drop(lower_dentry);
+                       d_delete(lower_dentry);
+               }
+       }
+       mutex_unlock(&inode_info->lower_file_mutex);
        ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
        kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
 }