@@ -93,21 +93,24 @@ static const struct rhashtable_params bch_promote_params = {
93
93
static inline int should_promote (struct bch_fs * c , struct bkey_s_c k ,
94
94
struct bpos pos ,
95
95
struct bch_io_opts opts ,
96
- unsigned flags )
96
+ unsigned flags ,
97
+ struct bch_io_failures * failed )
97
98
{
98
- BUG_ON (!opts .promote_target );
99
+ if (!failed ) {
100
+ BUG_ON (!opts .promote_target );
99
101
100
- if (!(flags & BCH_READ_MAY_PROMOTE ))
101
- return - BCH_ERR_nopromote_may_not ;
102
+ if (!(flags & BCH_READ_MAY_PROMOTE ))
103
+ return - BCH_ERR_nopromote_may_not ;
102
104
103
- if (bch2_bkey_has_target (c , k , opts .promote_target ))
104
- return - BCH_ERR_nopromote_already_promoted ;
105
+ if (bch2_bkey_has_target (c , k , opts .promote_target ))
106
+ return - BCH_ERR_nopromote_already_promoted ;
105
107
106
- if (bkey_extent_is_unwritten (k ))
107
- return - BCH_ERR_nopromote_unwritten ;
108
+ if (bkey_extent_is_unwritten (k ))
109
+ return - BCH_ERR_nopromote_unwritten ;
108
110
109
- if (bch2_target_congested (c , opts .promote_target ))
110
- return - BCH_ERR_nopromote_congested ;
111
+ if (bch2_target_congested (c , opts .promote_target ))
112
+ return - BCH_ERR_nopromote_congested ;
113
+ }
111
114
112
115
if (rhashtable_lookup_fast (& c -> promote_table , & pos ,
113
116
bch_promote_params ))
@@ -164,7 +167,8 @@ static struct promote_op *__promote_alloc(struct btree_trans *trans,
164
167
struct extent_ptr_decoded * pick ,
165
168
struct bch_io_opts opts ,
166
169
unsigned sectors ,
167
- struct bch_read_bio * * rbio )
170
+ struct bch_read_bio * * rbio ,
171
+ struct bch_io_failures * failed )
168
172
{
169
173
struct bch_fs * c = trans -> c ;
170
174
struct promote_op * op = NULL ;
@@ -217,14 +221,28 @@ static struct promote_op *__promote_alloc(struct btree_trans *trans,
217
221
bio = & op -> write .op .wbio .bio ;
218
222
bio_init (bio , NULL , bio -> bi_inline_vecs , pages , 0 );
219
223
224
+ struct data_update_opts update_opts = {};
225
+
226
+ if (!failed ) {
227
+ update_opts .target = opts .promote_target ;
228
+ update_opts .extra_replicas = 1 ;
229
+ update_opts .write_flags = BCH_WRITE_ALLOC_NOWAIT |BCH_WRITE_CACHED ;
230
+ } else {
231
+ update_opts .target = opts .foreground_target ;
232
+
233
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (k );
234
+ unsigned i = 0 ;
235
+ bkey_for_each_ptr (ptrs , ptr ) {
236
+ if (bch2_dev_io_failures (failed , ptr -> dev ))
237
+ update_opts .rewrite_ptrs |= BIT (i );
238
+ i ++ ;
239
+ }
240
+ }
241
+
220
242
ret = bch2_data_update_init (trans , NULL , NULL , & op -> write ,
221
243
writepoint_hashed ((unsigned long ) current ),
222
244
opts ,
223
- (struct data_update_opts ) {
224
- .target = opts .promote_target ,
225
- .extra_replicas = 1 ,
226
- .write_flags = BCH_WRITE_ALLOC_NOWAIT |BCH_WRITE_CACHED ,
227
- },
245
+ update_opts ,
228
246
btree_id , k );
229
247
/*
230
248
* possible errors: -BCH_ERR_nocow_lock_blocked,
@@ -258,10 +276,17 @@ static struct promote_op *promote_alloc(struct btree_trans *trans,
258
276
unsigned flags ,
259
277
struct bch_read_bio * * rbio ,
260
278
bool * bounce ,
261
- bool * read_full )
279
+ bool * read_full ,
280
+ struct bch_io_failures * failed )
262
281
{
263
282
struct bch_fs * c = trans -> c ;
264
- bool promote_full = * read_full || READ_ONCE (c -> promote_whole_extents );
283
+ /*
284
+ * if failed != NULL we're not actually doing a promote, we're
285
+ * recovering from an io/checksum error
286
+ */
287
+ bool promote_full = (failed ||
288
+ * read_full ||
289
+ READ_ONCE (c -> promote_whole_extents ));
265
290
/* data might have to be decompressed in the write path: */
266
291
unsigned sectors = promote_full
267
292
? max (pick -> crc .compressed_size , pick -> crc .live_size )
@@ -272,15 +297,15 @@ static struct promote_op *promote_alloc(struct btree_trans *trans,
272
297
struct promote_op * promote ;
273
298
int ret ;
274
299
275
- ret = should_promote (c , k , pos , opts , flags );
300
+ ret = should_promote (c , k , pos , opts , flags , failed );
276
301
if (ret )
277
302
goto nopromote ;
278
303
279
304
promote = __promote_alloc (trans ,
280
305
k .k -> type == KEY_TYPE_reflink_v
281
306
? BTREE_ID_reflink
282
307
: BTREE_ID_extents ,
283
- k , pos , pick , opts , sectors , rbio );
308
+ k , pos , pick , opts , sectors , rbio , failed );
284
309
ret = PTR_ERR_OR_ZERO (promote );
285
310
if (ret )
286
311
goto nopromote ;
@@ -910,9 +935,9 @@ int __bch2_read_extent(struct btree_trans *trans, struct bch_read_bio *orig,
910
935
bounce = true;
911
936
}
912
937
913
- if (orig -> opts .promote_target )
938
+ if (orig -> opts .promote_target )// || failed)
914
939
promote = promote_alloc (trans , iter , k , & pick , orig -> opts , flags ,
915
- & rbio , & bounce , & read_full );
940
+ & rbio , & bounce , & read_full , failed );
916
941
917
942
if (!read_full ) {
918
943
EBUG_ON (crc_is_compressed (pick .crc ));
0 commit comments