Merge branch 'xfs-O_TMPFILE-support' into for-next
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_iops.c
index cb06cc4d0003166031931e98ea2b5728cd6fd244..89b07e43ca28811349db39aa1ab2534de220fd87 100644 (file)
 #include <linux/fiemap.h>
 #include <linux/slab.h>
 
+/*
+ * Directories have different lock order w.r.t. mmap_sem compared to regular
+ * files. This is due to readdir potentially triggering page faults on a user
+ * buffer inside filldir(), and this happens with the ilock on the directory
+ * held. For regular files, the lock order is the other way around - the
+ * mmap_sem is taken during the page fault, and then we lock the ilock to do
+ * block mapping. Hence we need a different class for the directory ilock so
+ * that lockdep can tell them apart.
+ */
+static struct lock_class_key xfs_nondir_ilock_class;
+static struct lock_class_key xfs_dir_ilock_class;
+
 static int
 xfs_initxattrs(
        struct inode            *inode,
@@ -124,7 +136,7 @@ xfs_vn_mknod(
 {
        struct inode    *inode;
        struct xfs_inode *ip = NULL;
-       struct posix_acl *default_acl = NULL;
+       struct posix_acl *default_acl, *acl;
        struct xfs_name name;
        int             error;
 
@@ -140,14 +152,9 @@ xfs_vn_mknod(
                rdev = 0;
        }
 
-       if (IS_POSIXACL(dir)) {
-               default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
-               if (IS_ERR(default_acl))
-                       return PTR_ERR(default_acl);
-
-               if (!default_acl)
-                       mode &= ~current_umask();
-       }
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error)
+               return error;
 
        xfs_dentry_to_name(&name, dentry, mode);
        error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
@@ -160,22 +167,30 @@ xfs_vn_mknod(
        if (unlikely(error))
                goto out_cleanup_inode;
 
+#ifdef CONFIG_XFS_POSIX_ACL
        if (default_acl) {
-               error = -xfs_inherit_acl(inode, default_acl);
-               default_acl = NULL;
-               if (unlikely(error))
+               error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               if (error)
                        goto out_cleanup_inode;
        }
-
+       if (acl) {
+               error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               if (error)
+                       goto out_cleanup_inode;
+       }
+#endif
 
        d_instantiate(dentry, inode);
+ out_free_acl:
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
        return -error;
 
  out_cleanup_inode:
        xfs_cleanup_inode(dir, inode, dentry);
- out_free_acl:
-       posix_acl_release(default_acl);
-       return -error;
+       goto out_free_acl;
 }
 
 STATIC int
@@ -392,18 +407,6 @@ xfs_vn_follow_link(
        return NULL;
 }
 
-STATIC void
-xfs_vn_put_link(
-       struct dentry   *dentry,
-       struct nameidata *nd,
-       void            *p)
-{
-       char            *s = nd_get_link(nd);
-
-       if (!IS_ERR(s))
-               kfree(s);
-}
-
 STATIC int
 xfs_vn_getattr(
        struct vfsmount         *mnt,
@@ -689,7 +692,7 @@ xfs_setattr_nonsize(
         *           Posix ACL code seems to care about this issue either.
         */
        if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
-               error = -xfs_acl_chmod(inode);
+               error = -posix_acl_chmod(inode, inode->i_mode);
                if (error)
                        return XFS_ERROR(error);
        }
@@ -715,7 +718,6 @@ xfs_setattr_size(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
-       int                     mask = iattr->ia_valid;
        xfs_off_t               oldsize, newsize;
        struct xfs_trans        *tp;
        int                     error;
@@ -736,8 +738,8 @@ xfs_setattr_size(
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
        ASSERT(S_ISREG(ip->i_d.di_mode));
-       ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
-                       ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
+       ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
+               ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
 
        oldsize = inode->i_size;
        newsize = iattr->ia_size;
@@ -746,7 +748,7 @@ xfs_setattr_size(
         * Short circuit the truncate case for zero length files.
         */
        if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
-               if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
+               if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME)))
                        return 0;
 
                /*
@@ -834,10 +836,11 @@ xfs_setattr_size(
         * these flags set.  For all other operations the VFS set these flags
         * explicitly if it wants a timestamp update.
         */
-       if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+       if (newsize != oldsize &&
+           !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
                iattr->ia_ctime = iattr->ia_mtime =
                        current_fs_time(inode->i_sb);
-               mask |= ATTR_CTIME | ATTR_MTIME;
+               iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
        }
 
        /*
@@ -873,9 +876,9 @@ xfs_setattr_size(
                xfs_inode_clear_eofblocks_tag(ip);
        }
 
-       if (mask & ATTR_MODE)
+       if (iattr->ia_valid & ATTR_MODE)
                xfs_setattr_mode(ip, iattr);
-       if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
+       if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
                xfs_setattr_time(ip, iattr);
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -1059,6 +1062,7 @@ xfs_vn_tmpfile(
 
 static const struct inode_operations xfs_inode_operations = {
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1086,6 +1090,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
        .mknod                  = xfs_vn_mknod,
        .rename                 = xfs_vn_rename,
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1113,6 +1118,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
        .mknod                  = xfs_vn_mknod,
        .rename                 = xfs_vn_rename,
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1126,8 +1132,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 static const struct inode_operations xfs_symlink_inode_operations = {
        .readlink               = generic_readlink,
        .follow_link            = xfs_vn_follow_link,
-       .put_link               = xfs_vn_put_link,
-       .get_acl                = xfs_get_acl,
+       .put_link               = kfree_put_link,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1214,6 +1219,7 @@ xfs_setup_inode(
        xfs_diflags_to_iflags(inode, ip);
 
        ip->d_ops = ip->i_mount->m_nondir_inode_ops;
+       lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
        switch (inode->i_mode & S_IFMT) {
        case S_IFREG:
                inode->i_op = &xfs_inode_operations;
@@ -1221,6 +1227,7 @@ xfs_setup_inode(
                inode->i_mapping->a_ops = &xfs_address_space_operations;
                break;
        case S_IFDIR:
+               lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class);
                if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb))
                        inode->i_op = &xfs_dir_ci_inode_operations;
                else