eCryptfs: Handle failed metadata read in lookup
[linux-flexiantxendom0-natty.git] / fs / ecryptfs / file.c
index e7440a6..d30aac2 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/security.h>
 #include <linux/compat.h>
 #include <linux/fs_stack.h>
-#include <linux/smp_lock.h>
 #include "ecryptfs_kernel.h"
 
 /**
@@ -48,7 +47,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
                                const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos)
 {
-       int rc;
+       ssize_t rc;
        struct dentry *lower_dentry;
        struct vfsmount *lower_vfsmount;
        struct file *file = iocb->ki_filp;
@@ -192,29 +191,28 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                                      | ECRYPTFS_ENCRYPTED);
        }
        mutex_unlock(&crypt_stat->cs_mutex);
-       if (!ecryptfs_inode_to_private(inode)->lower_file) {
-               rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
-               if (rc) {
-                       printk(KERN_ERR "%s: Error attempting to initialize "
-                              "the persistent file for the dentry with name "
-                              "[%s]; rc = [%d]\n", __func__,
-                              ecryptfs_dentry->d_name.name, rc);
-                       goto out;
-               }
+       rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+       if (rc) {
+               printk(KERN_ERR "%s: Error attempting to initialize "
+                       "the persistent file for the dentry with name "
+                       "[%s]; rc = [%d]\n", __func__,
+                       ecryptfs_dentry->d_name.name, rc);
+               goto out_free;
        }
-       if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY)
-           && !(file->f_flags & O_RDONLY)) {
+       if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
+           == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
                rc = -EPERM;
                printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs "
                       "file must hence be opened RO\n", __func__);
-               goto out;
+               goto out_free;
        }
        ecryptfs_set_file_lower(
                file, ecryptfs_inode_to_private(inode)->lower_file);
        if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
                ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
                mutex_lock(&crypt_stat->cs_mutex);
-               crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+               crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
+                                       | ECRYPTFS_ENCRYPTED);
                mutex_unlock(&crypt_stat->cs_mutex);
                rc = 0;
                goto out;
@@ -244,9 +242,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                }
        }
        mutex_unlock(&crypt_stat->cs_mutex);
-       ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
-                       "size: [0x%.16x]\n", inode, inode->i_ino,
-                       i_size_read(inode));
+       ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
+                       "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
+                       (unsigned long long)i_size_read(inode));
        goto out;
 out_free:
        kmem_cache_free(ecryptfs_file_info_cache,
@@ -274,11 +272,9 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
 }
 
 static int
-ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+ecryptfs_fsync(struct file *file, int datasync)
 {
-       return vfs_fsync(ecryptfs_file_to_lower(file),
-                        ecryptfs_dentry_to_lower(dentry),
-                        datasync);
+       return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
 }
 
 static int ecryptfs_fasync(int fd, struct file *file, int flag)
@@ -286,26 +282,54 @@ static int ecryptfs_fasync(int fd, struct file *file, int flag)
        int rc = 0;
        struct file *lower_file = NULL;
 
-       lock_kernel();
        lower_file = ecryptfs_file_to_lower(file);
        if (lower_file->f_op && lower_file->f_op->fasync)
                rc = lower_file->f_op->fasync(fd, lower_file, flag);
-       unlock_kernel();
        return rc;
 }
 
-static int ecryptfs_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg);
+static long
+ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct file *lower_file = NULL;
+       long rc = -ENOTTY;
+
+       if (ecryptfs_file_to_private(file))
+               lower_file = ecryptfs_file_to_lower(file);
+       if (lower_file && lower_file->f_op && lower_file->f_op->unlocked_ioctl)
+               rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
+       return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct file *lower_file = NULL;
+       long rc = -ENOIOCTLCMD;
+
+       if (ecryptfs_file_to_private(file))
+               lower_file = ecryptfs_file_to_lower(file);
+       if (lower_file && lower_file->f_op && lower_file->f_op->compat_ioctl)
+               rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+       return rc;
+}
+#endif
 
 const struct file_operations ecryptfs_dir_fops = {
        .readdir = ecryptfs_readdir,
-       .ioctl = ecryptfs_ioctl,
+       .read = generic_read_dir,
+       .unlocked_ioctl = ecryptfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = ecryptfs_compat_ioctl,
+#endif
        .open = ecryptfs_open,
        .flush = ecryptfs_flush,
        .release = ecryptfs_release,
        .fsync = ecryptfs_fsync,
        .fasync = ecryptfs_fasync,
        .splice_read = generic_file_splice_read,
+       .llseek = default_llseek,
 };
 
 const struct file_operations ecryptfs_main_fops = {
@@ -315,7 +339,10 @@ const struct file_operations ecryptfs_main_fops = {
        .write = do_sync_write,
        .aio_write = generic_file_aio_write,
        .readdir = ecryptfs_readdir,
-       .ioctl = ecryptfs_ioctl,
+       .unlocked_ioctl = ecryptfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = ecryptfs_compat_ioctl,
+#endif
        .mmap = generic_file_mmap,
        .open = ecryptfs_open,
        .flush = ecryptfs_flush,
@@ -324,20 +351,3 @@ const struct file_operations ecryptfs_main_fops = {
        .fasync = ecryptfs_fasync,
        .splice_read = generic_file_splice_read,
 };
-
-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))
-               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;
-}