cifs: fix noserverino handling when unix extensions are enabled
[safe/jmp/linux-2.6] / fs / xfs / xfs_inode_item.c
index 0eee08a..7bfea85 100644 (file)
@@ -41,6 +41,7 @@
 #include "xfs_ialloc.h"
 #include "xfs_rw.h"
 #include "xfs_error.h"
+#include "xfs_trace.h"
 
 
 kmem_zone_t    *xfs_ili_zone;          /* inode log item zone */
@@ -227,11 +228,20 @@ xfs_inode_item_format(
 
        vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
        vecp->i_len  = sizeof(xfs_inode_log_format_t);
-       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IFORMAT);
+       vecp->i_type = XLOG_REG_TYPE_IFORMAT;
        vecp++;
        nvecs        = 1;
 
        /*
+        * Make sure the linux inode is dirty. We do this before
+        * clearing i_update_core as the VFS will call back into
+        * XFS here and set i_update_core, so we need to dirty the
+        * inode first so that the ordering of i_update_core and
+        * unlogged modifications still works as described below.
+        */
+       xfs_mark_inode_dirty_sync(ip);
+
+       /*
         * Clear i_update_core if the timestamps (or any other
         * non-transactional modification) need flushing/logging
         * and we're about to log them with the rest of the core.
@@ -263,26 +273,13 @@ xfs_inode_item_format(
        }
 
        /*
-        * We don't have to worry about re-ordering here because
-        * the update_size field is protected by the inode lock
-        * and we have that held in exclusive mode.
-        */
-       if (ip->i_update_size)
-               ip->i_update_size = 0;
-
-       /*
-        * Make sure to get the latest atime from the Linux inode.
+        * Make sure to get the latest timestamps from the Linux inode.
         */
-       xfs_synchronize_atime(ip);
-
-       /*
-        * make sure the linux inode is dirty
-        */
-       xfs_mark_inode_dirty_sync(ip);
+       xfs_synchronize_times(ip);
 
        vecp->i_addr = (xfs_caddr_t)&ip->i_d;
-       vecp->i_len  = sizeof(xfs_dinode_core_t);
-       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE);
+       vecp->i_len  = sizeof(struct xfs_icdinode);
+       vecp->i_type = XLOG_REG_TYPE_ICORE;
        vecp++;
        nvecs++;
        iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
@@ -296,9 +293,8 @@ xfs_inode_item_format(
         * has a new version number, then we don't bother converting back.
         */
        mp = ip->i_mount;
-       ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 ||
-              xfs_sb_version_hasnlink(&mp->m_sb));
-       if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
+       ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb));
+       if (ip->i_d.di_version == 1) {
                if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
                        /*
                         * Convert it back.
@@ -311,7 +307,7 @@ xfs_inode_item_format(
                         * so just make the conversion to the new inode
                         * format permanent.
                         */
-                       ip->i_d.di_version = XFS_DINODE_VERSION_2;
+                       ip->i_d.di_version = 2;
                        ip->i_d.di_onlink = 0;
                        memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
                }
@@ -340,7 +336,7 @@ xfs_inode_item_format(
                                vecp->i_addr =
                                        (char *)(ip->i_df.if_u1.if_extents);
                                vecp->i_len = ip->i_df.if_bytes;
-                               XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
+                               vecp->i_type = XLOG_REG_TYPE_IEXT;
                        } else
 #endif
                        {
@@ -359,7 +355,7 @@ xfs_inode_item_format(
                                vecp->i_addr = (xfs_caddr_t)ext_buffer;
                                vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                                XFS_DATA_FORK);
-                               XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT);
+                               vecp->i_type = XLOG_REG_TYPE_IEXT;
                        }
                        ASSERT(vecp->i_len <= ip->i_df.if_bytes);
                        iip->ili_format.ilf_dsize = vecp->i_len;
@@ -377,7 +373,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_df.if_broot != NULL);
                        vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
                        vecp->i_len = ip->i_df.if_broot_bytes;
-                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IBROOT);
+                       vecp->i_type = XLOG_REG_TYPE_IBROOT;
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
@@ -403,7 +399,7 @@ xfs_inode_item_format(
                        ASSERT((ip->i_df.if_real_bytes == 0) ||
                               (ip->i_df.if_real_bytes == data_bytes));
                        vecp->i_len = (int)data_bytes;
-                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ILOCAL);
+                       vecp->i_type = XLOG_REG_TYPE_ILOCAL;
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = (unsigned)data_bytes;
@@ -481,7 +477,7 @@ xfs_inode_item_format(
                        vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
                                        XFS_ATTR_FORK);
 #endif
