|
@@ -463,12 +463,40 @@ xlog_cil_push(
|
|
|
spin_unlock(&cil->xc_push_lock);
|
|
|
goto out_skip;
|
|
|
}
|
|
|
- spin_unlock(&cil->xc_push_lock);
|
|
|
|
|
|
|
|
|
/* check for a previously pushed seqeunce */
|
|
|
- if (push_seq < cil->xc_ctx->sequence)
|
|
|
+ if (push_seq < cil->xc_ctx->sequence) {
|
|
|
+ spin_unlock(&cil->xc_push_lock);
|
|
|
goto out_skip;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We are now going to push this context, so add it to the committing
|
|
|
+ * list before we do anything else. This ensures that anyone waiting on
|
|
|
+ * this push can easily detect the difference between a "push in
|
|
|
+ * progress" and "CIL is empty, nothing to do".
|
|
|
+ *
|
|
|
+ * IOWs, a wait loop can now check for:
|
|
|
+ * the current sequence not being found on the committing list;
|
|
|
+ * an empty CIL; and
|
|
|
+ * an unchanged sequence number
|
|
|
+ * to detect a push that had nothing to do and therefore does not need
|
|
|
+ * waiting on. If the CIL is not empty, we get put on the committing
|
|
|
+ * list before emptying the CIL and bumping the sequence number. Hence
|
|
|
+ * an empty CIL and an unchanged sequence number means we jumped out
|
|
|
+ * above after doing nothing.
|
|
|
+ *
|
|
|
+ * Hence the waiter will either find the commit sequence on the
|
|
|
+ * committing list or the sequence number will be unchanged and the CIL
|
|
|
+ * still dirty. In that latter case, the push has not yet started, and
|
|
|
+ * so the waiter will have to continue trying to check the CIL
|
|
|
+ * committing list until it is found. In extreme cases of delay, the
|
|
|
+ * sequence may fully commit between the attempts the wait makes to wait
|
|
|
+ * on the commit sequence.
|
|
|
+ */
|
|
|
+ list_add(&ctx->committing, &cil->xc_committing);
|
|
|
+ spin_unlock(&cil->xc_push_lock);
|
|
|
|
|
|
/*
|
|
|
* pull all the log vectors off the items in the CIL, and
|
|
@@ -532,7 +560,6 @@ xlog_cil_push(
|
|
|
*/
|
|
|
spin_lock(&cil->xc_push_lock);
|
|
|
cil->xc_current_sequence = new_ctx->sequence;
|
|
|
- list_add(&ctx->committing, &cil->xc_committing);
|
|
|
spin_unlock(&cil->xc_push_lock);
|
|
|
up_write(&cil->xc_ctx_lock);
|
|
|
|
|
@@ -855,13 +882,15 @@ restart:
|
|
|
* Hence by the time we have got here it our sequence may not have been
|
|
|
* pushed yet. This is true if the current sequence still matches the
|
|
|
* push sequence after the above wait loop and the CIL still contains
|
|
|
- * dirty objects.
|
|
|
+ * dirty objects. This is guaranteed by the push code first adding the
|
|
|
+ * context to the committing list before emptying the CIL.
|
|
|
*
|
|
|
- * When the push occurs, it will empty the CIL and atomically increment
|
|
|
- * the currect sequence past the push sequence and move it into the
|
|
|
- * committing list. Of course, if the CIL is clean at the time of the
|
|
|
- * push, it won't have pushed the CIL at all, so in that case we should
|
|
|
- * try the push for this sequence again from the start just in case.
|
|
|
+ * Hence if we don't find the context in the committing list and the
|
|
|
+ * current sequence number is unchanged then the CIL contents are
|
|
|
+ * significant. If the CIL is empty, if means there was nothing to push
|
|
|
+ * and that means there is nothing to wait for. If the CIL is not empty,
|
|
|
+ * it means we haven't yet started the push, because if it had started
|
|
|
+ * we would have found the context on the committing list.
|
|
|
*/
|
|
|
if (sequence == cil->xc_current_sequence &&
|
|
|
!list_empty(&cil->xc_cil)) {
|