]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'xfs-O_TMPFILE-support' into for-next
authorDave Chinner <david@fromorbit.com>
Thu, 13 Mar 2014 08:14:43 +0000 (19:14 +1100)
committerDave Chinner <david@fromorbit.com>
Thu, 13 Mar 2014 08:14:43 +0000 (19:14 +1100)
Conflicts:
fs/xfs/xfs_trans_resv.c
- fix for XFS_INODE_CLUSTER_SIZE macro removal

1  2 
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iops.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_trans_resv.c
fs/xfs/xfs_trans_resv.h

diff --combined fs/xfs/xfs_inode.c
index 3a137e9f9a7dac3fb72f1687bf086b1273d83890,b08b5a84cf0a35ee80d55ae3c7b8c3fa7f35627d..5e7a38fa6ee6bd82e43c05f66cdc6d4b8404225e
@@@ -42,7 -42,6 +42,6 @@@
  #include "xfs_bmap_util.h"
  #include "xfs_error.h"
  #include "xfs_quota.h"
- #include "xfs_dinode.h"
  #include "xfs_filestream.h"
  #include "xfs_cksum.h"
  #include "xfs_trace.h"
@@@ -62,6 -61,8 +61,8 @@@ kmem_zone_t *xfs_inode_zone
  
  STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
  
+ STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *);
  /*
   * helper function to extract extent size hint from inode
   */
