]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/ecryptfs/main.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[mv-sheeva.git] / fs / ecryptfs / main.c
index 00686f1c59976a01188b9729a2a408219a87ef9f..b83a512b7e085183e6ea3edb15c8dda3047889b5 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/crypto.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>
@@ -98,6 +97,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 +212,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;
 }
@@ -546,7 +610,7 @@ static struct file_system_type ecryptfs_fs_type = {
  * Initializes the ecryptfs_inode_info_cache when it is created
  */
 static void
-inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
+inode_info_init_once(struct kmem_cache *cachep, void *vptr)
 {
        struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
 
@@ -557,7 +621,7 @@ static struct ecryptfs_cache_info {
        struct kmem_cache **cache;
        const char *name;
        size_t size;
-       void (*ctor)(void*, struct kmem_cache *, unsigned long);
+       void (*ctor)(struct kmem_cache *cache, void *obj);
 } ecryptfs_cache_infos[] = {
        {
                .cache = &ecryptfs_auth_tok_list_item_cache,
@@ -605,11 +669,6 @@ static struct ecryptfs_cache_info {
                .name = "ecryptfs_xattr_cache",
                .size = PAGE_CACHE_SIZE,
        },
-       {
-               .cache = &ecryptfs_lower_page_cache,
-               .name = "ecryptfs_lower_page_cache",
-               .size = PAGE_CACHE_SIZE,
-       },
        {
                .cache = &ecryptfs_key_record_cache,
                .name = "ecryptfs_key_record_cache",
@@ -799,13 +858,6 @@ out:
 
 static void do_sysfs_unregistration(void)
 {
-       int rc;
-
-       rc = ecryptfs_destroy_crypto();
-       if (rc) {
-               printk(KERN_ERR "Failure whilst attempting to destroy crypto; "
-                      "rc = [%d]\n", rc);
-       }
        sysfs_remove_file(&ecryptfs_subsys.kobj,
                          &sysfs_attr_version.attr);
        sysfs_remove_file(&ecryptfs_subsys.kobj,
@@ -836,43 +888,49 @@ static int __init ecryptfs_init(void)
        rc = register_filesystem(&ecryptfs_fs_type);
        if (rc) {
                printk(KERN_ERR "Failed to register filesystem\n");
-               ecryptfs_free_kmem_caches();
-               goto out;
+               goto out_free_kmem_caches;
        }
        kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
        rc = do_sysfs_registration();
        if (rc) {
                printk(KERN_ERR "sysfs registration failed\n");
-               unregister_filesystem(&ecryptfs_fs_type);
-               ecryptfs_free_kmem_caches();
-               goto out;
+               goto out_unregister_filesystem;
        }
        rc = ecryptfs_init_messaging(ecryptfs_transport);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Failure occured while attempting to "
                                "initialize the eCryptfs netlink socket\n");
-               do_sysfs_unregistration();
-               unregister_filesystem(&ecryptfs_fs_type);
-               ecryptfs_free_kmem_caches();
-               goto out;
+               goto out_do_sysfs_unregistration;
        }
        rc = ecryptfs_init_crypto();
        if (rc) {
                printk(KERN_ERR "Failure whilst attempting to init crypto; "
                       "rc = [%d]\n", rc);
-               do_sysfs_unregistration();
-               unregister_filesystem(&ecryptfs_fs_type);
-               ecryptfs_free_kmem_caches();
-               goto out;
+               goto out_release_messaging;
        }
+       goto out;
+out_release_messaging:
+       ecryptfs_release_messaging(ecryptfs_transport);
+out_do_sysfs_unregistration:
+       do_sysfs_unregistration();
+out_unregister_filesystem:
+       unregister_filesystem(&ecryptfs_fs_type);
+out_free_kmem_caches:
+       ecryptfs_free_kmem_caches();
 out:
        return rc;
 }
 
 static void __exit ecryptfs_exit(void)
 {
-       do_sysfs_unregistration();
+       int rc;
+
+       rc = ecryptfs_destroy_crypto();
+       if (rc)
+               printk(KERN_ERR "Failure whilst attempting to destroy crypto; "
+                      "rc = [%d]\n", rc);
        ecryptfs_release_messaging(ecryptfs_transport);
+       do_sysfs_unregistration();
        unregister_filesystem(&ecryptfs_fs_type);
        ecryptfs_free_kmem_caches();
 }