Merge tag 'sound-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[cascardo/linux.git] / fs / xfs / xfs_trans.c
index 1f35b2f..7adcdf1 100644 (file)
@@ -1151,14 +1151,13 @@ xfs_trans_add_item(
 {
        struct xfs_log_item_desc *lidp;
 
-       ASSERT(lip->li_mountp = tp->t_mountp);
-       ASSERT(lip->li_ailp = tp->t_mountp->m_ail);
+       ASSERT(lip->li_mountp == tp->t_mountp);
+       ASSERT(lip->li_ailp == tp->t_mountp->m_ail);
 
        lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS);
 
        lidp->lid_item = lip;
        lidp->lid_flags = 0;
-       lidp->lid_size = 0;
        list_add_tail(&lidp->lid_trans, &tp->t_items);
 
        lip->li_desc = lidp;
@@ -1210,219 +1209,6 @@ xfs_trans_free_items(
        }
 }
 
-/*
- * Unlock the items associated with a transaction.
- *
- * Items which were not logged should be freed.  Those which were logged must
- * still be tracked so they can be unpinned when the transaction commits.
- */
-STATIC void
-xfs_trans_unlock_items(
-       struct xfs_trans        *tp,
-       xfs_lsn_t               commit_lsn)
-{
-       struct xfs_log_item_desc *lidp, *next;
-
-       list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
-               struct xfs_log_item     *lip = lidp->lid_item;
-
-               lip->li_desc = NULL;
-
-               if (commit_lsn != NULLCOMMITLSN)
-                       IOP_COMMITTING(lip, commit_lsn);
-               IOP_UNLOCK(lip);
-
-               /*
-                * Free the descriptor if the item is not dirty
-                * within this transaction.
-                */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY))
-                       xfs_trans_free_item_desc(lidp);
-       }
-}
-
-/*
- * Total up the number of log iovecs needed to commit this
- * transaction.  The transaction itself needs one for the
- * transaction header.  Ask each dirty item in turn how many
- * it needs to get the total.
- */
-static uint
-xfs_trans_count_vecs(
-       struct xfs_trans        *tp)
-{
-       int                     nvecs;
-       struct xfs_log_item_desc *lidp;
-
-       nvecs = 1;
-
-       /* In the non-debug case we need to start bailing out if we
-        * didn't find a log_item here, return zero and let trans_commit
-        * deal with it.
-        */
-       if (list_empty(&tp->t_items)) {
-               ASSERT(0);
-               return 0;
-       }
-
-       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               /*
-                * Skip items which aren't dirty in this transaction.
-                */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY))
-                       continue;
-               lidp->lid_size = IOP_SIZE(lidp->lid_item);
-               nvecs += lidp->lid_size;
-       }
-
-       return nvecs;
-}
-
-/*
- * Fill in the vector with pointers to data to be logged
- * by this transaction.  The transaction header takes
- * the first vector, and then each dirty item takes the
- * number of vectors it indicated it needed in xfs_trans_count_vecs().
- *
- * As each item fills in the entries it needs, also pin the item
- * so that it cannot be flushed out until the log write completes.
- */
-static void
-xfs_trans_fill_vecs(
-       struct xfs_trans        *tp,
-       struct xfs_log_iovec    *log_vector)
-{
-       struct xfs_log_item_desc *lidp;
-       struct xfs_log_iovec    *vecp;
-       uint                    nitems;
-
-       /*
-        * Skip over the entry for the transaction header, we'll
-        * fill that in at the end.
-        */
-       vecp = log_vector + 1;
-
-       nitems = 0;
-       ASSERT(!list_empty(&tp->t_items));
-       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               /* Skip items which aren't dirty in this transaction. */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY))
-                       continue;
-
-               /*
-                * The item may be marked dirty but not log anything.  This can
-                * be used to get called when a transaction is committed.
-                */
-               if (lidp->lid_size)
-                       nitems++;
-               IOP_FORMAT(lidp->lid_item, vecp);
-               vecp += lidp->lid_size;
-               IOP_PIN(lidp->lid_item);
-       }
-
-       /*
-        * Now that we've counted the number of items in this transaction, fill
-        * in the transaction header. Note that the transaction header does not
-        * have a log item.
-        */
-       tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
-       tp->t_header.th_type = tp->t_type;
-       tp->t_header.th_num_items = nitems;
-       log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
-       log_vector->i_len = sizeof(xfs_trans_header_t);
-       log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
-}
-
-/*
- * The committed item processing consists of calling the committed routine of
- * each logged item, updating the item's position in the AIL if necessary, and
- * unpinning each item.  If the committed routine returns -1, then do nothing
- * further with the item because it may have been freed.
- *
- * Since items are unlocked when they are copied to the incore log, it is
- * possible for two transactions to be completing and manipulating the same
- * item simultaneously.  The AIL lock will protect the lsn field of each item.
- * The value of this field can never go backwards.
- *
- * We unpin the items after repositioning them in the AIL, because otherwise
- * they could be immediately flushed and we'd have to race with the flusher
- * trying to pull the item from the AIL as we add it.
- */
-static void
-xfs_trans_item_committed(
-       struct xfs_log_item     *lip,
-       xfs_lsn_t               commit_lsn,
-       int                     aborted)
-{
-       xfs_lsn_t               item_lsn;
-       struct xfs_ail          *ailp;
-
-       if (aborted)
-               lip->li_flags |= XFS_LI_ABORTED;
-       item_lsn = IOP_COMMITTED(lip, commit_lsn);
-
-       /* item_lsn of -1 means the item needs no further processing */
-       if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
-               return;
-
-       /*
-        * If the returned lsn is greater than what it contained before, update
-        * the location of the item in the AIL.  If it is not, then do nothing.
-        * Items can never move backwards in the AIL.
-        *
-        * While the new lsn should usually be greater, it is possible that a
-        * later transaction completing simultaneously with an earlier one
-        * using the same item could complete first with a higher lsn.  This
-        * would cause the earlier transaction to fail the test below.
-        */
-       ailp = lip->li_ailp;
-       spin_lock(&ailp->xa_lock);
-       if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
-               /*
-                * This will set the item's lsn to item_lsn and update the
-                * position of the item in the AIL.
-                *
-                * xfs_trans_ail_update() drops the AIL lock.
-                */
-               xfs_trans_ail_update(ailp, lip, item_lsn);
-       } else {
-               spin_unlock(&ailp->xa_lock);
-       }
-
-       /*
-        * Now that we've repositioned the item in the AIL, unpin it so it can
-        * be flushed. Pass information about buffer stale state down from the
-        * log item flags, if anyone else stales the buffer we do not want to
-        * pay any attention to it.
-        */
-       IOP_UNPIN(lip, 0);
-}
-
-/*
- * This is typically called by the LM when a transaction has been fully
- * committed to disk.  It needs to unpin the items which have
- * been logged by the transaction and update their positions
- * in the AIL if necessary.
- *
- * This also gets called when the transactions didn't get written out
- * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then.
- */
-STATIC void
-xfs_trans_committed(
-       void                    *arg,
-       int                     abortflag)
-{
-       struct xfs_trans        *tp = arg;
-       struct xfs_log_item_desc *lidp, *next;
-
-       list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
-               xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
-               xfs_trans_free_item_desc(lidp);
-       }
-
-       xfs_trans_free(tp);
-}
-
 static inline void
 xfs_log_item_batch_insert(
        struct xfs_ail          *ailp,
@@ -1537,258 +1323,6 @@ xfs_trans_committed_bulk(
        spin_unlock(&ailp->xa_lock);
 }
 
-/*
- * Called from the trans_commit code when we notice that the filesystem is in
- * the middle of a forced shutdown.
- *
- * When we are called here, we have already pinned all the items in the
- * transaction. However, neither IOP_COMMITTING or IOP_UNLOCK has been called
- * so we can simply walk the items in the transaction, unpin them with an abort
- * flag and then free the items. Note that unpinning the items can result in
- * them being freed immediately, so we need to use a safe list traversal method
- * here.
- */
-STATIC void
-xfs_trans_uncommit(
-       struct xfs_trans        *tp,
-       uint                    flags)
-{
-       struct xfs_log_item_desc *lidp, *n;
-
-       list_for_each_entry_safe(lidp, n, &tp->t_items, lid_trans) {
-               if (lidp->lid_flags & XFS_LID_DIRTY)
-                       IOP_UNPIN(lidp->lid_item, 1);
-       }
-
-       xfs_trans_unreserve_and_mod_sb(tp);
-       xfs_trans_unreserve_and_mod_dquots(tp);
-
-       xfs_trans_free_items(tp, NULLCOMMITLSN, flags);
-       xfs_trans_free(tp);
-}
-
-/*
- * Format the transaction direct to the iclog. This isolates the physical
- * transaction commit operation from the logical operation and hence allows
- * other methods to be introduced without affecting the existing commit path.
- */
-static int
-xfs_trans_commit_iclog(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       xfs_lsn_t               *commit_lsn,
-       int                     flags)
-{
-       int                     shutdown;
-       int                     error;
-       int                     log_flags = 0;
-       struct xlog_in_core     *commit_iclog;
-#define XFS_TRANS_LOGVEC_COUNT  16
-       struct xfs_log_iovec    log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
-       struct xfs_log_iovec    *log_vector;
-       uint                    nvec;
-
-
-       /*
-        * Ask each log item how many log_vector entries it will
-        * need so we can figure out how many to allocate.
-        * Try to avoid the kmem_alloc() call in the common case
-        * by using a vector from the stack when it fits.
-        */
-       nvec = xfs_trans_count_vecs(tp);
-       if (nvec == 0) {
-               return ENOMEM;  /* triggers a shutdown! */
-       } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
-               log_vector = log_vector_fast;
-       } else {
-               log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec *
-                                                  sizeof(xfs_log_iovec_t),
-                                                  KM_SLEEP);
-       }
-
-       /*
-        * Fill in the log_vector and pin the logged items, and
-        * then write the transaction to the log.
-        */
-       xfs_trans_fill_vecs(tp, log_vector);
-
-       if (flags & XFS_TRANS_RELEASE_LOG_RES)
-               log_flags = XFS_LOG_REL_PERM_RESERV;
-
-       error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));
-
-       /*
-        * The transaction is committed incore here, and can go out to disk
-        * at any time after this call.  However, all the items associated
-        * with the transaction are still locked and pinned in memory.
-        */
-       *commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
-
-       tp->t_commit_lsn = *commit_lsn;
-       trace_xfs_trans_commit_lsn(tp);
-
-       if (nvec > XFS_TRANS_LOGVEC_COUNT)
-               kmem_free(log_vector);
-
-       /*
-        * If we got a log write error. Unpin the logitems that we
-        * had pinned, clean up, free trans structure, and return error.
-        */
-       if (error || *commit_lsn == -1) {
-               current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
-               xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
-               return XFS_ERROR(EIO);
-       }
-
-       /*
-        * Once the transaction has committed, unused
-        * reservations need to be released and changes to
-        * the superblock need to be reflected in the in-core
-        * version.  Do that now.
-        */
-       xfs_trans_unreserve_and_mod_sb(tp);
-
-       /*
-        * Tell the LM to call the transaction completion routine
-        * when the log write with LSN commit_lsn completes (e.g.
-        * when the transaction commit really hits the on-disk log).
-        * After this call we cannot reference tp, because the call
-        * can happen at any time and the call will free the transaction
-        * structure pointed to by tp.  The only case where we call
-        * the completion routine (xfs_trans_committed) directly is
-        * if the log is turned off on a debug kernel or we're
-        * running in simulation mode (the log is explicitly turned
-        * off).
-        */
-       tp->t_logcb.cb_func = xfs_trans_committed;
-       tp->t_logcb.cb_arg = tp;
-
-       /*
-        * We need to pass the iclog buffer which was used for the
-        * transaction commit record into this function, and attach
-        * the callback to it. The callback must be attached before
-        * the items are unlocked to avoid racing with other threads
-        * waiting for an item to unlock.
-        */
-       shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
-
-       /*
-        * Mark this thread as no longer being in a transaction
-        */
-       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
-
-       /*
-        * Once all the items of the transaction have been copied
-        * to the in core log and the callback is attached, the
-        * items can be unlocked.
-        *
-        * This will free descriptors pointing to items which were
-        * not logged since there is nothing more to do with them.
-        * For items which were logged, we will keep pointers to them
-        * so they can be unpinned after the transaction commits to disk.
-        * This will also stamp each modified meta-data item with
-        * the commit lsn of this transaction for dependency tracking
-        * purposes.
-        */
-       xfs_trans_unlock_items(tp, *commit_lsn);
-
-       /*
-        * If we detected a log error earlier, finish committing
-        * the transaction now (unpin log items, etc).
-        *
-        * Order is critical here, to avoid using the transaction
-        * pointer after its been freed (by xfs_trans_committed
-        * either here now, or as a callback).  We cannot do this
-        * step inside xfs_log_notify as was done earlier because
-        * of this issue.
-        */
-       if (shutdown)
-               xfs_trans_committed(tp, XFS_LI_ABORTED);
-
-       /*
-        * Now that the xfs_trans_committed callback has been attached,
-        * and the items are released we can finally allow the iclog to
-        * go to disk.
-        */
-       return xfs_log_release_iclog(mp, commit_iclog);
-}
-
-/*
- * Walk the log items and allocate log vector structures for
- * each item large enough to fit all the vectors they require.
- * Note that this format differs from the old log vector format in
- * that there is no transaction header in these log vectors.
- */
-STATIC struct xfs_log_vec *
-xfs_trans_alloc_log_vecs(
-       xfs_trans_t     *tp)
-{
-       struct xfs_log_item_desc *lidp;
-       struct xfs_log_vec      *lv = NULL;
-       struct xfs_log_vec      *ret_lv = NULL;
-
-
-       /* Bail out if we didn't find a log item.  */
-       if (list_empty(&tp->t_items)) {
-               ASSERT(0);
-               return NULL;
-       }
-
-       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               struct xfs_log_vec *new_lv;
-
-               /* Skip items which aren't dirty in this transaction. */
-               if (!(lidp->lid_flags & XFS_LID_DIRTY))
-                       continue;
-
-               /* Skip items that do not have any vectors for writing */
-               lidp->lid_size = IOP_SIZE(lidp->lid_item);
-               if (!lidp->lid_size)
-                       continue;
-
-               new_lv = kmem_zalloc(sizeof(*new_lv) +
-                               lidp->lid_size * sizeof(struct xfs_log_iovec),
-                               KM_SLEEP);
-
-               /* The allocated iovec region lies beyond the log vector. */
-               new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
-               new_lv->lv_niovecs = lidp->lid_size;
-               new_lv->lv_item = lidp->lid_item;
-               if (!ret_lv)
-                       ret_lv = new_lv;
-               else
-                       lv->lv_next = new_lv;
-               lv = new_lv;
-       }
-
-       return ret_lv;
-}
-
-static int
-xfs_trans_commit_cil(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       xfs_lsn_t               *commit_lsn,
-       int                     flags)
-{
-       struct xfs_log_vec      *log_vector;
-
-       /*
-        * Get each log item to allocate a vector structure for
-        * the log item to to pass to the log write code. The
-        * CIL commit code will format the vector and save it away.
-        */
-       log_vector = xfs_trans_alloc_log_vecs(tp);
-       if (!log_vector)
-               return ENOMEM;
-
-       xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
-
-       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
-       xfs_trans_free(tp);
-       return 0;
-}
-
 /*
  * Commit the given transaction to the log.
  *
@@ -1845,17 +1379,16 @@ xfs_trans_commit(
                xfs_trans_apply_sb_deltas(tp);
        xfs_trans_apply_dquot_deltas(tp);
 
-       if (mp->m_flags & XFS_MOUNT_DELAYLOG)
-               error = xfs_trans_commit_cil(mp, tp, &commit_lsn, flags);
-       else
-               error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags);
-
+       error = xfs_log_commit_cil(mp, tp, &commit_lsn, flags);
        if (error == ENOMEM) {
                xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                error = XFS_ERROR(EIO);
                goto out_unreserve;
        }
 
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
+       xfs_trans_free(tp);
+
        /*
         * If the transaction needs to be synchronous, then force the
         * log out now and wait for it.