]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge branch 'xfs-4.7-optimise-inline-symlinks' into for-next
authorDave Chinner <david@fromorbit.com>
Fri, 20 May 2016 00:32:10 +0000 (10:32 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 20 May 2016 00:32:10 +0000 (10:32 +1000)
1  2 
fs/xfs/xfs_inode.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_symlink.c

diff --combined fs/xfs/xfs_inode.c
index b82c729634f6ee30a0f1b19082394ea188f91b9c,4fcd6a722213fdc4955092e1508f8d3d0fb20396..ca270d9bbb908c162d42017b2ae5bed9a83f4620
@@@ -1161,9 -1161,11 +1161,9 @@@ xfs_create
                rdev = 0;
                resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
                tres = &M_RES(mp)->tr_mkdir;
 -              tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
        } else {
                resblks = XFS_CREATE_SPACE_RES(mp, name->len);
                tres = &M_RES(mp)->tr_create;
 -              tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
        }
  
        /*
         * the case we'll drop the one we have and get a more
         * appropriate transaction later.
         */
 -      error = xfs_trans_reserve(tp, tres, resblks, 0);
 +      error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
        if (error == -ENOSPC) {
                /* flush outstanding delalloc blocks and retry */
                xfs_flush_inodes(mp);
 -              error = xfs_trans_reserve(tp, tres, resblks, 0);
 +              error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
        }
        if (error == -ENOSPC) {
                /* No space at all so try a "no-allocation" reservation */
                resblks = 0;
 -              error = xfs_trans_reserve(tp, tres, 0, 0);
 +              error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp);
        }
        if (error)
 -              goto out_trans_cancel;
 -
 +              goto out_release_inode;
  
        xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL |
                      XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT);
@@@ -1334,16 -1337,17 +1334,16 @@@ xfs_create_tmpfile
                return error;
  
        resblks = XFS_IALLOC_SPACE_RES(mp);
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE);
 -
        tres = &M_RES(mp)->tr_create_tmpfile;
 -      error = xfs_trans_reserve(tp, tres, resblks, 0);
 +
 +      error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);
        if (error == -ENOSPC) {
                /* No space at all so try a "no-allocation" reservation */
                resblks = 0;
 -              error = xfs_trans_reserve(tp, tres, 0, 0);
 +              error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp);
        }
        if (error)
 -              goto out_trans_cancel;
 +              goto out_release_inode;
  
        error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
                                                pdqp, resblks, 1, 0);
@@@ -1428,14 -1432,15 +1428,14 @@@ xfs_link
        if (error)
                goto std_return;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
        resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, resblks, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
        if (error == -ENOSPC) {
                resblks = 0;
 -              error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, 0, 0);
 +              error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &tp);
        }
        if (error)
 -              goto error_return;
 +              goto std_return;
  
        xfs_ilock(tdp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
        xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
@@@ -1705,9 -1710,11 +1705,9 @@@ xfs_inactive_truncate
        struct xfs_trans        *tp;
        int                     error;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
        if (error) {
                ASSERT(XFS_FORCED_SHUTDOWN(mp));
 -              xfs_trans_cancel(tp);
                return error;
        }
  
@@@ -1757,6 -1764,8 +1757,6 @@@ xfs_inactive_ifree
        struct xfs_trans        *tp;
        int                     error;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 -
        /*
         * The ifree transaction might need to allocate blocks for record
         * insertion to the finobt. We don't want to fail here at ENOSPC, so
         * now remains allocated and sits on the unlinked list until the fs is
         * repaired.
         */
 -      tp->t_flags |= XFS_TRANS_RESERVE;
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
 -                                XFS_IFREE_SPACE_RES(mp), 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree,
 +                      XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
        if (error) {
                if (error == -ENOSPC) {
                        xfs_warn_ratelimited(mp,
                } else {
                        ASSERT(XFS_FORCED_SHUTDOWN(mp));
                }
 -              xfs_trans_cancel(tp);
                return error;
        }
  
@@@ -2514,6 -2525,11 +2514,6 @@@ xfs_remove
        if (error)
                goto std_return;
  
 -      if (is_dir)
 -              tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
 -      else
 -              tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
 -
        /*
         * We try to get the real space reservation first,
         * allowing for directory btree deletion(s) implying
         * block from the directory.
         */
        resblks = XFS_REMOVE_SPACE_RES(mp);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, resblks, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, resblks, 0, 0, &tp);
        if (error == -ENOSPC) {
                resblks = 0;
 -              error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, 0, 0);
 +              error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, 0, 0, 0,
 +                              &tp);
        }
        if (error) {
                ASSERT(error != -ENOSPC);
 -              goto out_trans_cancel;
 +              goto std_return;
        }
  
        xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