@@@ -77,44 -78,48 +78,44 @@@ xfs_get_extsz_hint
  }
  
  /*
 - * This is a wrapper routine around the xfs_ilock() routine used to centralize
 - * some grungy code.  It is used in places that wish to lock the inode solely
 - * for reading the extents.  The reason these places can't just call
 - * xfs_ilock(SHARED) is that the inode lock also guards to bringing in of the
 - * extents from disk for a file in b-tree format.  If the inode is in b-tree
 - * format, then we need to lock the inode exclusively until the extents are read
 - * in.  Locking it exclusively all the time would limit our parallelism
 - * unnecessarily, though.  What we do instead is check to see if the extents
 - * have been read in yet, and only lock the inode exclusively if they have not.
 + * These two are wrapper routines around the xfs_ilock() routine used to
 + * centralize some grungy code.  They are used in places that wish to lock the
 + * inode solely for reading the extents.  The reason these places can't just
 + * call xfs_ilock(ip, XFS_ILOCK_SHARED) is that the inode lock also guards to
 + * bringing in of the extents from disk for a file in b-tree format.  If the
 + * inode is in b-tree format, then we need to lock the inode exclusively until
 + * the extents are read in.  Locking it exclusively all the time would limit
 + * our parallelism unnecessarily, though.  What we do instead is check to see
 + * if the extents have been read in yet, and only lock the inode exclusively
 + * if they have not.
   *
 - * The function returns a value which should be given to the corresponding
 - * xfs_iunlock_map_shared().  This value is the mode in which the lock was
 - * actually taken.
 + * The functions return a value which should be given to the corresponding
 + * xfs_iunlock() call.
   */
  uint
 -xfs_ilock_map_shared(
 -      xfs_inode_t     *ip)
 +xfs_ilock_data_map_shared(
 +      struct xfs_inode        *ip)
  {
 -      uint    lock_mode;
 +      uint                    lock_mode = XFS_ILOCK_SHARED;
  
 -      if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) &&
 -          ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) {
 +      if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
 +          (ip->i_df.if_flags & XFS_IFEXTENTS) == 0)
                lock_mode = XFS_ILOCK_EXCL;
 -      } else {
 -              lock_mode = XFS_ILOCK_SHARED;
 -      }
 -
        xfs_ilock(ip, lock_mode);
 -
        return lock_mode;
  }
  
 -/*
 - * This is simply the unlock routine to go with xfs_ilock_map_shared().
 - * All it does is call xfs_iunlock() with the given lock_mode.
 - */
 -void
 -xfs_iunlock_map_shared(
 -      xfs_inode_t     *ip,
 -      unsigned int    lock_mode)
 +uint
 +xfs_ilock_attr_map_shared(
 +      struct xfs_inode        *ip)
  {
 -      xfs_iunlock(ip, lock_mode);
 +      uint                    lock_mode = XFS_ILOCK_SHARED;
 +
 +      if (ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE &&
 +          (ip->i_afp->if_flags & XFS_IFEXTENTS) == 0)
 +              lock_mode = XFS_ILOCK_EXCL;
 +      xfs_ilock(ip, lock_mode);
 +      return lock_mode;
  }
  
  /*
@@@ -584,9 -589,9 +585,9 @@@ xfs_lookup
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
                return XFS_ERROR(EIO);
  
 -      lock_mode = xfs_ilock_map_shared(dp);
 +      lock_mode = xfs_ilock_data_map_shared(dp);
        error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
 -      xfs_iunlock_map_shared(dp, lock_mode);
 +      xfs_iunlock(dp, lock_mode);
  
        if (error)
                goto out;
@@@ -1115,7 -1120,7 +1116,7 @@@ xfs_bumplink
  {
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
  
-       ASSERT(ip->i_d.di_nlink > 0);
+       ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE));
        ip->i_d.di_nlink++;
        inc_nlink(VFS_I(ip));
        if ((ip->i_d.di_version == 1) &&
@@@ -1165,10 -1170,7 +1166,7 @@@ xfs_create
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
  
-       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = xfs_get_projid(dp);
-       else
-               prid = XFS_PROJID_DEFAULT;
+       prid = xfs_get_initial_prid(dp);
  
        /*
         * Make sure that we have allocated dquot(s) on disk.
        return error;
  }
  
+ int
+ xfs_create_tmpfile(
+       struct xfs_inode        *dp,
+       struct dentry           *dentry,
+       umode_t                 mode)
+ {
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *ip = NULL;
+       struct xfs_trans        *tp = NULL;
+       int                     error;
+       uint                    cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
+       prid_t                  prid;
+       struct xfs_dquot        *udqp = NULL;
+       struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
+       struct xfs_trans_res    *tres;
+       uint                    resblks;
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+       prid = xfs_get_initial_prid(dp);
+       /*
+        * Make sure that we have allocated dquot(s) on disk.
+        */
+       error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()),
+                               xfs_kgid_to_gid(current_fsgid()), prid,
+                               XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                               &udqp, &gdqp, &pdqp);
+       if (error)
+               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);
+       if (error == ENOSPC) {
+               /* No space at all so try a "no-allocation" reservation */
+               resblks = 0;
+               error = xfs_trans_reserve(tp, tres, 0, 0);
+       }
+       if (error) {
+               cancel_flags = 0;
+               goto out_trans_cancel;
+       }
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+                                               pdqp, resblks, 1, 0);
+       if (error)
+               goto out_trans_cancel;
+       error = xfs_dir_ialloc(&tp, dp, mode, 1, 0,
+                               prid, resblks > 0, &ip, NULL);
+       if (error) {
+               if (error == ENOSPC)
+                       goto out_trans_cancel;
+               goto out_trans_abort;
+       }
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
+               xfs_trans_set_sync(tp);
+       /*
+        * Attach the dquot(s) to the inodes and modify them incore.
+        * These ids of the inode couldn't have changed since the new
+        * inode has been locked ever since it was created.
+        */
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
+       ip->i_d.di_nlink--;
+       d_tmpfile(dentry, VFS_I(ip));
+       error = xfs_iunlink(tp, ip);
+       if (error)
+               goto out_trans_abort;
+       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+       if (error)
+               goto out_release_inode;
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
+       return 0;
+  out_trans_abort:
+       cancel_flags |= XFS_TRANS_ABORT;
+  out_trans_cancel:
+       xfs_trans_cancel(tp, cancel_flags);
+  out_release_inode:
+       /*
+        * Wait until after the current transaction is aborted to
+        * release the inode.  This prevents recursive transactions
+        * and deadlocks from xfs_inactive.
+        */
+       if (ip)
+               IRELE(ip);
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
+       return error;
+ }
  int
  xfs_link(
        xfs_inode_t             *tdp,
  
        xfs_bmap_init(&free_list, &first_block);
  
+       if (sip->i_d.di_nlink == 0) {
+               error = xfs_iunlink_remove(tp, sip);
+               if (error)
+                       goto abort_return;
+       }
        error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error)
