@@ -190,31 +190,48 @@ int ocfs2_recovery_init(struct ocfs2_super *osb)
190
190
return 0 ;
191
191
}
192
192
193
- /* we can't grab the goofy sem lock from inside wait_event, so we use
194
- * memory barriers to make sure that we'll see the null task before
195
- * being woken up */
196
193
static int ocfs2_recovery_thread_running (struct ocfs2_super * osb )
197
194
{
198
- mb ();
199
195
return osb -> recovery_thread_task != NULL ;
200
196
}
201
197
202
- void ocfs2_recovery_exit (struct ocfs2_super * osb )
198
+ static void ocfs2_recovery_disable (struct ocfs2_super * osb ,
199
+ enum ocfs2_recovery_state state )
203
200
{
204
- struct ocfs2_recovery_map * rm ;
205
-
206
- /* disable any new recovery threads and wait for any currently
207
- * running ones to exit. Do this before setting the vol_state. */
208
201
mutex_lock (& osb -> recovery_lock );
209
- osb -> recovery_state = OCFS2_REC_DISABLED ;
202
+ /*
203
+ * If recovery thread is not running, we can directly transition to
204
+ * final state.
205
+ */
206
+ if (!ocfs2_recovery_thread_running (osb )) {
207
+ osb -> recovery_state = state + 1 ;
208
+ goto out_lock ;
209
+ }
210
+ osb -> recovery_state = state ;
211
+ /* Wait for recovery thread to acknowledge state transition */
212
+ wait_event_cmd (osb -> recovery_event ,
213
+ !ocfs2_recovery_thread_running (osb ) ||
214
+ osb -> recovery_state >= state + 1 ,
215
+ mutex_unlock (& osb -> recovery_lock ),
216
+ mutex_lock (& osb -> recovery_lock ));
217
+ out_lock :
210
218
mutex_unlock (& osb -> recovery_lock );
211
- wait_event (osb -> recovery_event , !ocfs2_recovery_thread_running (osb ));
212
219
213
- /* At this point, we know that no more recovery threads can be
214
- * launched, so wait for any recovery completion work to
215
- * complete. */
220
+ /*
221
+ * At this point we know that no more recovery work can be queued so
222
+ * wait for any recovery completion work to complete.
223
+ */
216
224
if (osb -> ocfs2_wq )
217
225
flush_workqueue (osb -> ocfs2_wq );
226
+ }
227
+
228
+ void ocfs2_recovery_exit (struct ocfs2_super * osb )
229
+ {
230
+ struct ocfs2_recovery_map * rm ;
231
+
232
+ /* disable any new recovery threads and wait for any currently
233
+ * running ones to exit. Do this before setting the vol_state. */
234
+ ocfs2_recovery_disable (osb , OCFS2_REC_WANT_DISABLE );
218
235
219
236
/*
220
237
* Now that recovery is shut down, and the osb is about to be
@@ -1569,7 +1586,8 @@ static int __ocfs2_recovery_thread(void *arg)
1569
1586
1570
1587
ocfs2_free_replay_slots (osb );
1571
1588
osb -> recovery_thread_task = NULL ;
1572
- mb (); /* sync with ocfs2_recovery_thread_running */
1589
+ if (osb -> recovery_state == OCFS2_REC_WANT_DISABLE )
1590
+ osb -> recovery_state = OCFS2_REC_DISABLED ;
1573
1591
wake_up (& osb -> recovery_event );
1574
1592
1575
1593
mutex_unlock (& osb -> recovery_lock );
@@ -1585,13 +1603,13 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num)
1585
1603
int was_set = -1 ;
1586
1604
1587
1605
mutex_lock (& osb -> recovery_lock );
1588
- if (osb -> recovery_state < OCFS2_REC_DISABLED )
1606
+ if (osb -> recovery_state < OCFS2_REC_WANT_DISABLE )
1589
1607
was_set = ocfs2_recovery_map_set (osb , node_num );
1590
1608
1591
1609
trace_ocfs2_recovery_thread (node_num , osb -> node_num ,
1592
1610
osb -> recovery_state , osb -> recovery_thread_task , was_set );
1593
1611
1594
- if (osb -> recovery_state == OCFS2_REC_DISABLED )
1612
+ if (osb -> recovery_state >= OCFS2_REC_WANT_DISABLE )
1595
1613
goto out ;
1596
1614
1597
1615
if (osb -> recovery_thread_task )
0 commit comments