@@@ -2840,6 -2855,7 +2840,7 @@@ xfs_rename_alloc_whiteout
         * and flag it as linkable.
         */
        drop_nlink(VFS_I(tmpfile));
+       xfs_setup_iops(tmpfile);
        xfs_finish_inode_setup(tmpfile);
        VFS_I(tmpfile)->i_state |= I_LINKABLE;
  
@@@ -2895,15 -2911,15 +2896,15 @@@ xfs_rename
        xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
                                inodes, &num_inodes);
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
        spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, spaceres, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp);
        if (error == -ENOSPC) {
                spaceres = 0;
 -              error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, 0, 0);
 +              error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, 0, 0, 0,
 +                              &tp);
        }
        if (error)
 -              goto out_trans_cancel;
 +              goto out_release_wip;
  
        /*
         * Attach the dquots to the inodes
@@@ -3140,7 -3156,6 +3141,7 @@@ out_bmap_cancel
        xfs_bmap_cancel(&free_list);
  out_trans_cancel:
        xfs_trans_cancel(tp);
 +out_release_wip:
        if (wip)
                IRELE(wip);
        return error;
diff --combined fs/xfs/xfs_ioctl.c
index 6f82187ee297b28dd19024dae0a58fa0ef1ce7b3,5414bcaf2e730bc912382f73dcc2efd556a3c15d..dbca7375deefa3f7d2499f516697ffdd28178546
@@@ -277,7 -277,6 +277,6 @@@ xfs_readlink_by_handle
  {
        struct dentry           *dentry;
        __u32                   olen;
-       void                    *link;
        int                     error;
  
        if (!capable(CAP_SYS_ADMIN))
                return PTR_ERR(dentry);
  
        /* Restrict this handle operation to symlinks only. */
-       if (!d_is_symlink(dentry)) {
+       if (!d_inode(dentry)->i_op->readlink) {
                error = -EINVAL;
                goto out_dput;
        }
                goto out_dput;
        }
  
-       link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
-       if (!link) {
-               error = -ENOMEM;
-               goto out_dput;
-       }
-       error = xfs_readlink(XFS_I(d_inode(dentry)), link);
-       if (error)
-               goto out_kfree;
-       error = readlink_copy(hreq->ohandle, olen, link);
-       if (error)
-               goto out_kfree;
+       error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen);
  
-  out_kfree:
-       kfree(link);
   out_dput:
        dput(dentry);
        return error;
@@@ -334,10 -320,12 +320,10 @@@ xfs_set_dmattrs
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
 -      if (error) {
 -              xfs_trans_cancel(tp);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp);
 +      if (error)
                return error;
 -      }
 +
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
  
@@@ -1139,9 -1127,10 +1125,9 @@@ xfs_ioctl_setattr_get_trans
        if (XFS_FORCED_SHUTDOWN(mp))
                goto out_unlock;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp);
        if (error)
 -              goto out_cancel;
 +              return ERR_PTR(error);
  
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags);
diff --combined fs/xfs/xfs_iops.c
index fc7766164dc960a217d00fa0ea960f5ba56d8d73,aee06d9a7b6cb11a6399f6fc7775169bbc2ae5e1..c5d4eba6972eb17327be763e7bd914c5f4da3a59
@@@ -181,6 -181,8 +181,8 @@@ xfs_generic_create
        }
  #endif
  
+       xfs_setup_iops(ip);
        if (tmpfile)
                d_tmpfile(dentry, inode);
        else
@@@ -368,6 -370,8 +370,8 @@@ xfs_vn_symlink
        if (unlikely(error))
                goto out_cleanup_inode;
  