@@@ -2137,8 -2252,8 +2248,8 @@@ xfs_ifree_cluster
  {
        xfs_mount_t             *mp = free_ip->i_mount;
        int                     blks_per_cluster;
 +      int                     inodes_per_cluster;
        int                     nbufs;
 -      int                     ninodes;
        int                     i, j;
        xfs_daddr_t             blkno;
        xfs_buf_t               *bp;
        struct xfs_perag        *pag;
  
        pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum));
 -      if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
 -              blks_per_cluster = 1;
 -              ninodes = mp->m_sb.sb_inopblock;
 -              nbufs = XFS_IALLOC_BLOCKS(mp);
 -      } else {
 -              blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) /
 -                                      mp->m_sb.sb_blocksize;
 -              ninodes = blks_per_cluster * mp->m_sb.sb_inopblock;
 -              nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster;
 -      }
 +      blks_per_cluster = xfs_icluster_size_fsb(mp);
 +      inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog;
 +      nbufs = mp->m_ialloc_blks / blks_per_cluster;
  
 -      for (j = 0; j < nbufs; j++, inum += ninodes) {
 +      for (j = 0; j < nbufs; j++, inum += inodes_per_cluster) {
                blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum),
                                         XFS_INO_TO_AGBNO(mp, inum));
  
                 * transaction stale above, which means there is no point in
                 * even trying to lock them.
                 */
 -              for (i = 0; i < ninodes; i++) {
 +              for (i = 0; i < inodes_per_cluster; i++) {
  retry:
                        rcu_read_lock();
                        ip = radix_tree_lookup(&pag->pag_ici_root,
@@@ -2895,13 -3017,13 +3006,13 @@@ xfs_iflush_cluster
  
        pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
  
 -      inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog;
 +      inodes_per_cluster = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
        ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
        ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS);
        if (!ilist)
                goto out_put;
  
 -      mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
 +      mask = ~(((mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog)) - 1);
        first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
        rcu_read_lock();
        /* really need a gang lookup range call here */
diff --combined fs/xfs/xfs_inode.h
index 65e2350f449c9c4c086b8e6cd0de1f07f82c7fc8,3a978208f30be403e3af712b757355a91da8be2f..396cc1fafd0d5e358c5ea8ccc21d3525d2396bfa
@@@ -20,6 -20,7 +20,7 @@@
  
  #include "xfs_inode_buf.h"
  #include "xfs_inode_fork.h"
+ #include "xfs_dinode.h"
  
  /*
   * Kernel only inode definitions
@@@ -192,6 -193,15 +193,15 @@@ xfs_set_projid(struct xfs_inode *ip
        ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff);
  }
  
+ static inline prid_t
+ xfs_get_initial_prid(struct xfs_inode *dp)
+ {
+       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+               return xfs_get_projid(dp);
+       return XFS_PROJID_DEFAULT;
+ }
  /*
   * In-core inode flags.
   */
@@@ -323,6 -333,8 +333,8 @@@ int                xfs_lookup(struct xfs_inode *dp, s
                           struct xfs_inode **ipp, struct xfs_name *ci_name);
  int           xfs_create(struct xfs_inode *dp, struct xfs_name *name,
                           umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp);
+ int           xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry,
+                          umode_t mode);
  int           xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
                           struct xfs_inode *ip);
  int           xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
