@@ -3846,14 +3846,13 @@ STATIC int
3846
3846
xlog_recover_commit_trans (
3847
3847
struct xlog * log ,
3848
3848
struct xlog_recover * trans ,
3849
- int pass )
3849
+ int pass ,
3850
+ struct list_head * buffer_list )
3850
3851
{
3851
3852
int error = 0 ;
3852
- int error2 ;
3853
3853
int items_queued = 0 ;
3854
3854
struct xlog_recover_item * item ;
3855
3855
struct xlog_recover_item * next ;
3856
- LIST_HEAD (buffer_list );
3857
3856
LIST_HEAD (ra_list );
3858
3857
LIST_HEAD (done_list );
3859
3858
@@ -3876,7 +3875,7 @@ xlog_recover_commit_trans(
3876
3875
items_queued ++ ;
3877
3876
if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX ) {
3878
3877
error = xlog_recover_items_pass2 (log , trans ,
3879
- & buffer_list , & ra_list );
3878
+ buffer_list , & ra_list );
3880
3879
list_splice_tail_init (& ra_list , & done_list );
3881
3880
items_queued = 0 ;
3882
3881
}
@@ -3894,15 +3893,14 @@ xlog_recover_commit_trans(
3894
3893
if (!list_empty (& ra_list )) {
3895
3894
if (!error )
3896
3895
error = xlog_recover_items_pass2 (log , trans ,
3897
- & buffer_list , & ra_list );
3896
+ buffer_list , & ra_list );
3898
3897
list_splice_tail_init (& ra_list , & done_list );
3899
3898
}
3900
3899
3901
3900
if (!list_empty (& done_list ))
3902
3901
list_splice_init (& done_list , & trans -> r_itemq );
3903
3902
3904
- error2 = xfs_buf_delwri_submit (& buffer_list );
3905
- return error ? error : error2 ;
3903
+ return error ;
3906
3904
}
3907
3905
3908
3906
STATIC void
@@ -4085,7 +4083,8 @@ xlog_recovery_process_trans(
4085
4083
char * dp ,
4086
4084
unsigned int len ,
4087
4085
unsigned int flags ,
4088
- int pass )
4086
+ int pass ,
4087
+ struct list_head * buffer_list )
4089
4088
{
4090
4089
int error = 0 ;
4091
4090
bool freeit = false;
@@ -4109,7 +4108,8 @@ xlog_recovery_process_trans(
4109
4108
error = xlog_recover_add_to_cont_trans (log , trans , dp , len );
4110
4109
break ;
4111
4110
case XLOG_COMMIT_TRANS :
4112
- error = xlog_recover_commit_trans (log , trans , pass );
4111
+ error = xlog_recover_commit_trans (log , trans , pass ,
4112
+ buffer_list );
4113
4113
/* success or fail, we are now done with this transaction. */
4114
4114
freeit = true;
4115
4115
break ;
@@ -4191,10 +4191,12 @@ xlog_recover_process_ophdr(
4191
4191
struct xlog_op_header * ohead ,
4192
4192
char * dp ,
4193
4193
char * end ,
4194
- int pass )
4194
+ int pass ,
4195
+ struct list_head * buffer_list )
4195
4196
{
4196
4197
struct xlog_recover * trans ;
4197
4198
unsigned int len ;
4199
+ int error ;
4198
4200
4199
4201
/* Do we understand who wrote this op? */
4200
4202
if (ohead -> oh_clientid != XFS_TRANSACTION &&
@@ -4221,8 +4223,39 @@ xlog_recover_process_ophdr(
4221
4223
return 0 ;
4222
4224
}
4223
4225
4226
+ /*
4227
+ * The recovered buffer queue is drained only once we know that all
4228
+ * recovery items for the current LSN have been processed. This is
4229
+ * required because:
4230
+ *
4231
+ * - Buffer write submission updates the metadata LSN of the buffer.
4232
+ * - Log recovery skips items with a metadata LSN >= the current LSN of
4233
+ * the recovery item.
4234
+ * - Separate recovery items against the same metadata buffer can share
4235
+ * a current LSN. I.e., consider that the LSN of a recovery item is
4236
+ * defined as the starting LSN of the first record in which its
4237
+ * transaction appears, that a record can hold multiple transactions,
4238
+ * and/or that a transaction can span multiple records.
4239
+ *
4240
+ * In other words, we are allowed to submit a buffer from log recovery
4241
+ * once per current LSN. Otherwise, we may incorrectly skip recovery
4242
+ * items and cause corruption.
4243
+ *
4244
+ * We don't know up front whether buffers are updated multiple times per
4245
+ * LSN. Therefore, track the current LSN of each commit log record as it
4246
+ * is processed and drain the queue when it changes. Use commit records
4247
+ * because they are ordered correctly by the logging code.
4248
+ */
4249
+ if (log -> l_recovery_lsn != trans -> r_lsn &&
4250
+ ohead -> oh_flags & XLOG_COMMIT_TRANS ) {
4251
+ error = xfs_buf_delwri_submit (buffer_list );
4252
+ if (error )
4253
+ return error ;
4254
+ log -> l_recovery_lsn = trans -> r_lsn ;
4255
+ }
4256
+
4224
4257
return xlog_recovery_process_trans (log , trans , dp , len ,
4225
- ohead -> oh_flags , pass );
4258
+ ohead -> oh_flags , pass , buffer_list );
4226
4259
}
4227
4260
4228
4261
/*
@@ -4240,7 +4273,8 @@ xlog_recover_process_data(
4240
4273
struct hlist_head rhash [],
4241
4274
struct xlog_rec_header * rhead ,
4242
4275
char * dp ,
4243
- int pass )
4276
+ int pass ,
4277
+ struct list_head * buffer_list )
4244
4278
{
4245
4279
struct xlog_op_header * ohead ;
4246
4280
char * end ;
@@ -4262,7 +4296,7 @@ xlog_recover_process_data(
4262
4296
4263
4297
/* errors will abort recovery */
4264
4298
error = xlog_recover_process_ophdr (log , rhash , rhead , ohead ,
4265
- dp , end , pass );
4299
+ dp , end , pass , buffer_list );
4266
4300
if (error )
4267
4301
return error ;
4268
4302
@@ -4685,7 +4719,8 @@ xlog_recover_process(
4685
4719
struct hlist_head rhash [],
4686
4720
struct xlog_rec_header * rhead ,
4687
4721
char * dp ,
4688
- int pass )
4722
+ int pass ,
4723
+ struct list_head * buffer_list )
4689
4724
{
4690
4725
int error ;
4691
4726
__le32 crc ;
@@ -4732,7 +4767,8 @@ xlog_recover_process(
4732
4767
if (error )
4733
4768
return error ;
4734
4769
4735
- return xlog_recover_process_data (log , rhash , rhead , dp , pass );
4770
+ return xlog_recover_process_data (log , rhash , rhead , dp , pass ,
4771
+ buffer_list );
4736
4772
}
4737
4773
4738
4774
STATIC int
@@ -4793,9 +4829,11 @@ xlog_do_recovery_pass(
4793
4829
char * offset ;
4794
4830
xfs_buf_t * hbp , * dbp ;
4795
4831
int error = 0 , h_size , h_len ;
4832
+ int error2 = 0 ;
4796
4833
int bblks , split_bblks ;
4797
4834
int hblks , split_hblks , wrapped_hblks ;
4798
4835
struct hlist_head rhash [XLOG_RHASH_SIZE ];
4836
+ LIST_HEAD (buffer_list );
4799
4837
4800
4838
ASSERT (head_blk != tail_blk );
4801
4839
rhead_blk = 0 ;
@@ -4981,7 +5019,7 @@ xlog_do_recovery_pass(
4981
5019
}
4982
5020
4983
5021
error = xlog_recover_process (log , rhash , rhead , offset ,
4984
- pass );
5022
+ pass , & buffer_list );
4985
5023
if (error )
4986
5024
goto bread_err2 ;
4987
5025
@@ -5012,7 +5050,8 @@ xlog_do_recovery_pass(
5012
5050
if (error )
5013
5051
goto bread_err2 ;
5014
5052
5015
- error = xlog_recover_process (log , rhash , rhead , offset , pass );
5053
+ error = xlog_recover_process (log , rhash , rhead , offset , pass ,
5054
+ & buffer_list );
5016
5055
if (error )
5017
5056
goto bread_err2 ;
5018
5057
@@ -5025,10 +5064,17 @@ xlog_do_recovery_pass(
5025
5064
bread_err1 :
5026
5065
xlog_put_bp (hbp );
5027
5066
5067
+ /*
5068
+ * Submit buffers that have been added from the last record processed,
5069
+ * regardless of error status.
5070
+ */
5071
+ if (!list_empty (& buffer_list ))
5072
+ error2 = xfs_buf_delwri_submit (& buffer_list );
5073
+
5028
5074
if (error && first_bad )
5029
5075
* first_bad = rhead_blk ;
5030
5076
5031
- return error ;
5077
+ return error ? error : error2 ;
5032
5078
}
5033
5079
5034
5080
/*
0 commit comments