+       xfs_setup_iops(cip);
        d_instantiate(dentry, inode);
        xfs_finish_inode_setup(cip);
        return 0;
@@@ -442,6 -446,16 +446,16 @@@ xfs_vn_get_link
        return ERR_PTR(error);
  }
  
+ STATIC const char *
+ xfs_vn_get_link_inline(
+       struct dentry           *dentry,
+       struct inode            *inode,
+       struct delayed_call     *done)
+ {
+       ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE);
+       return XFS_I(inode)->i_df.if_u1.if_data;
+ }
  STATIC int
  xfs_vn_getattr(
        struct vfsmount         *mnt,
@@@ -599,12 -613,12 +613,12 @@@ xfs_setattr_nonsize
                        return error;
        }
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp);
        if (error)
 -              goto out_trans_cancel;
 +              goto out_dqrele;
  
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 +      xfs_trans_ijoin(tp, ip, 0);
  
        /*
         * Change file ownership.  Must be the owner or privileged.
                                                NULL, capable(CAP_FOWNER) ?
                                                XFS_QMOPT_FORCE_RES : 0);
                        if (error)      /* out of quota */
 -                              goto out_unlock;
 +                              goto out_cancel;
                }
        }
  
 -      xfs_trans_ijoin(tp, ip, 0);
 -
        /*
         * Change file ownership.  Must be the owner or privileged.
         */
  
        return 0;
  
 -out_unlock:
 -      xfs_iunlock(ip, XFS_ILOCK_EXCL);
 -out_trans_cancel:
 +out_cancel:
        xfs_trans_cancel(tp);
 +out_dqrele:
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
        return error;
@@@ -831,7 -848,7 +845,7 @@@ xfs_setattr_size
         * We have to do all the page cache truncate work outside the
         * transaction context as the "lock" order is page lock->log space
         * reservation as defined by extent allocation in the writeback path.
 -       * Hence a truncate can fail with ENOMEM from xfs_trans_reserve(), but
 +       * Hence a truncate can fail with ENOMEM from xfs_trans_alloc(), but
         * having already truncated the in-memory version of the file (i.e. made
         * user visible changes). There's not much we can do about this, except
         * to hope that the caller sees ENOMEM and retries the truncate
                return error;
        truncate_setsize(inode, newsize);
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
        if (error)
 -              goto out_trans_cancel;
 +              return error;
  
        lock_flags |= XFS_ILOCK_EXCL;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
@@@ -967,9 -985,12 +981,9 @@@ xfs_vn_update_time
  
        trace_xfs_update_time(ip);
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0);
 -      if (error) {
 -              xfs_trans_cancel(tp);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
 +      if (error)
                return error;
 -      }
  
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        if (flags & S_CTIME)
@@@ -1160,6 -1181,18 +1174,18 @@@ static const struct inode_operations xf
        .update_time            = xfs_vn_update_time,
  };
  
