|
@@ -2427,13 +2427,20 @@ restart:
|
|
if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) {
|
|
if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) {
|
|
xlog_state_switch_iclogs(log, iclog, iclog->ic_size);
|
|
xlog_state_switch_iclogs(log, iclog, iclog->ic_size);
|
|
|
|
|
|
- /* If I'm the only one writing to this iclog, sync it to disk */
|
|
|
|
- if (atomic_read(&iclog->ic_refcnt) == 1) {
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If I'm the only one writing to this iclog, sync it to disk.
|
|
|
|
+ * We need to do an atomic compare and decrement here to avoid
|
|
|
|
+ * racing with concurrent atomic_dec_and_lock() calls in
|
|
|
|
+ * xlog_state_release_iclog() when there is more than one
|
|
|
|
+ * reference to the iclog.
|
|
|
|
+ */
|
|
|
|
+ if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1)) {
|
|
|
|
+ /* we are the only one */
|
|
spin_unlock(&log->l_icloglock);
|
|
spin_unlock(&log->l_icloglock);
|
|
- if ((error = xlog_state_release_iclog(log, iclog)))
|
|
|
|
|
|
+ error = xlog_state_release_iclog(log, iclog);
|
|
|
|
+ if (error)
|
|
return error;
|
|
return error;
|
|
} else {
|
|
} else {
|
|
- atomic_dec(&iclog->ic_refcnt);
|
|
|
|
spin_unlock(&log->l_icloglock);
|
|
spin_unlock(&log->l_icloglock);
|
|
}
|
|
}
|
|
goto restart;
|
|
goto restart;
|