lockd: fix arg parsing for grace_period and timeout.
[firefly-linux-kernel-4.4.55.git] / fs / ecryptfs / inode.c
index 7349ade17de671cabadaeb9e90ec1bdaca28e55b..2717329386d858ba9173a76e3d377efa89614394 100644 (file)
@@ -69,6 +69,7 @@ static int ecryptfs_inode_set(struct inode *inode, void *opaque)
        inode->i_ino = lower_inode->i_ino;
        inode->i_version++;
        inode->i_mapping->a_ops = &ecryptfs_aops;
+       inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
 
        if (S_ISLNK(inode->i_mode))
                inode->i_op = &ecryptfs_symlink_iops;
@@ -853,18 +854,6 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
                size_t num_zeros = (PAGE_CACHE_SIZE
                                    - (ia->ia_size & ~PAGE_CACHE_MASK));
 
-
-               /*
-                * XXX(truncate) this should really happen at the begginning
-                * of ->setattr.  But the code is too messy to that as part
-                * of a larger patch.  ecryptfs is also totally missing out
-                * on the inode_change_ok check at the beginning of
-                * ->setattr while would include this.
-                */
-               rc = inode_newsize_ok(inode, ia->ia_size);
-               if (rc)
-                       goto out;
-
                if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
                        truncate_setsize(inode, ia->ia_size);
                        lower_ia->ia_size = ia->ia_size;
@@ -914,6 +903,28 @@ out:
        return rc;
 }
 
+static int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset)
+{
+       struct ecryptfs_crypt_stat *crypt_stat;
+       loff_t lower_oldsize, lower_newsize;
+
+       crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+       lower_oldsize = upper_size_to_lower_size(crypt_stat,
+                                                i_size_read(inode));
+       lower_newsize = upper_size_to_lower_size(crypt_stat, offset);
+       if (lower_newsize > lower_oldsize) {
+               /*
+                * The eCryptfs inode and the new *lower* size are mixed here
+                * because we may not have the lower i_mutex held and/or it may
+                * not be appropriate to call inode_newsize_ok() with inodes
+                * from other filesystems.
+                */
+               return inode_newsize_ok(inode, lower_newsize);
+       }
+
+       return 0;
+}
+
 /**
  * ecryptfs_truncate
  * @dentry: The ecryptfs layer dentry
@@ -930,6 +941,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
        struct iattr lower_ia = { .ia_valid = 0 };
        int rc;
 
+       rc = ecryptfs_inode_newsize_ok(dentry->d_inode, new_length);
+       if (rc)
+               return rc;
+
        rc = truncate_upper(dentry, &ia, &lower_ia);
        if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
                struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
@@ -1011,6 +1026,16 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
                }
        }
        mutex_unlock(&crypt_stat->cs_mutex);
+
+       rc = inode_change_ok(inode, ia);
+       if (rc)
+               goto out;
+       if (ia->ia_valid & ATTR_SIZE) {
+               rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size);
+               if (rc)
+                       goto out;
+       }
+
        if (S_ISREG(inode->i_mode)) {
                rc = filemap_write_and_wait(inode->i_mapping);
                if (rc)
@@ -1094,6 +1119,8 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
        }
 
        rc = vfs_setxattr(lower_dentry, name, value, size, flags);
+       if (!rc)
+               fsstack_copy_attr_all(dentry->d_inode, lower_dentry->d_inode);
 out:
        return rc;
 }