-                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_EXT);
+                       vecp->i_type = XLOG_REG_TYPE_IATTR_EXT;
                        iip->ili_format.ilf_asize = vecp->i_len;
                        vecp++;
                        nvecs++;
@@ -496,7 +492,7 @@ xfs_inode_item_format(
                        ASSERT(ip->i_afp->if_broot != NULL);
                        vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
                        vecp->i_len = ip->i_afp->if_broot_bytes;
-                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_BROOT);
+                       vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
@@ -520,7 +516,7 @@ xfs_inode_item_format(
                        ASSERT((ip->i_afp->if_real_bytes == 0) ||
                               (ip->i_afp->if_real_bytes == data_bytes));
                        vecp->i_len = (int)data_bytes;
-                       XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_LOCAL);
+                       vecp->i_type = XLOG_REG_TYPE_IATTR_LOCAL;
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = (unsigned)data_bytes;
@@ -539,23 +535,23 @@ xfs_inode_item_format(
 
 /*
  * This is called to pin the inode associated with the inode log
- * item in memory so it cannot be written out.  Do this by calling
- * xfs_ipin() to bump the pin count in the inode while holding the
- * inode pin lock.
+ * item in memory so it cannot be written out.
  */
 STATIC void
 xfs_inode_item_pin(
        xfs_inode_log_item_t    *iip)
 {
        ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
-       xfs_ipin(iip->ili_inode);
+
+       atomic_inc(&iip->ili_inode->i_pincount);
 }
 
 
 /*
  * This is called to unpin the inode associated with the inode log
  * item which was previously pinned with a call to xfs_inode_item_pin().
- * Just call xfs_iunpin() on the inode to do this.
+ *
+ * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0.
  */
 /* ARGSUSED */
 STATIC void
@@ -563,7 +559,11 @@ xfs_inode_item_unpin(
        xfs_inode_log_item_t    *iip,
        int                     stale)
 {
-       xfs_iunpin(iip->ili_inode);
+       struct xfs_inode        *ip = iip->ili_inode;
+
+       ASSERT(atomic_read(&ip->i_pincount) > 0);
+       if (atomic_dec_and_test(&ip->i_pincount))
+               wake_up(&ip->i_ipin_wait);
 }
 
 /* ARGSUSED */
@@ -572,7 +572,7 @@ xfs_inode_item_unpin_remove(
        xfs_inode_log_item_t    *iip,
        xfs_trans_t             *tp)
 {
-       xfs_iunpin(iip->ili_inode);
+       xfs_inode_item_unpin(iip, 0);
 }
 
 /*
@@ -606,33 +606,20 @@ xfs_inode_item_trylock(
 
        if (!xfs_iflock_nowait(ip)) {
                /*
-                * If someone else isn't already trying to push the inode
-                * buffer, we get to do it.
+                * inode has already been flushed to the backing buffer,
+                * leave it locked in shared mode, pushbuf routine will
+                * unlock it.
                 */
-               if (iip->ili_pushbuf_flag == 0) {
-                       iip->ili_pushbuf_flag = 1;
-#ifdef DEBUG
-                       iip->ili_push_owner = current_pid();
-#endif
-                       /*
-                        * Inode is left locked in shared mode.
-                        * Pushbuf routine gets to unlock it.
-                        */
-                       return XFS_ITEM_PUSHBUF;
-               } else {
-                       /*
-                        * We hold the AIL lock, so we must specify the
-                        * NONOTIFY flag so that we won't double trip.
-                        */
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
-                       return XFS_ITEM_FLUSHING;
-               }
-               /* NOTREACHED */
+               return XFS_ITEM_PUSHBUF;
        }
 
        /* Stale items should force out the iclog */
        if (ip->i_flags & XFS_ISTALE) {
                xfs_ifunlock(ip);
+               /*
+                * we hold the AIL lock - notify the unlock routine of this
+                * so it doesn't try to get the lock again.
+                */
                xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
                return XFS_ITEM_PINNED;
        }