+ static const struct inode_operations xfs_inline_symlink_inode_operations = {
+       .readlink               = generic_readlink,
+       .get_link               = xfs_vn_get_link_inline,
+       .getattr                = xfs_vn_getattr,
+       .setattr                = xfs_vn_setattr,
+       .setxattr               = generic_setxattr,
+       .getxattr               = generic_getxattr,
+       .removexattr            = generic_removexattr,
+       .listxattr              = xfs_vn_listxattr,
+       .update_time            = xfs_vn_update_time,
+ };
  STATIC void
  xfs_diflags_to_iflags(
        struct inode            *inode,
  }
  
  /*
-  * Initialize the Linux inode and set up the operation vectors.
+  * Initialize the Linux inode.
   *
   * When reading existing inodes from disk this is called directly from xfs_iget,
   * when creating a new inode it is called from xfs_ialloc after setting up the
@@@ -1225,32 -1258,12 +1251,12 @@@ xfs_setup_inode
        i_size_write(inode, ip->i_d.di_size);
        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;
-               inode->i_fop = &xfs_file_operations;
-               inode->i_mapping->a_ops = &xfs_address_space_operations;
-               break;
-       case S_IFDIR:
+       if (S_ISDIR(inode->i_mode)) {
                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
-                       inode->i_op = &xfs_dir_inode_operations;
-               inode->i_fop = &xfs_dir_file_operations;
                ip->d_ops = ip->i_mount->m_dir_inode_ops;
-               break;
-       case S_IFLNK:
-               inode->i_op = &xfs_symlink_inode_operations;
-               if (!(ip->i_df.if_flags & XFS_IFINLINE))
-                       inode->i_mapping->a_ops = &xfs_address_space_operations;
-               break;
-       default:
-               inode->i_op = &xfs_inode_operations;
-               init_special_inode(inode, inode->i_mode, inode->i_rdev);
-               break;
+       } else {
+               ip->d_ops = ip->i_mount->m_nondir_inode_ops;
+               lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
        }
  
        /*
                cache_no_acl(inode);
        }
  }
+ void
+ xfs_setup_iops(
+       struct xfs_inode        *ip)
+ {
+       struct inode            *inode = &ip->i_vnode;
+       switch (inode->i_mode & S_IFMT) {
+       case S_IFREG:
+               inode->i_op = &xfs_inode_operations;
+               inode->i_fop = &xfs_file_operations;
+               inode->i_mapping->a_ops = &xfs_address_space_operations;
+               break;
+       case S_IFDIR:
+               if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb))
+                       inode->i_op = &xfs_dir_ci_inode_operations;
+               else
+                       inode->i_op = &xfs_dir_inode_operations;
+               inode->i_fop = &xfs_dir_file_operations;
+               break;
+       case S_IFLNK:
+               if (ip->i_df.if_flags & XFS_IFINLINE)
+                       inode->i_op = &xfs_inline_symlink_inode_operations;
+               else
+                       inode->i_op = &xfs_symlink_inode_operations;
+               break;
+       default:
+               inode->i_op = &xfs_inode_operations;
+               init_special_inode(inode, inode->i_mode, inode->i_rdev);
+               break;
+       }
+ }
diff --combined fs/xfs/xfs_symlink.c
index c3aeaa884478b40584fbb0207a123826ad0cd513,5961c1e880c265c64b53badd7ec3b2a8991e7720..08a46c6181fdb698bf6b6deed28e21fa6c01ce7d
@@@ -131,6 -131,8 +131,8 @@@ xfs_readlink
  
        trace_xfs_readlink(ip);
  
+       ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
  
        }
  
  
-       if (ip->i_df.if_flags & XFS_IFINLINE) {
-               memcpy(link, ip->i_df.if_u1.if_data, pathlen);
-               link[pathlen] = '\0';
-       } else {
-               error = xfs_readlink_bmap(ip, link);
-       }
+       error = xfs_readlink_bmap(ip, link);
  
   out:
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@@ -221,6 -218,7 +218,6 @@@ xfs_symlink
        if (error)
                return error;
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
        /*
         * The symlink will fit into the inode data fork?
         * There can't be any attributes so we get the whole variable part.
        else
                fs_blocks = xfs_symlink_blocks(mp, pathlen);
        resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_symlink, resblks, 0);
 +
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp);
        if (error == -ENOSPC && fs_blocks == 0) {
                resblks = 0;
 -              error = xfs_trans_reserve(tp, &M_RES(mp)->tr_symlink, 0, 0);
 +              error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, 0, 0, 0,
 +                              &tp);
        }
        if (error)
 -              goto out_trans_cancel;
 +              goto out_release_inode;
  
        xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL |
                      XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT);
         * If the symlink will fit into the inode, write it inline.
         */
        if (pathlen <= XFS_IFORK_DSIZE(ip)) {
-               xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
-               memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
-               ip->i_d.di_size = pathlen;
-               /*
-                * The inode was initially created in extent format.
-                */
-               ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
-               ip->i_df.if_flags |= XFS_IFINLINE;
+               xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
  
+               ip->i_d.di_size = pathlen;
                ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
                xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
        } else {
                int     offset;
  
@@@ -456,9 -444,12 +445,9 @@@ xfs_inactive_symlink_rmt
         */
        ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
  
 -      tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 -      error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
 -      if (error) {
 -              xfs_trans_cancel(tp);
 +      error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
 +      if (error)
                return error;
 -      }
  
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);