|
@@ -1,5 +1,6 @@
|
|
/*
|
|
/*
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
|
|
+ * Copyright (C) 2010 Red Hat, Inc.
|
|
* All Rights Reserved.
|
|
* All Rights Reserved.
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -43,6 +44,7 @@
|
|
#include "xfs_trace.h"
|
|
#include "xfs_trace.h"
|
|
|
|
|
|
kmem_zone_t *xfs_trans_zone;
|
|
kmem_zone_t *xfs_trans_zone;
|
|
|
|
+kmem_zone_t *xfs_log_item_desc_zone;
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -593,8 +595,7 @@ _xfs_trans_alloc(
|
|
tp->t_magic = XFS_TRANS_MAGIC;
|
|
tp->t_magic = XFS_TRANS_MAGIC;
|
|
tp->t_type = type;
|
|
tp->t_type = type;
|
|
tp->t_mountp = mp;
|
|
tp->t_mountp = mp;
|
|
- tp->t_items_free = XFS_LIC_NUM_SLOTS;
|
|
|
|
- xfs_lic_init(&(tp->t_items));
|
|
|
|
|
|
+ INIT_LIST_HEAD(&tp->t_items);
|
|
INIT_LIST_HEAD(&tp->t_busy);
|
|
INIT_LIST_HEAD(&tp->t_busy);
|
|
return tp;
|
|
return tp;
|
|
}
|
|
}
|
|
@@ -639,8 +640,7 @@ xfs_trans_dup(
|
|
ntp->t_magic = XFS_TRANS_MAGIC;
|
|
ntp->t_magic = XFS_TRANS_MAGIC;
|
|
ntp->t_type = tp->t_type;
|
|
ntp->t_type = tp->t_type;
|
|
ntp->t_mountp = tp->t_mountp;
|
|
ntp->t_mountp = tp->t_mountp;
|
|
- ntp->t_items_free = XFS_LIC_NUM_SLOTS;
|
|
|
|
- xfs_lic_init(&(ntp->t_items));
|
|
|
|
|
|
+ INIT_LIST_HEAD(&ntp->t_items);
|
|
INIT_LIST_HEAD(&ntp->t_busy);
|
|
INIT_LIST_HEAD(&ntp->t_busy);
|
|
|
|
|
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
|
@@ -1119,6 +1119,108 @@ xfs_trans_unreserve_and_mod_sb(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Add the given log item to the transaction's list of log items.
|
|
|
|
+ *
|
|
|
|
+ * The log item will now point to its new descriptor with its li_desc field.
|
|
|
|
+ */
|
|
|
|
+void
|
|
|
|
+xfs_trans_add_item(
|
|
|
|
+ struct xfs_trans *tp,
|
|
|
|
+ struct xfs_log_item *lip)
|
|
|
|
+{
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+STATIC void
|
|
|
|
+xfs_trans_free_item_desc(
|
|
|
|
+ struct xfs_log_item_desc *lidp)
|
|
|
|
+{
|
|
|
|
+ list_del_init(&lidp->lid_trans);
|
|
|
|
+ kmem_zone_free(xfs_log_item_desc_zone, lidp);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Unlink and free the given descriptor.
|
|
|
|
+ */
|
|
|
|
+void
|
|
|
|
+xfs_trans_del_item(
|
|
|
|
+ struct xfs_log_item *lip)
|
|
|
|
+{
|
|
|
|
+ xfs_trans_free_item_desc(lip->li_desc);
|
|
|
|
+ lip->li_desc = NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Unlock all of the items of a transaction and free all the descriptors
|
|
|
|
+ * of that transaction.
|
|
|
|
+ */
|
|
|
|
+STATIC void
|
|
|
|
+xfs_trans_free_items(
|
|
|
|
+ struct xfs_trans *tp,
|
|
|
|
+ xfs_lsn_t commit_lsn,
|
|
|
|
+ int flags)
|
|
|
|
+{
|
|
|
|
+ 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);
|
|
|
|
+ if (flags & XFS_TRANS_ABORT)
|
|
|
|
+ lip->li_flags |= XFS_LI_ABORTED;
|
|
|
|
+ IOP_UNLOCK(lip);
|
|
|
|
+
|
|
|
|
+ xfs_trans_free_item_desc(lidp);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * 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
|
|
* Total up the number of log iovecs needed to commit this
|
|
* transaction. The transaction itself needs one for the
|
|
* transaction. The transaction itself needs one for the
|
|
@@ -1130,30 +1232,27 @@ xfs_trans_count_vecs(
|
|
struct xfs_trans *tp)
|
|
struct xfs_trans *tp)
|
|
{
|
|
{
|
|
int nvecs;
|
|
int nvecs;
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
|
|
|
|
nvecs = 1;
|
|
nvecs = 1;
|
|
- lidp = xfs_trans_first_item(tp);
|
|
|
|
- ASSERT(lidp != NULL);
|
|
|
|
|
|
|
|
/* In the non-debug case we need to start bailing out if we
|
|
/* 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
|
|
* didn't find a log_item here, return zero and let trans_commit
|
|
* deal with it.
|
|
* deal with it.
|
|
*/
|
|
*/
|
|
- if (lidp == NULL)
|
|
|
|
|
|
+ if (list_empty(&tp->t_items)) {
|
|
|
|
+ ASSERT(0);
|
|
return 0;
|
|
return 0;
|
|
|
|
+ }
|
|
|
|
|
|
- while (lidp != NULL) {
|
|
|
|
|
|
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
|
|
/*
|
|
/*
|
|
* Skip items which aren't dirty in this transaction.
|
|
* Skip items which aren't dirty in this transaction.
|
|
*/
|
|
*/
|
|
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
|
|
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
|
|
continue;
|
|
continue;
|
|
- }
|
|
|
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
|
nvecs += lidp->lid_size;
|
|
nvecs += lidp->lid_size;
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return nvecs;
|
|
return nvecs;
|
|
@@ -1173,7 +1272,7 @@ xfs_trans_fill_vecs(
|
|
struct xfs_trans *tp,
|
|
struct xfs_trans *tp,
|
|
struct xfs_log_iovec *log_vector)
|
|
struct xfs_log_iovec *log_vector)
|
|
{
|
|
{
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
struct xfs_log_iovec *vecp;
|
|
struct xfs_log_iovec *vecp;
|
|
uint nitems;
|
|
uint nitems;
|
|
|
|
|
|
@@ -1184,14 +1283,11 @@ xfs_trans_fill_vecs(
|
|
vecp = log_vector + 1;
|
|
vecp = log_vector + 1;
|
|
|
|
|
|
nitems = 0;
|
|
nitems = 0;
|
|
- lidp = xfs_trans_first_item(tp);
|
|
|
|
- ASSERT(lidp);
|
|
|
|
- while (lidp) {
|
|
|
|
|
|
+ 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. */
|
|
/* Skip items which aren't dirty in this transaction. */
|
|
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
|
|
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
|
|
continue;
|
|
continue;
|
|
- }
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* The item may be marked dirty but not log anything. This can
|
|
* The item may be marked dirty but not log anything. This can
|
|
@@ -1202,7 +1298,6 @@ xfs_trans_fill_vecs(
|
|
IOP_FORMAT(lidp->lid_item, vecp);
|
|
IOP_FORMAT(lidp->lid_item, vecp);
|
|
vecp += lidp->lid_size;
|
|
vecp += lidp->lid_size;
|
|
IOP_PIN(lidp->lid_item);
|
|
IOP_PIN(lidp->lid_item);
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1297,24 +1392,15 @@ xfs_trans_committed(
|
|
struct xfs_trans *tp,
|
|
struct xfs_trans *tp,
|
|
int abortflag)
|
|
int abortflag)
|
|
{
|
|
{
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
- xfs_log_item_chunk_t *licp;
|
|
|
|
- xfs_log_item_chunk_t *next_licp;
|
|
|
|
|
|
+ struct xfs_log_item_desc *lidp, *next;
|
|
|
|
|
|
/* Call the transaction's completion callback if there is one. */
|
|
/* Call the transaction's completion callback if there is one. */
|
|
if (tp->t_callback != NULL)
|
|
if (tp->t_callback != NULL)
|
|
tp->t_callback(tp, tp->t_callarg);
|
|
tp->t_callback(tp, tp->t_callarg);
|
|
|
|
|
|
- for (lidp = xfs_trans_first_item(tp);
|
|
|
|
- lidp != NULL;
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
|
|
|
+ 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_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
|
|
- }
|
|
|
|
-
|
|
|
|
- /* free the item chunks, ignoring the embedded chunk */
|
|
|
|
- for (licp = tp->t_items.lic_next; licp != NULL; licp = next_licp) {
|
|
|
|
- next_licp = licp->lic_next;
|
|
|
|
- kmem_free(licp);
|
|
|
|
|
|
+ xfs_trans_free_item_desc(lidp);
|
|
}
|
|
}
|
|
|
|
|
|
xfs_trans_free(tp);
|
|
xfs_trans_free(tp);
|
|
@@ -1329,11 +1415,9 @@ xfs_trans_uncommit(
|
|
struct xfs_trans *tp,
|
|
struct xfs_trans *tp,
|
|
uint flags)
|
|
uint flags)
|
|
{
|
|
{
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
|
|
|
|
- for (lidp = xfs_trans_first_item(tp);
|
|
|
|
- lidp != NULL;
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp)) {
|
|
|
|
|
|
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
|
|
/*
|
|
/*
|
|
* Unpin all but those that aren't dirty.
|
|
* Unpin all but those that aren't dirty.
|
|
*/
|
|
*/
|
|
@@ -1504,33 +1588,28 @@ STATIC struct xfs_log_vec *
|
|
xfs_trans_alloc_log_vecs(
|
|
xfs_trans_alloc_log_vecs(
|
|
xfs_trans_t *tp)
|
|
xfs_trans_t *tp)
|
|
{
|
|
{
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
struct xfs_log_vec *lv = NULL;
|
|
struct xfs_log_vec *lv = NULL;
|
|
struct xfs_log_vec *ret_lv = NULL;
|
|
struct xfs_log_vec *ret_lv = NULL;
|
|
|
|
|
|
- lidp = xfs_trans_first_item(tp);
|
|
|
|
|
|
|
|
/* Bail out if we didn't find a log item. */
|
|
/* Bail out if we didn't find a log item. */
|
|
- if (!lidp) {
|
|
|
|
|
|
+ if (list_empty(&tp->t_items)) {
|
|
ASSERT(0);
|
|
ASSERT(0);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- while (lidp != NULL) {
|
|
|
|
|
|
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
|
|
struct xfs_log_vec *new_lv;
|
|
struct xfs_log_vec *new_lv;
|
|
|
|
|
|
/* Skip items which aren't dirty in this transaction. */
|
|
/* Skip items which aren't dirty in this transaction. */
|
|
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
|
|
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
|
|
continue;
|
|
continue;
|
|
- }
|
|
|
|
|
|
|
|
/* Skip items that do not have any vectors for writing */
|
|
/* Skip items that do not have any vectors for writing */
|
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
|
- if (!lidp->lid_size) {
|
|
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
|
|
+ if (!lidp->lid_size)
|
|
continue;
|
|
continue;
|
|
- }
|
|
|
|
|
|
|
|
new_lv = kmem_zalloc(sizeof(*new_lv) +
|
|
new_lv = kmem_zalloc(sizeof(*new_lv) +
|
|
lidp->lid_size * sizeof(struct xfs_log_iovec),
|
|
lidp->lid_size * sizeof(struct xfs_log_iovec),
|
|
@@ -1545,7 +1624,6 @@ xfs_trans_alloc_log_vecs(
|
|
else
|
|
else
|
|
lv->lv_next = new_lv;
|
|
lv->lv_next = new_lv;
|
|
lv = new_lv;
|
|
lv = new_lv;
|
|
- lidp = xfs_trans_next_item(tp, lidp);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return ret_lv;
|
|
return ret_lv;
|
|
@@ -1704,12 +1782,6 @@ xfs_trans_cancel(
|
|
int flags)
|
|
int flags)
|
|
{
|
|
{
|
|
int log_flags;
|
|
int log_flags;
|
|
-#ifdef DEBUG
|
|
|
|
- xfs_log_item_chunk_t *licp;
|
|
|
|
- xfs_log_item_desc_t *lidp;
|
|
|
|
- xfs_log_item_t *lip;
|
|
|
|
- int i;
|
|
|
|
-#endif
|
|
|
|
xfs_mount_t *mp = tp->t_mountp;
|
|
xfs_mount_t *mp = tp->t_mountp;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1728,21 +1800,11 @@ xfs_trans_cancel(
|
|
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
|
|
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
#ifdef DEBUG
|
|
- if (!(flags & XFS_TRANS_ABORT)) {
|
|
|
|
- licp = &(tp->t_items);
|
|
|
|
- while (licp != NULL) {
|
|
|
|
- lidp = licp->lic_descs;
|
|
|
|
- for (i = 0; i < licp->lic_unused; i++, lidp++) {
|
|
|
|
- if (xfs_lic_isfree(licp, i)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- lip = lidp->lid_item;
|
|
|
|
- if (!XFS_FORCED_SHUTDOWN(mp))
|
|
|
|
- ASSERT(!(lip->li_type == XFS_LI_EFD));
|
|
|
|
- }
|
|
|
|
- licp = licp->lic_next;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!(flags & XFS_TRANS_ABORT) && !XFS_FORCED_SHUTDOWN(mp)) {
|
|
|
|
+ struct xfs_log_item_desc *lidp;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(lidp, &tp->t_items, lid_trans)
|
|
|
|
+ ASSERT(!(lidp->lid_item->li_type == XFS_LI_EFD));
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|
|
xfs_trans_unreserve_and_mod_sb(tp);
|