@@ -713,8 +700,6 @@ xfs_inode_item_unlock(
         * Clear out the fields of the inode log item particular
         * to the current transaction.
         */
-       iip->ili_ilock_recur = 0;
-       iip->ili_iolock_recur = 0;
        iip->ili_flags = 0;
 
        /*
@@ -752,11 +737,8 @@ xfs_inode_item_committed(
  * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK
  * failed to get the inode flush lock but did get the inode locked SHARED.
  * Here we're trying to see if the inode buffer is incore, and if so whether it's
- * marked delayed write. If that's the case, we'll initiate a bawrite on that
- * buffer to expedite the process.
- *
- * We aren't holding the AIL lock (or the flush lock) when this gets called,
- * so it is inherently race-y.
+ * marked delayed write. If that's the case, we'll promote it and that will
+ * allow the caller to write the buffer by triggering the xfsbufd to run.
  */
 STATIC void
 xfs_inode_item_pushbuf(
@@ -765,81 +747,30 @@ xfs_inode_item_pushbuf(
        xfs_inode_t     *ip;
        xfs_mount_t     *mp;
        xfs_buf_t       *bp;
-       uint            dopush;
 
        ip = iip->ili_inode;
-
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
 
        /*
-        * The ili_pushbuf_flag keeps others from
-        * trying to duplicate our effort.
-        */
-       ASSERT(iip->ili_pushbuf_flag != 0);
-       ASSERT(iip->ili_push_owner == current_pid());
-
-       /*
-        * If flushlock isn't locked anymore, chances are that the
-        * inode flush completed and the inode was taken off the AIL.
-        * So, just get out.
+        * If a flush is not in progress anymore, chances are that the
+        * inode was taken off the AIL. So, just get out.
         */
-       if (!issemalocked(&(ip->i_flock)) ||
+       if (completion_done(&ip->i_flush) ||
            ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
-               iip->ili_pushbuf_flag = 0;
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
                return;
        }
 
        mp = ip->i_mount;
        bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno,
-                   iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK);
+                   iip->ili_format.ilf_len, XBF_TRYLOCK);
 
-       if (bp != NULL) {
-               if (XFS_BUF_ISDELAYWRITE(bp)) {
-                       /*
-                        * We were racing with iflush because we don't hold
-                        * the AIL lock or the flush lock. However, at this point,
-                        * we have the buffer, and we know that it's dirty.
-                        * So, it's possible that iflush raced with us, and
-                        * this item is already taken off the AIL.
-                        * If not, we can flush it async.
-                        */
-                       dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) &&
-                                 issemalocked(&(ip->i_flock)));
-                       iip->ili_pushbuf_flag = 0;
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-                       xfs_buftrace("INODE ITEM PUSH", bp);
-                       if (XFS_BUF_ISPINNED(bp)) {
-                               xfs_log_force(mp, (xfs_lsn_t)0,
-                                             XFS_LOG_FORCE);
-                       }
-                       if (dopush) {
-                               int     error;
-                               error = xfs_bawrite(mp, bp);
-                               if (error)
-                                       xfs_fs_cmn_err(CE_WARN, mp,
-               "xfs_inode_item_pushbuf: pushbuf error %d on iip %p, bp %p",
-                                                       error, iip, bp);
-                       } else {
-                               xfs_buf_relse(bp);
-                       }
-               } else {
-                       iip->ili_pushbuf_flag = 0;
-                       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-                       xfs_buf_relse(bp);
-               }
-               return;
-       }
-       /*
-        * We have to be careful about resetting pushbuf flag too early (above).
-        * Even though in theory we can do it as soon as we have the buflock,
-        * we don't want others to be doing work needlessly. They'll come to
-        * this function thinking that pushing the buffer is their
-        * responsibility only to find that the buffer is still locked by
-        * another doing the same thing
-        */
-       iip->ili_pushbuf_flag = 0;
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
+       if (!bp)
+               return;
+       if (XFS_BUF_ISDELAYWRITE(bp))
+               xfs_buf_delwri_promote(bp);
+       xfs_buf_relse(bp);
        return;
 }
 