@@@ -337,8 -349,8 +349,8 @@@ int                xfs_ilock_nowait(xfs_inode_t *, ui
  void          xfs_iunlock(xfs_inode_t *, uint);
  void          xfs_ilock_demote(xfs_inode_t *, uint);
  int           xfs_isilocked(xfs_inode_t *, uint);
 -uint          xfs_ilock_map_shared(xfs_inode_t *);
 -void          xfs_iunlock_map_shared(xfs_inode_t *, uint);
 +uint          xfs_ilock_data_map_shared(struct xfs_inode *);
 +uint          xfs_ilock_attr_map_shared(struct xfs_inode *);
  int           xfs_ialloc(struct xfs_trans *, xfs_inode_t *, umode_t,
                           xfs_nlink_t, xfs_dev_t, prid_t, int,
                           struct xfs_buf **, xfs_inode_t **);
diff --combined fs/xfs/xfs_iops.c
index bb3bb658e39cc7cc1021667030a87327dbeb2e57,cb06cc4d0003166031931e98ea2b5728cd6fd244..89b07e43ca28811349db39aa1ab2534de220fd87
@@@ -39,6 -39,7 +39,7 @@@
  #include "xfs_da_btree.h"
  #include "xfs_dir2_priv.h"
  #include "xfs_dinode.h"
+ #include "xfs_trans_space.h"
  
  #include <linux/capability.h>
  #include <linux/xattr.h>
  #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,
@@@ -135,7 -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;
  
                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);
        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
@@@ -406,6 -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,
@@@ -691,7 -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);
        }
@@@ -717,6 -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;
  
        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;
         * 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;
  
                /*
         * 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;
        }
  
        /*
                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);
@@@ -1046,9 -1044,21 +1047,22 @@@ xfs_vn_fiemap
        return 0;
  }
  
+ STATIC int
+ xfs_vn_tmpfile(
+       struct inode    *dir,
+       struct dentry   *dentry,
+       umode_t         mode)
+ {
+       int             error;
+       error = xfs_create_tmpfile(XFS_I(dir), dentry, mode);
+       return -error;
+ }
  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,
@@@ -1076,7 -1086,6 +1090,7 @@@ static const struct inode_operations xf
        .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,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
        .update_time            = xfs_vn_update_time,
+       .tmpfile                = xfs_vn_tmpfile,
  };
  
  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,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
        .update_time            = xfs_vn_update_time,
+       .tmpfile                = xfs_vn_tmpfile,
  };
  
  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,
@@@ -1203,7 -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;
                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
diff --combined fs/xfs/xfs_symlink.c
index 5fda18919d3b2cb1915de245d79e6fa2bec94791,13140c7244f5bddefbf1705815c2275f304636bb..52979aa90986ca3a1a6caada967a460567245265
@@@ -80,10 -80,6 +80,10 @@@ xfs_readlink_bmap
                if (error) {
                        xfs_buf_ioerror_alert(bp, __func__);
                        xfs_buf_relse(bp);
 +
 +                      /* bad CRC means corrupted metadata */
 +                      if (error == EFSBADCRC)
 +                              error = EFSCORRUPTED;
                        goto out;
                }
                byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
@@@ -212,10 -208,7 +212,7 @@@ xfs_symlink
                return XFS_ERROR(ENAMETOOLONG);
  
        udqp = gdqp = NULL;
