reiserfs: Don't call reiserfs_get_acl() with the reiserfs lock
[safe/jmp/linux-2.6] / fs / ecryptfs / inode.c
index 7168a88..056fed6 100644 (file)
@@ -52,8 +52,7 @@ static void unlock_dir(struct dentry *dir)
 /**
  * ecryptfs_create_underlying_file
  * @lower_dir_inode: inode of the parent in the lower fs of the new file
- * @lower_dentry: New file's dentry in the lower fs
- * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @dentry: New file's dentry
  * @mode: The mode of the new file
  * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
  *
@@ -247,7 +246,6 @@ out:
  */
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
-                                       struct ecryptfs_crypt_stat *crypt_stat,
                                        struct inode *ecryptfs_dir_inode,
                                        struct nameidata *ecryptfs_nd)
 {
@@ -255,6 +253,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
        struct vfsmount *lower_mnt;
        struct inode *lower_inode;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+       struct ecryptfs_crypt_stat *crypt_stat;
        char *page_virt = NULL;
        u64 file_size;
        int rc = 0;
@@ -315,6 +314,11 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                        goto out_free_kmem;
                }
        }
+       crypt_stat = &ecryptfs_inode_to_private(
+                                       ecryptfs_dentry->d_inode)->crypt_stat;
+       /* TODO: lock for crypt_stat comparison */
+       if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
+                       ecryptfs_set_default_sizes(crypt_stat);
        rc = ecryptfs_read_and_validate_header_region(page_virt,
                                                      ecryptfs_dentry->d_inode);
        if (rc) {
@@ -363,9 +367,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
 {
        char *encrypted_and_encoded_name = NULL;
        size_t encrypted_and_encoded_name_size;
-       struct ecryptfs_crypt_stat *crypt_stat = NULL;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
-       struct ecryptfs_inode_info *inode_info;
        struct dentry *lower_dir_dentry, *lower_dentry;
        int rc = 0;
 
@@ -377,9 +379,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                goto out_d_drop;
        }
        lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
        lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,
                                      lower_dir_dentry,
                                      ecryptfs_dentry->d_name.len);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
                printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
@@ -389,35 +393,26 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        }
        if (lower_dentry->d_inode)
                goto lookup_and_interpose;
-       inode_info =  ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
-       if (inode_info) {
-               crypt_stat = &inode_info->crypt_stat;
-               /* TODO: lock for crypt_stat comparison */
-               if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
-                       ecryptfs_set_default_sizes(crypt_stat);
-       }
-       if (crypt_stat)
-               mount_crypt_stat = crypt_stat->mount_crypt_stat;
-       else
-               mount_crypt_stat = &ecryptfs_superblock_to_private(
-                       ecryptfs_dentry->d_sb)->mount_crypt_stat;
-       if (!(crypt_stat && (crypt_stat->flags & ECRYPTFS_ENCRYPT_FILENAMES))
-           && !(mount_crypt_stat && (mount_crypt_stat->flags
-                                    & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
+       mount_crypt_stat = &ecryptfs_superblock_to_private(
+                               ecryptfs_dentry->d_sb)->mount_crypt_stat;
+       if (!(mount_crypt_stat
+           && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
                goto lookup_and_interpose;
        dput(lower_dentry);
        rc = ecryptfs_encrypt_and_encode_filename(
                &encrypted_and_encoded_name, &encrypted_and_encoded_name_size,
-               crypt_stat, mount_crypt_stat, ecryptfs_dentry->d_name.name,
+               NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name,
                ecryptfs_dentry->d_name.len);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to encrypt and encode "
                       "filename; rc = [%d]\n", __func__, rc);
                goto out_d_drop;
        }
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
        lower_dentry = lookup_one_len(encrypted_and_encoded_name,
                                      lower_dir_dentry,
                                      encrypted_and_encoded_name_size - 1);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
                printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
@@ -427,7 +422,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        }
 lookup_and_interpose:
        rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
-                                                crypt_stat, ecryptfs_dir_inode,
+                                                ecryptfs_dir_inode,
                                                 ecryptfs_nd);
        goto out;
 out_d_drop:
@@ -481,6 +476,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
        struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
        struct dentry *lower_dir_dentry;
 
+       dget(lower_dentry);
        lower_dir_dentry = lock_parent(lower_dentry);
        rc = vfs_unlink(lower_dir_inode, lower_dentry);
        if (rc) {
@@ -494,6 +490,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
        d_drop(dentry);
 out_unlock:
        unlock_dir(lower_dir_dentry);
+       dput(lower_dentry);
        return rc;
 }
 
@@ -645,8 +642,9 @@ static int
 ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 {
        char *lower_buf;
+       size_t lower_bufsiz;
        struct dentry *lower_dentry;
-       struct ecryptfs_crypt_stat *crypt_stat;
+       struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
        char *plaintext_name;
        size_t plaintext_name_size;
        mm_segment_t old_fs;
@@ -657,12 +655,21 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
                rc = -EINVAL;
                goto out;
        }
-       crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+       mount_crypt_stat = &ecryptfs_superblock_to_private(
+                                               dentry->d_sb)->mount_crypt_stat;
+       /*
+        * If the lower filename is encrypted, it will result in a significantly
+        * longer name.  If needed, truncate the name after decode and decrypt.
+        */
+       if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
+               lower_bufsiz = PATH_MAX;
+       else
+               lower_bufsiz = bufsiz;
        /* Released in this function */
-       lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+       lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);
        if (lower_buf == NULL) {
                printk(KERN_ERR "%s: Out of memory whilst attempting to "
-                      "kmalloc [%d] bytes\n", __func__, bufsiz);
+                      "kmalloc [%zd] bytes\n", __func__, lower_bufsiz);
                rc = -ENOMEM;
                goto out;
        }
@@ -670,7 +677,7 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
        set_fs(get_ds());
        rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
                                                   (char __user *)lower_buf,
-                                                  bufsiz);
+                                                  lower_bufsiz);
        set_fs(old_fs);
        if (rc >= 0) {
                rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name,
@@ -683,7 +690,9 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
                                rc);
                        goto out_free_lower_buf;
                }
-               rc = copy_to_user(buf, plaintext_name, plaintext_name_size);
+               /* Check for bufsiz <= 0 done in sys_readlinkat() */
+               rc = copy_to_user(buf, plaintext_name,
+                                 min((size_t) bufsiz, plaintext_name_size));
                if (rc)
                        rc = -EFAULT;
                else
@@ -823,6 +832,13 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
                size_t num_zeros = (PAGE_CACHE_SIZE
                                    - (new_length & ~PAGE_CACHE_MASK));
 
+               if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
+                       rc = vmtruncate(inode, new_length);
+                       if (rc)
+                               goto out_free;
+                       rc = vmtruncate(lower_dentry->d_inode, new_length);
+                       goto out_free;
+               }
                if (num_zeros) {
                        char *zeros_virt;
 
@@ -924,8 +940,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
                        }
                        rc = 0;
                        crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
-                       mutex_unlock(&crypt_stat->cs_mutex);
-                       goto out;
                }
        }
        mutex_unlock(&crypt_stat->cs_mutex);