@@ -858,7 +789,7 @@ xfs_inode_item_push(
        ip = iip->ili_inode;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
-       ASSERT(issemalocked(&(ip->i_flock)));
+       ASSERT(!completion_done(&ip->i_flush));
        /*
         * Since we were able to lock the inode's flush lock and
         * we found it on the AIL, the inode must be dirty.  This
@@ -872,10 +803,14 @@ xfs_inode_item_push(
               iip->ili_format.ilf_fields != 0);
 
        /*
-        * Write out the inode.  The completion routine ('iflush_done') will
-        * pull it from the AIL, mark it clean, unlock the flush lock.
+        * Push the inode to it's backing buffer. This will not remove the
+        * inode from the AIL - a further push will be required to trigger a
+        * buffer push. However, this allows all the dirty inodes to be pushed
+        * to the buffer before it is pushed to disk. THe buffer IO completion
+        * will pull th einode from the AIL, mark it clean and unlock the flush
+        * lock.
         */
-       (void) xfs_iflush(ip, XFS_IFLUSH_ASYNC);
+       (void) xfs_iflush(ip, 0);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        return;
@@ -933,19 +868,19 @@ xfs_inode_item_init(
        iip->ili_item.li_type = XFS_LI_INODE;
        iip->ili_item.li_ops = &xfs_inode_item_ops;
        iip->ili_item.li_mountp = mp;
+       iip->ili_item.li_ailp = mp->m_ail;
        iip->ili_inode = ip;
 
        /*
           We have zeroed memory. No need ...
           iip->ili_extents_buf = NULL;
-          iip->ili_pushbuf_flag = 0;
         */
 
        iip->ili_format.ilf_type = XFS_LI_INODE;
        iip->ili_format.ilf_ino = ip->i_ino;
-       iip->ili_format.ilf_blkno = ip->i_blkno;
-       iip->ili_format.ilf_len = ip->i_len;
-       iip->ili_format.ilf_boffset = ip->i_boffset;
+       iip->ili_format.ilf_blkno = ip->i_imap.im_blkno;
+       iip->ili_format.ilf_len = ip->i_imap.im_len;
+       iip->ili_format.ilf_boffset = ip->i_imap.im_boffset;
 }
 
 /*
@@ -977,9 +912,8 @@ xfs_iflush_done(
        xfs_buf_t               *bp,
        xfs_inode_log_item_t    *iip)
 {
-       xfs_inode_t     *ip;
-
-       ip = iip->ili_inode;
+       xfs_inode_t             *ip = iip->ili_inode;
+       struct xfs_ail          *ailp = iip->ili_item.li_ailp;
 
        /*
         * We only want to pull the item from the AIL if it is
@@ -992,15 +926,12 @@ xfs_iflush_done(
         */
        if (iip->ili_logged &&
            (iip->ili_item.li_lsn == iip->ili_flush_lsn)) {
-               spin_lock(&ip->i_mount->m_ail_lock);
+               spin_lock(&ailp->xa_lock);
                if (iip->ili_item.li_lsn == iip->ili_flush_lsn) {
-                       /*
-                        * xfs_trans_delete_ail() drops the AIL lock.
-                        */
-                       xfs_trans_delete_ail(ip->i_mount,
-                                            (xfs_log_item_t*)iip);
+                       /* xfs_trans_ail_delete() drops the AIL lock. */
+                       xfs_trans_ail_delete(ailp, (xfs_log_item_t*)iip);
                } else {
-                       spin_unlock(&ip->i_mount->m_ail_lock);
+                       spin_unlock(&ailp->xa_lock);
                }
        }
 
@@ -1032,21 +963,20 @@ void
 xfs_iflush_abort(
        xfs_inode_t             *ip)
 {
-       xfs_inode_log_item_t    *iip;
+       xfs_inode_log_item_t    *iip = ip->i_itemp;
        xfs_mount_t             *mp;
 
        iip = ip->i_itemp;
        mp = ip->i_mount;
        if (iip) {
+               struct xfs_ail  *ailp = iip->ili_item.li_ailp;
                if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
-                       spin_lock(&mp->m_ail_lock);
+                       spin_lock(&ailp->xa_lock);
                        if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
-                               /*
-                                * xfs_trans_delete_ail() drops the AIL lock.
-                                */
-                               xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip);
+                               /* xfs_trans_ail_delete() drops the AIL lock. */
+                               xfs_trans_ail_delete(ailp, (xfs_log_item_t *)iip);
                        } else
-                               spin_unlock(&mp->m_ail_lock);
+                               spin_unlock(&ailp->xa_lock);
                }
                iip->ili_logged = 0;
                /*