-       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = xfs_get_projid(dp);
-       else
-               prid = XFS_PROJID_DEFAULT;
+       prid = xfs_get_initial_prid(dp);
  
        /*
         * Make sure that we have allocated dquot(s) on disk.
diff --combined fs/xfs/xfs_trans_resv.c
index d2c8e4a6ee2afdc4a4ea9c625a24fa0c718aee23,76f9a02bc36be06a36003a16d3268f5710e5225c..ae368165244d49458bd4db2cc4688d196f2e2098
@@@ -81,28 -81,20 +81,28 @@@ xfs_calc_buf_res
   * on disk. Hence we need an inode reservation function that calculates all this
   * correctly. So, we log:
   *
 - * - log op headers for object
 + * - 4 log op headers for object
 + *    - for the ilf, the inode core and 2 forks
   * - inode log format object
 - * - the entire inode contents (core + 2 forks)
 - * - two bmap btree block headers
 + * - the inode core
 + * - two inode forks containing bmap btree root blocks.
 + *    - the btree data contained by both forks will fit into the inode size,
 + *      hence when combined with the inode core above, we have a total of the
 + *      actual inode size.
 + *    - the BMBT headers need to be accounted separately, as they are
 + *      additional to the records and pointers that fit inside the inode
 + *      forks.
   */
  STATIC uint
  xfs_calc_inode_res(
        struct xfs_mount        *mp,
        uint                    ninodes)
  {
 -      return ninodes * (sizeof(struct xlog_op_header) +
 -                        sizeof(struct xfs_inode_log_format) +
 -                        mp->m_sb.sb_inodesize +
 -                        2 * XFS_BMBT_BLOCK_LEN(mp));
 +      return ninodes *
 +              (4 * sizeof(struct xlog_op_header) +
 +               sizeof(struct xfs_inode_log_format) +
 +               mp->m_sb.sb_inodesize +
 +               2 * XFS_BMBT_BLOCK_LEN(mp));
  }
  
  /*
@@@ -182,7 -174,7 +182,7 @@@ xfs_calc_itruncate_reservation
                    xfs_calc_buf_res(5, 0) +
                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
                                     XFS_FSB_TO_B(mp, 1)) +
 -                  xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
 +                  xfs_calc_buf_res(2 + mp->m_ialloc_blks +
                                     mp->m_in_maxlevels, 0)));
  }
  
@@@ -211,6 -203,20 +211,19 @@@ xfs_calc_rename_reservation
                                      XFS_FSB_TO_B(mp, 1))));
  }
  
 -              MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
 -                      (__uint16_t)XFS_INODE_CLUSTER_SIZE(mp));
+ /*
+  * For removing an inode from unlinked list at first, we can modify:
+  *    the agi hash list and counters: sector size
+  *    the on disk inode before ours in the agi hash list: inode cluster size
+  */
+ STATIC uint
+ xfs_calc_iunlink_remove_reservation(
+       struct xfs_mount        *mp)
+ {
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
++             max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size);
+ }
  /*
   * For creating a link to an inode:
   *    the parent directory inode: inode size
@@@ -228,6 -234,7 +241,7 @@@ xfs_calc_link_reservation
        struct xfs_mount        *mp)
  {
        return XFS_DQUOT_LOGRES(mp) +
+               xfs_calc_iunlink_remove_reservation(mp) +
                MAX((xfs_calc_inode_res(mp, 2) +
                     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
                                      XFS_FSB_TO_B(mp, 1))),
                                      XFS_FSB_TO_B(mp, 1))));
  }
  
+ /*
+  * For adding an inode to unlinked list we can modify:
+  *    the agi hash list: sector size
+  *    the unlinked inode: inode size
+  */
+ STATIC uint
+ xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
+ {
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+               xfs_calc_inode_res(mp, 1);
+ }
  /*
   * For removing a directory entry we can modify:
   *    the parent directory inode: inode size
@@@ -253,10 -272,11 +279,11 @@@ xfs_calc_remove_reservation
        struct xfs_mount        *mp)
  {
        return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_inode_res(mp, 2) +
+               xfs_calc_iunlink_add_reservation(mp) +
+               MAX((xfs_calc_inode_res(mp, 1) +
                     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
                                      XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
+                   (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
                     xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
                                      XFS_FSB_TO_B(mp, 1))));
  }
@@@ -290,7 -310,7 +317,7 @@@ xfs_calc_create_resv_modify
   * For create we can allocate some inodes giving:
   *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
   *    the superblock for the nlink flag: sector size
 - *    the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
 + *    the inode blocks allocated: mp->m_ialloc_blks * blocksize
   *    the inode btree: max depth * blocksize
   *    the allocation btrees: 2 trees * (max depth - 1) * block size
   */
@@@ -300,7 -320,7 +327,7 @@@ xfs_calc_create_resv_alloc
  {
        return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
                mp->m_sb.sb_sectsize +
 -              xfs_calc_buf_res(XFS_IALLOC_BLOCKS(mp), XFS_FSB_TO_B(mp, 1)) +
 +              xfs_calc_buf_res(mp->m_ialloc_blks, XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
@@@ -351,6 -371,20 +378,20 @@@ xfs_calc_create_reservation
  
  }
  
+ STATIC uint
+ xfs_calc_create_tmpfile_reservation(
+       struct xfs_mount        *mp)
+ {
+       uint    res = XFS_DQUOT_LOGRES(mp);
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               res += xfs_calc_icreate_resv_alloc(mp);
+       else
+               res += xfs_calc_create_resv_alloc(mp);
+       return res + xfs_calc_iunlink_add_reservation(mp);
+ }
  /*
   * Making a new directory is the same as creating a new file.
   */
@@@ -391,11 -425,11 +432,11 @@@ xfs_calc_ifree_reservation
  {
        return XFS_DQUOT_LOGRES(mp) +
                xfs_calc_inode_res(mp, 1) +
-               xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
                xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
-               max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size) +
+               xfs_calc_iunlink_remove_reservation(mp) +
                xfs_calc_buf_res(1, 0) +
 -              xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
 +              xfs_calc_buf_res(2 + mp->m_ialloc_blks +
                                 mp->m_in_maxlevels, 0) +
                xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
@@@ -652,14 -686,15 +693,14 @@@ xfs_calc_qm_setqlim_reservation
  
  /*
   * Allocating quota on disk if needed.
 - *    the write transaction log space: M_RES(mp)->tr_write.tr_logres
 + *    the write transaction log space for quota file extent allocation
   *    the unit of quota allocation: one system block size
   */
  STATIC uint
  xfs_calc_qm_dqalloc_reservation(
        struct xfs_mount        *mp)
  {
 -      ASSERT(M_RES(mp)->tr_write.tr_logres);
 -      return M_RES(mp)->tr_write.tr_logres +
 +      return xfs_calc_write_reservation(mp) +
                xfs_calc_buf_res(1,
                        XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1);
  }
@@@ -736,6 -771,11 +777,11 @@@ xfs_trans_resv_calc
        resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
        resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
  
+       resp->tr_create_tmpfile.tr_logres =
+                       xfs_calc_create_tmpfile_reservation(mp);
+       resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
+       resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
        resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
        resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
        resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
        /* The following transaction are logged in logical format */
        resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp);
        resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp);
 -      resp->tr_swrite.tr_logres = xfs_calc_swrite_reservation(mp);
        resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp);
        resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp);
        resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp);
diff --combined fs/xfs/xfs_trans_resv.h
index f76c1297b83f9356cf46801bdbf1b2b2ebf681cd,285621d583f07792caf754ec4a2885a5ed060e34..1097d14cd583f974559b33c170467220c8cae2c7
@@@ -38,10 -38,12 +38,11 @@@ struct xfs_trans_resv 
        struct xfs_trans_res    tr_remove;      /* unlink trans */
        struct xfs_trans_res    tr_symlink;     /* symlink trans */
        struct xfs_trans_res    tr_create;      /* create trans */
+       struct xfs_trans_res    tr_create_tmpfile; /* create O_TMPFILE trans */
        struct xfs_trans_res    tr_mkdir;       /* mkdir trans */
        struct xfs_trans_res    tr_ifree;       /* inode free trans */
        struct xfs_trans_res    tr_ichange;     /* inode update trans */
        struct xfs_trans_res    tr_growdata;    /* fs data section grow trans */
 -      struct xfs_trans_res    tr_swrite;      /* sync write inode trans */
        struct xfs_trans_res    tr_addafork;    /* add inode attr fork trans */
        struct xfs_trans_res    tr_writeid;     /* write setuid/setgid file */
        struct xfs_trans_res    tr_attrinval;   /* attr fork buffer
  #define       XFS_ITRUNCATE_LOG_COUNT         2
  #define XFS_INACTIVE_LOG_COUNT                2
  #define       XFS_CREATE_LOG_COUNT            2
+ #define       XFS_CREATE_TMPFILE_LOG_COUNT    2
  #define       XFS_MKDIR_LOG_COUNT             3
  #define       XFS_SYMLINK_LOG_COUNT           3
  #define       XFS_REMOVE_LOG_COUNT            2