Blame view

fs/btrfs/scrub.c 110 KB
a2de733c7   Arne Jansen   btrfs: scrub
1
  /*
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
2
   * Copyright (C) 2011, 2012 STRATO.  All rights reserved.
a2de733c7   Arne Jansen   btrfs: scrub
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public
   * License v2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public
   * License along with this program; if not, write to the
   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   * Boston, MA 021110-1307, USA.
   */
a2de733c7   Arne Jansen   btrfs: scrub
18
  #include <linux/blkdev.h>
558540c17   Jan Schmidt   btrfs scrub: prin...
19
  #include <linux/ratelimit.h>
a2de733c7   Arne Jansen   btrfs: scrub
20
21
22
23
  #include "ctree.h"
  #include "volumes.h"
  #include "disk-io.h"
  #include "ordered-data.h"
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
24
  #include "transaction.h"
558540c17   Jan Schmidt   btrfs scrub: prin...
25
  #include "backref.h"
5da6fcbc4   Jan Schmidt   btrfs: integratin...
26
  #include "extent_io.h"
ff023aac3   Stefan Behrens   Btrfs: add code t...
27
  #include "dev-replace.h"
21adbd5cb   Stefan Behrens   Btrfs: integrate ...
28
  #include "check-integrity.h"
606686eea   Josef Bacik   Btrfs: use rcu to...
29
  #include "rcu-string.h"
53b381b3a   David Woodhouse   Btrfs: RAID5 and ...
30
  #include "raid56.h"
a2de733c7   Arne Jansen   btrfs: scrub
31
32
33
34
35
36
37
38
  
  /*
   * This is only the first step towards a full-features scrub. It reads all
   * extent and super block and verifies the checksums. In case a bad checksum
   * is found or the extent cannot be read, good data will be written back if
   * any can be found.
   *
   * Future enhancements:
a2de733c7   Arne Jansen   btrfs: scrub
39
40
   *  - In case an unrepairable extent is encountered, track which files are
   *    affected and report them
a2de733c7   Arne Jansen   btrfs: scrub
41
   *  - track and record media errors, throw out bad devices
a2de733c7   Arne Jansen   btrfs: scrub
42
   *  - add a mode to also read unallocated space
a2de733c7   Arne Jansen   btrfs: scrub
43
   */
b5d67f64f   Stefan Behrens   Btrfs: change scr...
44
  struct scrub_block;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
45
  struct scrub_ctx;
a2de733c7   Arne Jansen   btrfs: scrub
46

ff023aac3   Stefan Behrens   Btrfs: add code t...
47
48
49
50
51
52
53
54
55
  /*
   * the following three values only influence the performance.
   * The last one configures the number of parallel and outstanding I/O
   * operations. The first two values configure an upper limit for the number
   * of (dynamically allocated) pages that are added to a bio.
   */
  #define SCRUB_PAGES_PER_RD_BIO	32	/* 128k per bio */
  #define SCRUB_PAGES_PER_WR_BIO	32	/* 128k per bio */
  #define SCRUB_BIOS_PER_SCTX	64	/* 8MB per device in flight */
7a9e99876   Stefan Behrens   Btrfs: make the s...
56
57
58
59
60
61
  
  /*
   * the following value times PAGE_SIZE needs to be large enough to match the
   * largest node/leaf/sector size that shall be supported.
   * Values larger than BTRFS_STRIPE_LEN are not supported.
   */
b5d67f64f   Stefan Behrens   Btrfs: change scr...
62
  #define SCRUB_MAX_PAGES_PER_BLOCK	16	/* 64k per node/leaf/sector */
a2de733c7   Arne Jansen   btrfs: scrub
63

af8e2d1df   Miao Xie   Btrfs, scrub: rep...
64
65
66
67
68
69
  struct scrub_recover {
  	atomic_t		refs;
  	struct btrfs_bio	*bbio;
  	u64			*raid_map;
  	u64			map_length;
  };
a2de733c7   Arne Jansen   btrfs: scrub
70
  struct scrub_page {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
71
72
  	struct scrub_block	*sblock;
  	struct page		*page;
442a4f630   Stefan Behrens   Btrfs: add device...
73
  	struct btrfs_device	*dev;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
74
  	struct list_head	list;
a2de733c7   Arne Jansen   btrfs: scrub
75
76
  	u64			flags;  /* extent flags */
  	u64			generation;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
77
78
  	u64			logical;
  	u64			physical;
ff023aac3   Stefan Behrens   Btrfs: add code t...
79
  	u64			physical_for_dev_replace;
7a9e99876   Stefan Behrens   Btrfs: make the s...
80
  	atomic_t		ref_count;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
81
82
83
84
85
  	struct {
  		unsigned int	mirror_num:8;
  		unsigned int	have_csum:1;
  		unsigned int	io_error:1;
  	};
a2de733c7   Arne Jansen   btrfs: scrub
86
  	u8			csum[BTRFS_CSUM_SIZE];
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
87
88
  
  	struct scrub_recover	*recover;
a2de733c7   Arne Jansen   btrfs: scrub
89
90
91
92
  };
  
  struct scrub_bio {
  	int			index;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
93
  	struct scrub_ctx	*sctx;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
94
  	struct btrfs_device	*dev;
a2de733c7   Arne Jansen   btrfs: scrub
95
96
97
98
  	struct bio		*bio;
  	int			err;
  	u64			logical;
  	u64			physical;
ff023aac3   Stefan Behrens   Btrfs: add code t...
99
100
101
102
103
  #if SCRUB_PAGES_PER_WR_BIO >= SCRUB_PAGES_PER_RD_BIO
  	struct scrub_page	*pagev[SCRUB_PAGES_PER_WR_BIO];
  #else
  	struct scrub_page	*pagev[SCRUB_PAGES_PER_RD_BIO];
  #endif
b5d67f64f   Stefan Behrens   Btrfs: change scr...
104
  	int			page_count;
a2de733c7   Arne Jansen   btrfs: scrub
105
106
107
  	int			next_free;
  	struct btrfs_work	work;
  };
b5d67f64f   Stefan Behrens   Btrfs: change scr...
108
  struct scrub_block {
7a9e99876   Stefan Behrens   Btrfs: make the s...
109
  	struct scrub_page	*pagev[SCRUB_MAX_PAGES_PER_BLOCK];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
110
111
112
  	int			page_count;
  	atomic_t		outstanding_pages;
  	atomic_t		ref_count; /* free mem on transition to zero */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
113
  	struct scrub_ctx	*sctx;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
114
  	struct scrub_parity	*sparity;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
115
116
117
118
  	struct {
  		unsigned int	header_error:1;
  		unsigned int	checksum_error:1;
  		unsigned int	no_io_error_seen:1;
442a4f630   Stefan Behrens   Btrfs: add device...
119
  		unsigned int	generation_error:1; /* also sets header_error */
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
120
121
122
123
  
  		/* The following is for the data used to check parity */
  		/* It is for the data with checksum */
  		unsigned int	data_corrected:1;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
124
125
  	};
  };
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  /* Used for the chunks with parity stripe such RAID5/6 */
  struct scrub_parity {
  	struct scrub_ctx	*sctx;
  
  	struct btrfs_device	*scrub_dev;
  
  	u64			logic_start;
  
  	u64			logic_end;
  
  	int			nsectors;
  
  	int			stripe_len;
  
  	atomic_t		ref_count;
  
  	struct list_head	spages;
  
  	/* Work of parity check and repair */
  	struct btrfs_work	work;
  
  	/* Mark the parity blocks which have data */
  	unsigned long		*dbitmap;
  
  	/*
  	 * Mark the parity blocks which have data, but errors happen when
  	 * read data or check data
  	 */
  	unsigned long		*ebitmap;
  
  	unsigned long		bitmap[0];
  };
ff023aac3   Stefan Behrens   Btrfs: add code t...
158
159
160
161
162
163
164
  struct scrub_wr_ctx {
  	struct scrub_bio *wr_curr_bio;
  	struct btrfs_device *tgtdev;
  	int pages_per_wr_bio; /* <= SCRUB_PAGES_PER_WR_BIO */
  	atomic_t flush_all_writes;
  	struct mutex wr_lock;
  };
d9d181c1b   Stefan Behrens   Btrfs: rename the...
165
  struct scrub_ctx {
ff023aac3   Stefan Behrens   Btrfs: add code t...
166
  	struct scrub_bio	*bios[SCRUB_BIOS_PER_SCTX];
a36cf8b89   Stefan Behrens   Btrfs: remove the...
167
  	struct btrfs_root	*dev_root;
a2de733c7   Arne Jansen   btrfs: scrub
168
169
  	int			first_free;
  	int			curr;
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
170
171
  	atomic_t		bios_in_flight;
  	atomic_t		workers_pending;
a2de733c7   Arne Jansen   btrfs: scrub
172
173
174
175
176
  	spinlock_t		list_lock;
  	wait_queue_head_t	list_wait;
  	u16			csum_size;
  	struct list_head	csum_list;
  	atomic_t		cancel_req;
8628764e1   Arne Jansen   btrfs: add readon...
177
  	int			readonly;
ff023aac3   Stefan Behrens   Btrfs: add code t...
178
  	int			pages_per_rd_bio;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
179
180
  	u32			sectorsize;
  	u32			nodesize;
63a212abc   Stefan Behrens   Btrfs: disallow s...
181
182
  
  	int			is_dev_replace;
ff023aac3   Stefan Behrens   Btrfs: add code t...
183
  	struct scrub_wr_ctx	wr_ctx;
63a212abc   Stefan Behrens   Btrfs: disallow s...
184

a2de733c7   Arne Jansen   btrfs: scrub
185
186
187
188
189
190
  	/*
  	 * statistics
  	 */
  	struct btrfs_scrub_progress stat;
  	spinlock_t		stat_lock;
  };
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
191
  struct scrub_fixup_nodatasum {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
192
  	struct scrub_ctx	*sctx;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
193
  	struct btrfs_device	*dev;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
194
195
196
197
198
  	u64			logical;
  	struct btrfs_root	*root;
  	struct btrfs_work	work;
  	int			mirror_num;
  };
652f25a29   Josef Bacik   Btrfs: improve re...
199
200
201
202
203
204
  struct scrub_nocow_inode {
  	u64			inum;
  	u64			offset;
  	u64			root;
  	struct list_head	list;
  };
ff023aac3   Stefan Behrens   Btrfs: add code t...
205
206
207
208
209
210
  struct scrub_copy_nocow_ctx {
  	struct scrub_ctx	*sctx;
  	u64			logical;
  	u64			len;
  	int			mirror_num;
  	u64			physical_for_dev_replace;
652f25a29   Josef Bacik   Btrfs: improve re...
211
  	struct list_head	inodes;
ff023aac3   Stefan Behrens   Btrfs: add code t...
212
213
  	struct btrfs_work	work;
  };
558540c17   Jan Schmidt   btrfs scrub: prin...
214
215
216
  struct scrub_warning {
  	struct btrfs_path	*path;
  	u64			extent_item_size;
558540c17   Jan Schmidt   btrfs scrub: prin...
217
218
219
220
  	const char		*errstr;
  	sector_t		sector;
  	u64			logical;
  	struct btrfs_device	*dev;
558540c17   Jan Schmidt   btrfs scrub: prin...
221
  };
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
222
223
224
225
  static void scrub_pending_bio_inc(struct scrub_ctx *sctx);
  static void scrub_pending_bio_dec(struct scrub_ctx *sctx);
  static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx);
  static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
226
  static int scrub_handle_errored_block(struct scrub_block *sblock_to_check);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
227
  static int scrub_setup_recheck_block(struct scrub_ctx *sctx,
3ec706c83   Stefan Behrens   Btrfs: pass fs_in...
228
  				     struct btrfs_fs_info *fs_info,
ff023aac3   Stefan Behrens   Btrfs: add code t...
229
  				     struct scrub_block *original_sblock,
b5d67f64f   Stefan Behrens   Btrfs: change scr...
230
  				     u64 length, u64 logical,
ff023aac3   Stefan Behrens   Btrfs: add code t...
231
  				     struct scrub_block *sblocks_for_recheck);
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
232
233
234
  static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
  				struct scrub_block *sblock, int is_metadata,
  				int have_csum, u8 *csum, u64 generation,
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
235
  				u16 csum_size, int retry_failed_mirror);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
236
237
238
239
240
  static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
  					 struct scrub_block *sblock,
  					 int is_metadata, int have_csum,
  					 const u8 *csum, u64 generation,
  					 u16 csum_size);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
241
242
243
244
245
246
  static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
  					     struct scrub_block *sblock_good,
  					     int force_write);
  static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
  					    struct scrub_block *sblock_good,
  					    int page_num, int force_write);
ff023aac3   Stefan Behrens   Btrfs: add code t...
247
248
249
  static void scrub_write_block_to_dev_replace(struct scrub_block *sblock);
  static int scrub_write_page_to_dev_replace(struct scrub_block *sblock,
  					   int page_num);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
250
251
252
253
254
  static int scrub_checksum_data(struct scrub_block *sblock);
  static int scrub_checksum_tree_block(struct scrub_block *sblock);
  static int scrub_checksum_super(struct scrub_block *sblock);
  static void scrub_block_get(struct scrub_block *sblock);
  static void scrub_block_put(struct scrub_block *sblock);
7a9e99876   Stefan Behrens   Btrfs: make the s...
255
256
  static void scrub_page_get(struct scrub_page *spage);
  static void scrub_page_put(struct scrub_page *spage);
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
257
258
  static void scrub_parity_get(struct scrub_parity *sparity);
  static void scrub_parity_put(struct scrub_parity *sparity);
ff023aac3   Stefan Behrens   Btrfs: add code t...
259
260
  static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx,
  				    struct scrub_page *spage);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
261
  static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
262
  		       u64 physical, struct btrfs_device *dev, u64 flags,
ff023aac3   Stefan Behrens   Btrfs: add code t...
263
264
  		       u64 gen, int mirror_num, u8 *csum, int force,
  		       u64 physical_for_dev_replace);
1623edebe   Stefan Behrens   Btrfs: minor clea...
265
  static void scrub_bio_end_io(struct bio *bio, int err);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
266
267
  static void scrub_bio_end_io_worker(struct btrfs_work *work);
  static void scrub_block_complete(struct scrub_block *sblock);
ff023aac3   Stefan Behrens   Btrfs: add code t...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  static void scrub_remap_extent(struct btrfs_fs_info *fs_info,
  			       u64 extent_logical, u64 extent_len,
  			       u64 *extent_physical,
  			       struct btrfs_device **extent_dev,
  			       int *extent_mirror_num);
  static int scrub_setup_wr_ctx(struct scrub_ctx *sctx,
  			      struct scrub_wr_ctx *wr_ctx,
  			      struct btrfs_fs_info *fs_info,
  			      struct btrfs_device *dev,
  			      int is_dev_replace);
  static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx);
  static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
  				    struct scrub_page *spage);
  static void scrub_wr_submit(struct scrub_ctx *sctx);
  static void scrub_wr_bio_end_io(struct bio *bio, int err);
  static void scrub_wr_bio_end_io_worker(struct btrfs_work *work);
  static int write_page_nocow(struct scrub_ctx *sctx,
  			    u64 physical_for_dev_replace, struct page *page);
  static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
652f25a29   Josef Bacik   Btrfs: improve re...
287
  				      struct scrub_copy_nocow_ctx *ctx);
ff023aac3   Stefan Behrens   Btrfs: add code t...
288
289
290
  static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
  			    int mirror_num, u64 physical_for_dev_replace);
  static void copy_nocow_pages_worker(struct btrfs_work *work);
cb7ab0215   Wang Shilong   Btrfs: wrap repea...
291
  static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info);
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
292
  static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info);
1623edebe   Stefan Behrens   Btrfs: minor clea...
293

b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
294
295
296
297
298
299
300
301
302
303
  static void scrub_pending_bio_inc(struct scrub_ctx *sctx)
  {
  	atomic_inc(&sctx->bios_in_flight);
  }
  
  static void scrub_pending_bio_dec(struct scrub_ctx *sctx)
  {
  	atomic_dec(&sctx->bios_in_flight);
  	wake_up(&sctx->list_wait);
  }
cb7ab0215   Wang Shilong   Btrfs: wrap repea...
304
  static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
305
306
307
308
309
310
311
312
  {
  	while (atomic_read(&fs_info->scrub_pause_req)) {
  		mutex_unlock(&fs_info->scrub_lock);
  		wait_event(fs_info->scrub_pause_wait,
  		   atomic_read(&fs_info->scrub_pause_req) == 0);
  		mutex_lock(&fs_info->scrub_lock);
  	}
  }
cb7ab0215   Wang Shilong   Btrfs: wrap repea...
313
314
315
316
317
318
319
320
321
322
323
324
  static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
  {
  	atomic_inc(&fs_info->scrubs_paused);
  	wake_up(&fs_info->scrub_pause_wait);
  
  	mutex_lock(&fs_info->scrub_lock);
  	__scrub_blocked_if_needed(fs_info);
  	atomic_dec(&fs_info->scrubs_paused);
  	mutex_unlock(&fs_info->scrub_lock);
  
  	wake_up(&fs_info->scrub_pause_wait);
  }
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
  /*
   * used for workers that require transaction commits (i.e., for the
   * NOCOW case)
   */
  static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx)
  {
  	struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
  
  	/*
  	 * increment scrubs_running to prevent cancel requests from
  	 * completing as long as a worker is running. we must also
  	 * increment scrubs_paused to prevent deadlocking on pause
  	 * requests used for transactions commits (as the worker uses a
  	 * transaction context). it is safe to regard the worker
  	 * as paused for all matters practical. effectively, we only
  	 * avoid cancellation requests from completing.
  	 */
  	mutex_lock(&fs_info->scrub_lock);
  	atomic_inc(&fs_info->scrubs_running);
  	atomic_inc(&fs_info->scrubs_paused);
  	mutex_unlock(&fs_info->scrub_lock);
32a447896   Wang Shilong   Btrfs: wake up @s...
346
347
348
349
350
351
352
353
354
  
  	/*
  	 * check if @scrubs_running=@scrubs_paused condition
  	 * inside wait_event() is not an atomic operation.
  	 * which means we may inc/dec @scrub_running/paused
  	 * at any time. Let's wake up @scrub_pause_wait as
  	 * much as we can to let commit transaction blocked less.
  	 */
  	wake_up(&fs_info->scrub_pause_wait);
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
  	atomic_inc(&sctx->workers_pending);
  }
  
  /* used for workers that require transaction commits */
  static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx)
  {
  	struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
  
  	/*
  	 * see scrub_pending_trans_workers_inc() why we're pretending
  	 * to be paused in the scrub counters
  	 */
  	mutex_lock(&fs_info->scrub_lock);
  	atomic_dec(&fs_info->scrubs_running);
  	atomic_dec(&fs_info->scrubs_paused);
  	mutex_unlock(&fs_info->scrub_lock);
  	atomic_dec(&sctx->workers_pending);
  	wake_up(&fs_info->scrub_pause_wait);
  	wake_up(&sctx->list_wait);
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
375
  static void scrub_free_csums(struct scrub_ctx *sctx)
a2de733c7   Arne Jansen   btrfs: scrub
376
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
377
  	while (!list_empty(&sctx->csum_list)) {
a2de733c7   Arne Jansen   btrfs: scrub
378
  		struct btrfs_ordered_sum *sum;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
379
  		sum = list_first_entry(&sctx->csum_list,
a2de733c7   Arne Jansen   btrfs: scrub
380
381
382
383
384
  				       struct btrfs_ordered_sum, list);
  		list_del(&sum->list);
  		kfree(sum);
  	}
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
385
  static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx)
a2de733c7   Arne Jansen   btrfs: scrub
386
387
  {
  	int i;
a2de733c7   Arne Jansen   btrfs: scrub
388

d9d181c1b   Stefan Behrens   Btrfs: rename the...
389
  	if (!sctx)
a2de733c7   Arne Jansen   btrfs: scrub
390
  		return;
ff023aac3   Stefan Behrens   Btrfs: add code t...
391
  	scrub_free_wr_ctx(&sctx->wr_ctx);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
392
  	/* this can happen when scrub is cancelled */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
393
394
  	if (sctx->curr != -1) {
  		struct scrub_bio *sbio = sctx->bios[sctx->curr];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
395
396
  
  		for (i = 0; i < sbio->page_count; i++) {
ff023aac3   Stefan Behrens   Btrfs: add code t...
397
  			WARN_ON(!sbio->pagev[i]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
398
399
400
401
  			scrub_block_put(sbio->pagev[i]->sblock);
  		}
  		bio_put(sbio->bio);
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
402
  	for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
403
  		struct scrub_bio *sbio = sctx->bios[i];
a2de733c7   Arne Jansen   btrfs: scrub
404
405
406
  
  		if (!sbio)
  			break;
a2de733c7   Arne Jansen   btrfs: scrub
407
408
  		kfree(sbio);
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
409
410
  	scrub_free_csums(sctx);
  	kfree(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
411
412
413
  }
  
  static noinline_for_stack
63a212abc   Stefan Behrens   Btrfs: disallow s...
414
  struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
415
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
416
  	struct scrub_ctx *sctx;
a2de733c7   Arne Jansen   btrfs: scrub
417
  	int		i;
a2de733c7   Arne Jansen   btrfs: scrub
418
  	struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
ff023aac3   Stefan Behrens   Btrfs: add code t...
419
420
  	int pages_per_rd_bio;
  	int ret;
a2de733c7   Arne Jansen   btrfs: scrub
421

ff023aac3   Stefan Behrens   Btrfs: add code t...
422
423
424
425
426
427
428
429
430
431
432
433
  	/*
  	 * the setting of pages_per_rd_bio is correct for scrub but might
  	 * be wrong for the dev_replace code where we might read from
  	 * different devices in the initial huge bios. However, that
  	 * code is able to correctly handle the case when adding a page
  	 * to a bio fails.
  	 */
  	if (dev->bdev)
  		pages_per_rd_bio = min_t(int, SCRUB_PAGES_PER_RD_BIO,
  					 bio_get_nr_vecs(dev->bdev));
  	else
  		pages_per_rd_bio = SCRUB_PAGES_PER_RD_BIO;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
434
435
  	sctx = kzalloc(sizeof(*sctx), GFP_NOFS);
  	if (!sctx)
a2de733c7   Arne Jansen   btrfs: scrub
436
  		goto nomem;
63a212abc   Stefan Behrens   Btrfs: disallow s...
437
  	sctx->is_dev_replace = is_dev_replace;
ff023aac3   Stefan Behrens   Btrfs: add code t...
438
  	sctx->pages_per_rd_bio = pages_per_rd_bio;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
439
  	sctx->curr = -1;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
440
  	sctx->dev_root = dev->dev_root;
ff023aac3   Stefan Behrens   Btrfs: add code t...
441
  	for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) {
a2de733c7   Arne Jansen   btrfs: scrub
442
443
444
445
446
  		struct scrub_bio *sbio;
  
  		sbio = kzalloc(sizeof(*sbio), GFP_NOFS);
  		if (!sbio)
  			goto nomem;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
447
  		sctx->bios[i] = sbio;
a2de733c7   Arne Jansen   btrfs: scrub
448

a2de733c7   Arne Jansen   btrfs: scrub
449
  		sbio->index = i;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
450
  		sbio->sctx = sctx;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
451
  		sbio->page_count = 0;
9e0af2376   Liu Bo   Btrfs: fix task h...
452
453
  		btrfs_init_work(&sbio->work, btrfs_scrub_helper,
  				scrub_bio_end_io_worker, NULL, NULL);
a2de733c7   Arne Jansen   btrfs: scrub
454

ff023aac3   Stefan Behrens   Btrfs: add code t...
455
  		if (i != SCRUB_BIOS_PER_SCTX - 1)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
456
  			sctx->bios[i]->next_free = i + 1;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
457
  		else
d9d181c1b   Stefan Behrens   Btrfs: rename the...
458
459
460
461
  			sctx->bios[i]->next_free = -1;
  	}
  	sctx->first_free = 0;
  	sctx->nodesize = dev->dev_root->nodesize;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
462
  	sctx->sectorsize = dev->dev_root->sectorsize;
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
463
464
  	atomic_set(&sctx->bios_in_flight, 0);
  	atomic_set(&sctx->workers_pending, 0);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
465
466
467
468
469
470
471
  	atomic_set(&sctx->cancel_req, 0);
  	sctx->csum_size = btrfs_super_csum_size(fs_info->super_copy);
  	INIT_LIST_HEAD(&sctx->csum_list);
  
  	spin_lock_init(&sctx->list_lock);
  	spin_lock_init(&sctx->stat_lock);
  	init_waitqueue_head(&sctx->list_wait);
ff023aac3   Stefan Behrens   Btrfs: add code t...
472
473
474
475
476
477
478
  
  	ret = scrub_setup_wr_ctx(sctx, &sctx->wr_ctx, fs_info,
  				 fs_info->dev_replace.tgtdev, is_dev_replace);
  	if (ret) {
  		scrub_free_ctx(sctx);
  		return ERR_PTR(ret);
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
479
  	return sctx;
a2de733c7   Arne Jansen   btrfs: scrub
480
481
  
  nomem:
d9d181c1b   Stefan Behrens   Btrfs: rename the...
482
  	scrub_free_ctx(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
483
484
  	return ERR_PTR(-ENOMEM);
  }
ff023aac3   Stefan Behrens   Btrfs: add code t...
485
486
  static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
  				     void *warn_ctx)
558540c17   Jan Schmidt   btrfs scrub: prin...
487
488
489
490
491
492
493
  {
  	u64 isize;
  	u32 nlink;
  	int ret;
  	int i;
  	struct extent_buffer *eb;
  	struct btrfs_inode_item *inode_item;
ff023aac3   Stefan Behrens   Btrfs: add code t...
494
  	struct scrub_warning *swarn = warn_ctx;
558540c17   Jan Schmidt   btrfs scrub: prin...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  	struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info;
  	struct inode_fs_paths *ipath = NULL;
  	struct btrfs_root *local_root;
  	struct btrfs_key root_key;
  
  	root_key.objectid = root;
  	root_key.type = BTRFS_ROOT_ITEM_KEY;
  	root_key.offset = (u64)-1;
  	local_root = btrfs_read_fs_root_no_name(fs_info, &root_key);
  	if (IS_ERR(local_root)) {
  		ret = PTR_ERR(local_root);
  		goto err;
  	}
  
  	ret = inode_item_info(inum, 0, local_root, swarn->path);
  	if (ret) {
  		btrfs_release_path(swarn->path);
  		goto err;
  	}
  
  	eb = swarn->path->nodes[0];
  	inode_item = btrfs_item_ptr(eb, swarn->path->slots[0],
  					struct btrfs_inode_item);
  	isize = btrfs_inode_size(eb, inode_item);
  	nlink = btrfs_inode_nlink(eb, inode_item);
  	btrfs_release_path(swarn->path);
  
  	ipath = init_ipath(4096, local_root, swarn->path);
26bdef541   Dan Carpenter   btrfs scrub: hand...
523
524
525
526
527
  	if (IS_ERR(ipath)) {
  		ret = PTR_ERR(ipath);
  		ipath = NULL;
  		goto err;
  	}
558540c17   Jan Schmidt   btrfs scrub: prin...
528
529
530
531
532
533
534
535
536
537
  	ret = paths_from_inode(inum, ipath);
  
  	if (ret < 0)
  		goto err;
  
  	/*
  	 * we deliberately ignore the bit ipath might have been too small to
  	 * hold all of the paths here
  	 */
  	for (i = 0; i < ipath->fspath->elem_cnt; ++i)
efe120a06   Frank Holton   Btrfs: convert pr...
538
  		printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
558540c17   Jan Schmidt   btrfs scrub: prin...
539
540
541
  			"%s, sector %llu, root %llu, inode %llu, offset %llu, "
  			"length %llu, links %u (path: %s)
  ", swarn->errstr,
606686eea   Josef Bacik   Btrfs: use rcu to...
542
  			swarn->logical, rcu_str_deref(swarn->dev->name),
558540c17   Jan Schmidt   btrfs scrub: prin...
543
544
  			(unsigned long long)swarn->sector, root, inum, offset,
  			min(isize - offset, (u64)PAGE_SIZE), nlink,
745c4d8e1   Jeff Mahoney   btrfs: Fix up 32/...
545
  			(char *)(unsigned long)ipath->fspath->val[i]);
558540c17   Jan Schmidt   btrfs scrub: prin...
546
547
548
549
550
  
  	free_ipath(ipath);
  	return 0;
  
  err:
efe120a06   Frank Holton   Btrfs: convert pr...
551
  	printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
558540c17   Jan Schmidt   btrfs scrub: prin...
552
553
554
  		"%s, sector %llu, root %llu, inode %llu, offset %llu: path "
  		"resolving failed with ret=%d
  ", swarn->errstr,
606686eea   Josef Bacik   Btrfs: use rcu to...
555
  		swarn->logical, rcu_str_deref(swarn->dev->name),
558540c17   Jan Schmidt   btrfs scrub: prin...
556
557
558
559
560
  		(unsigned long long)swarn->sector, root, inum, offset, ret);
  
  	free_ipath(ipath);
  	return 0;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
561
  static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
558540c17   Jan Schmidt   btrfs scrub: prin...
562
  {
a36cf8b89   Stefan Behrens   Btrfs: remove the...
563
564
  	struct btrfs_device *dev;
  	struct btrfs_fs_info *fs_info;
558540c17   Jan Schmidt   btrfs scrub: prin...
565
566
567
568
569
  	struct btrfs_path *path;
  	struct btrfs_key found_key;
  	struct extent_buffer *eb;
  	struct btrfs_extent_item *ei;
  	struct scrub_warning swarn;
69917e431   Liu Bo   Btrfs: fix a bug ...
570
571
572
  	unsigned long ptr = 0;
  	u64 extent_item_pos;
  	u64 flags = 0;
558540c17   Jan Schmidt   btrfs scrub: prin...
573
  	u64 ref_root;
69917e431   Liu Bo   Btrfs: fix a bug ...
574
  	u32 item_size;
558540c17   Jan Schmidt   btrfs scrub: prin...
575
  	u8 ref_level;
69917e431   Liu Bo   Btrfs: fix a bug ...
576
  	int ret;
558540c17   Jan Schmidt   btrfs scrub: prin...
577

a36cf8b89   Stefan Behrens   Btrfs: remove the...
578
  	WARN_ON(sblock->page_count < 1);
7a9e99876   Stefan Behrens   Btrfs: make the s...
579
  	dev = sblock->pagev[0]->dev;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
580
  	fs_info = sblock->sctx->dev_root->fs_info;
558540c17   Jan Schmidt   btrfs scrub: prin...
581
  	path = btrfs_alloc_path();
8b9456da0   David Sterba   btrfs: remove unu...
582
583
  	if (!path)
  		return;
558540c17   Jan Schmidt   btrfs scrub: prin...
584

7a9e99876   Stefan Behrens   Btrfs: make the s...
585
586
  	swarn.sector = (sblock->pagev[0]->physical) >> 9;
  	swarn.logical = sblock->pagev[0]->logical;
558540c17   Jan Schmidt   btrfs scrub: prin...
587
  	swarn.errstr = errstr;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
588
  	swarn.dev = NULL;
558540c17   Jan Schmidt   btrfs scrub: prin...
589

69917e431   Liu Bo   Btrfs: fix a bug ...
590
591
  	ret = extent_from_logical(fs_info, swarn.logical, path, &found_key,
  				  &flags);
558540c17   Jan Schmidt   btrfs scrub: prin...
592
593
  	if (ret < 0)
  		goto out;
4692cf58a   Jan Schmidt   Btrfs: new backre...
594
  	extent_item_pos = swarn.logical - found_key.objectid;
558540c17   Jan Schmidt   btrfs scrub: prin...
595
596
597
598
599
  	swarn.extent_item_size = found_key.offset;
  
  	eb = path->nodes[0];
  	ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
  	item_size = btrfs_item_size_nr(eb, path->slots[0]);
69917e431   Liu Bo   Btrfs: fix a bug ...
600
  	if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
558540c17   Jan Schmidt   btrfs scrub: prin...
601
  		do {
6eda71d0c   Liu Bo   Btrfs: fix scrub_...
602
603
604
  			ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
  						      item_size, &ref_root,
  						      &ref_level);
606686eea   Josef Bacik   Btrfs: use rcu to...
605
  			printk_in_rcu(KERN_WARNING
efe120a06   Frank Holton   Btrfs: convert pr...
606
  				"BTRFS: %s at logical %llu on dev %s, "
558540c17   Jan Schmidt   btrfs scrub: prin...
607
  				"sector %llu: metadata %s (level %d) in tree "
606686eea   Josef Bacik   Btrfs: use rcu to...
608
609
610
  				"%llu
  ", errstr, swarn.logical,
  				rcu_str_deref(dev->name),
558540c17   Jan Schmidt   btrfs scrub: prin...
611
612
613
614
615
  				(unsigned long long)swarn.sector,
  				ref_level ? "node" : "leaf",
  				ret < 0 ? -1 : ref_level,
  				ret < 0 ? -1 : ref_root);
  		} while (ret != 1);
d8fe29e9d   Josef Bacik   Btrfs: don't drop...
616
  		btrfs_release_path(path);
558540c17   Jan Schmidt   btrfs scrub: prin...
617
  	} else {
d8fe29e9d   Josef Bacik   Btrfs: don't drop...
618
  		btrfs_release_path(path);
558540c17   Jan Schmidt   btrfs scrub: prin...
619
  		swarn.path = path;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
620
  		swarn.dev = dev;
7a3ae2f8c   Jan Schmidt   Btrfs: fix regres...
621
622
  		iterate_extent_inodes(fs_info, found_key.objectid,
  					extent_item_pos, 1,
558540c17   Jan Schmidt   btrfs scrub: prin...
623
624
625
626
627
  					scrub_print_warning_inode, &swarn);
  	}
  
  out:
  	btrfs_free_path(path);
558540c17   Jan Schmidt   btrfs scrub: prin...
628
  }
ff023aac3   Stefan Behrens   Btrfs: add code t...
629
  static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx)
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
630
  {
5da6fcbc4   Jan Schmidt   btrfs: integratin...
631
  	struct page *page = NULL;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
632
  	unsigned long index;
ff023aac3   Stefan Behrens   Btrfs: add code t...
633
  	struct scrub_fixup_nodatasum *fixup = fixup_ctx;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
634
  	int ret;
5da6fcbc4   Jan Schmidt   btrfs: integratin...
635
  	int corrected = 0;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
636
  	struct btrfs_key key;
5da6fcbc4   Jan Schmidt   btrfs: integratin...
637
  	struct inode *inode = NULL;
6f1c36055   Liu Bo   Btrfs: fix race b...
638
  	struct btrfs_fs_info *fs_info;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
639
640
  	u64 end = offset + PAGE_SIZE - 1;
  	struct btrfs_root *local_root;
6f1c36055   Liu Bo   Btrfs: fix race b...
641
  	int srcu_index;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
642
643
644
645
  
  	key.objectid = root;
  	key.type = BTRFS_ROOT_ITEM_KEY;
  	key.offset = (u64)-1;
6f1c36055   Liu Bo   Btrfs: fix race b...
646
647
648
649
650
651
652
  
  	fs_info = fixup->root->fs_info;
  	srcu_index = srcu_read_lock(&fs_info->subvol_srcu);
  
  	local_root = btrfs_read_fs_root_no_name(fs_info, &key);
  	if (IS_ERR(local_root)) {
  		srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
653
  		return PTR_ERR(local_root);
6f1c36055   Liu Bo   Btrfs: fix race b...
654
  	}
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
655
656
657
658
  
  	key.type = BTRFS_INODE_ITEM_KEY;
  	key.objectid = inum;
  	key.offset = 0;
6f1c36055   Liu Bo   Btrfs: fix race b...
659
660
  	inode = btrfs_iget(fs_info->sb, &key, local_root, NULL);
  	srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
661
662
  	if (IS_ERR(inode))
  		return PTR_ERR(inode);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
663
664
665
  	index = offset >> PAGE_CACHE_SHIFT;
  
  	page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
5da6fcbc4   Jan Schmidt   btrfs: integratin...
666
667
668
669
670
671
  	if (!page) {
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	if (PageUptodate(page)) {
5da6fcbc4   Jan Schmidt   btrfs: integratin...
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  		if (PageDirty(page)) {
  			/*
  			 * we need to write the data to the defect sector. the
  			 * data that was in that sector is not in memory,
  			 * because the page was modified. we must not write the
  			 * modified page to that sector.
  			 *
  			 * TODO: what could be done here: wait for the delalloc
  			 *       runner to write out that page (might involve
  			 *       COW) and see whether the sector is still
  			 *       referenced afterwards.
  			 *
  			 * For the meantime, we'll treat this error
  			 * incorrectable, although there is a chance that a
  			 * later scrub will find the bad sector again and that
  			 * there's no dirty page in memory, then.
  			 */
  			ret = -EIO;
  			goto out;
  		}
1203b6813   Miao Xie   Btrfs: modify cle...
692
  		ret = repair_io_failure(inode, offset, PAGE_SIZE,
5da6fcbc4   Jan Schmidt   btrfs: integratin...
693
  					fixup->logical, page,
ffdd2018d   Miao Xie   Btrfs: modify rep...
694
  					offset - page_offset(page),
5da6fcbc4   Jan Schmidt   btrfs: integratin...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
  					fixup->mirror_num);
  		unlock_page(page);
  		corrected = !ret;
  	} else {
  		/*
  		 * we need to get good data first. the general readpage path
  		 * will call repair_io_failure for us, we just have to make
  		 * sure we read the bad mirror.
  		 */
  		ret = set_extent_bits(&BTRFS_I(inode)->io_tree, offset, end,
  					EXTENT_DAMAGED, GFP_NOFS);
  		if (ret) {
  			/* set_extent_bits should give proper error */
  			WARN_ON(ret > 0);
  			if (ret > 0)
  				ret = -EFAULT;
  			goto out;
  		}
  
  		ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page,
  						btrfs_get_extent,
  						fixup->mirror_num);
  		wait_on_page_locked(page);
  
  		corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset,
  						end, EXTENT_DAMAGED, 0, NULL);
  		if (!corrected)
  			clear_extent_bits(&BTRFS_I(inode)->io_tree, offset, end,
  						EXTENT_DAMAGED, GFP_NOFS);
  	}
  
  out:
  	if (page)
  		put_page(page);
7fb18a066   Tobias Klauser   btrfs: Remove unn...
729
730
  
  	iput(inode);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
  
  	if (ret < 0)
  		return ret;
  
  	if (ret == 0 && corrected) {
  		/*
  		 * we only need to call readpage for one of the inodes belonging
  		 * to this extent. so make iterate_extent_inodes stop
  		 */
  		return 1;
  	}
  
  	return -EIO;
  }
  
  static void scrub_fixup_nodatasum(struct btrfs_work *work)
  {
  	int ret;
  	struct scrub_fixup_nodatasum *fixup;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
750
  	struct scrub_ctx *sctx;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
751
  	struct btrfs_trans_handle *trans = NULL;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
752
753
754
755
  	struct btrfs_path *path;
  	int uncorrectable = 0;
  
  	fixup = container_of(work, struct scrub_fixup_nodatasum, work);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
756
  	sctx = fixup->sctx;
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
757
758
759
  
  	path = btrfs_alloc_path();
  	if (!path) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
760
761
762
  		spin_lock(&sctx->stat_lock);
  		++sctx->stat.malloc_errors;
  		spin_unlock(&sctx->stat_lock);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
  		uncorrectable = 1;
  		goto out;
  	}
  
  	trans = btrfs_join_transaction(fixup->root);
  	if (IS_ERR(trans)) {
  		uncorrectable = 1;
  		goto out;
  	}
  
  	/*
  	 * the idea is to trigger a regular read through the standard path. we
  	 * read a page from the (failed) logical address by specifying the
  	 * corresponding copynum of the failed sector. thus, that readpage is
  	 * expected to fail.
  	 * that is the point where on-the-fly error correction will kick in
  	 * (once it's finished) and rewrite the failed sector if a good copy
  	 * can be found.
  	 */
  	ret = iterate_inodes_from_logical(fixup->logical, fixup->root->fs_info,
  						path, scrub_fixup_readpage,
  						fixup);
  	if (ret < 0) {
  		uncorrectable = 1;
  		goto out;
  	}
  	WARN_ON(ret != 1);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
790
791
792
  	spin_lock(&sctx->stat_lock);
  	++sctx->stat.corrected_errors;
  	spin_unlock(&sctx->stat_lock);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
793
794
795
796
797
  
  out:
  	if (trans && !IS_ERR(trans))
  		btrfs_end_transaction(trans, fixup->root);
  	if (uncorrectable) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
798
799
800
  		spin_lock(&sctx->stat_lock);
  		++sctx->stat.uncorrectable_errors;
  		spin_unlock(&sctx->stat_lock);
ff023aac3   Stefan Behrens   Btrfs: add code t...
801
802
803
  		btrfs_dev_replace_stats_inc(
  			&sctx->dev_root->fs_info->dev_replace.
  			num_uncorrectable_read_errors);
efe120a06   Frank Holton   Btrfs: convert pr...
804
805
806
  		printk_ratelimited_in_rcu(KERN_ERR "BTRFS: "
  		    "unable to fixup (nodatasum) error at logical %llu on dev %s
  ",
c1c9ff7c9   Geert Uytterhoeven   Btrfs: Remove sup...
807
  			fixup->logical, rcu_str_deref(fixup->dev->name));
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
808
809
810
811
  	}
  
  	btrfs_free_path(path);
  	kfree(fixup);
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
812
  	scrub_pending_trans_workers_dec(sctx);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
813
  }
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
814
815
816
817
818
819
820
821
822
823
824
825
826
  static inline void scrub_get_recover(struct scrub_recover *recover)
  {
  	atomic_inc(&recover->refs);
  }
  
  static inline void scrub_put_recover(struct scrub_recover *recover)
  {
  	if (atomic_dec_and_test(&recover->refs)) {
  		kfree(recover->bbio);
  		kfree(recover->raid_map);
  		kfree(recover);
  	}
  }
a2de733c7   Arne Jansen   btrfs: scrub
827
  /*
b5d67f64f   Stefan Behrens   Btrfs: change scr...
828
829
830
831
832
833
   * scrub_handle_errored_block gets called when either verification of the
   * pages failed or the bio failed to read, e.g. with EIO. In the latter
   * case, this function handles all pages in the bio, even though only one
   * may be bad.
   * The goal of this function is to repair the errored block by using the
   * contents of one of the mirrors.
a2de733c7   Arne Jansen   btrfs: scrub
834
   */
b5d67f64f   Stefan Behrens   Btrfs: change scr...
835
  static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
a2de733c7   Arne Jansen   btrfs: scrub
836
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
837
  	struct scrub_ctx *sctx = sblock_to_check->sctx;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
838
  	struct btrfs_device *dev;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
  	struct btrfs_fs_info *fs_info;
  	u64 length;
  	u64 logical;
  	u64 generation;
  	unsigned int failed_mirror_index;
  	unsigned int is_metadata;
  	unsigned int have_csum;
  	u8 *csum;
  	struct scrub_block *sblocks_for_recheck; /* holds one for each mirror */
  	struct scrub_block *sblock_bad;
  	int ret;
  	int mirror_index;
  	int page_num;
  	int success;
558540c17   Jan Schmidt   btrfs scrub: prin...
853
  	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
b5d67f64f   Stefan Behrens   Btrfs: change scr...
854
855
856
  				      DEFAULT_RATELIMIT_BURST);
  
  	BUG_ON(sblock_to_check->page_count < 1);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
857
  	fs_info = sctx->dev_root->fs_info;
4ded4f639   Stefan Behrens   Btrfs: fix BUG() ...
858
859
860
861
862
863
864
865
866
867
868
  	if (sblock_to_check->pagev[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
  		/*
  		 * if we find an error in a super block, we just report it.
  		 * They will get written with the next transaction commit
  		 * anyway
  		 */
  		spin_lock(&sctx->stat_lock);
  		++sctx->stat.super_errors;
  		spin_unlock(&sctx->stat_lock);
  		return 0;
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
869
  	length = sblock_to_check->page_count * PAGE_SIZE;
7a9e99876   Stefan Behrens   Btrfs: make the s...
870
871
872
873
874
  	logical = sblock_to_check->pagev[0]->logical;
  	generation = sblock_to_check->pagev[0]->generation;
  	BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1);
  	failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1;
  	is_metadata = !(sblock_to_check->pagev[0]->flags &
b5d67f64f   Stefan Behrens   Btrfs: change scr...
875
  			BTRFS_EXTENT_FLAG_DATA);
7a9e99876   Stefan Behrens   Btrfs: make the s...
876
877
878
  	have_csum = sblock_to_check->pagev[0]->have_csum;
  	csum = sblock_to_check->pagev[0]->csum;
  	dev = sblock_to_check->pagev[0]->dev;
13db62b7a   Jan Schmidt   btrfs scrub: adde...
879

ff023aac3   Stefan Behrens   Btrfs: add code t...
880
881
882
883
  	if (sctx->is_dev_replace && !is_metadata && !have_csum) {
  		sblocks_for_recheck = NULL;
  		goto nodatasum_case;
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  	/*
  	 * read all mirrors one after the other. This includes to
  	 * re-read the extent or metadata block that failed (that was
  	 * the cause that this fixup code is called) another time,
  	 * page by page this time in order to know which pages
  	 * caused I/O errors and which ones are good (for all mirrors).
  	 * It is the goal to handle the situation when more than one
  	 * mirror contains I/O errors, but the errors do not
  	 * overlap, i.e. the data can be repaired by selecting the
  	 * pages from those mirrors without I/O error on the
  	 * particular pages. One example (with blocks >= 2 * PAGE_SIZE)
  	 * would be that mirror #1 has an I/O error on the first page,
  	 * the second page is good, and mirror #2 has an I/O error on
  	 * the second page, but the first page is good.
  	 * Then the first page of the first mirror can be repaired by
  	 * taking the first page of the second mirror, and the
  	 * second page of the second mirror can be repaired by
  	 * copying the contents of the 2nd page of the 1st mirror.
  	 * One more note: if the pages of one mirror contain I/O
  	 * errors, the checksum cannot be verified. In order to get
  	 * the best data for repairing, the first attempt is to find
  	 * a mirror without I/O errors and with a validated checksum.
  	 * Only if this is not possible, the pages are picked from
  	 * mirrors with I/O errors without considering the checksum.
  	 * If the latter is the case, at the end, the checksum of the
  	 * repaired area is verified in order to correctly maintain
  	 * the statistics.
  	 */
  
  	sblocks_for_recheck = kzalloc(BTRFS_MAX_MIRRORS *
  				     sizeof(*sblocks_for_recheck),
  				     GFP_NOFS);
  	if (!sblocks_for_recheck) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
917
918
919
920
921
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		sctx->stat.read_errors++;
  		sctx->stat.uncorrectable_errors++;
  		spin_unlock(&sctx->stat_lock);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
922
  		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
923
  		goto out;
a2de733c7   Arne Jansen   btrfs: scrub
924
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
925
  	/* setup the context, map the logical blocks and alloc the pages */
ff023aac3   Stefan Behrens   Btrfs: add code t...
926
  	ret = scrub_setup_recheck_block(sctx, fs_info, sblock_to_check, length,
b5d67f64f   Stefan Behrens   Btrfs: change scr...
927
928
  					logical, sblocks_for_recheck);
  	if (ret) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
929
930
931
932
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.read_errors++;
  		sctx->stat.uncorrectable_errors++;
  		spin_unlock(&sctx->stat_lock);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
933
  		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
934
935
936
937
  		goto out;
  	}
  	BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS);
  	sblock_bad = sblocks_for_recheck + failed_mirror_index;
13db62b7a   Jan Schmidt   btrfs scrub: adde...
938

b5d67f64f   Stefan Behrens   Btrfs: change scr...
939
  	/* build and submit the bios for the failed mirror, check checksums */
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
940
  	scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum,
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
941
  			    csum, generation, sctx->csum_size, 1);
a2de733c7   Arne Jansen   btrfs: scrub
942

b5d67f64f   Stefan Behrens   Btrfs: change scr...
943
944
945
946
947
948
949
950
951
952
  	if (!sblock_bad->header_error && !sblock_bad->checksum_error &&
  	    sblock_bad->no_io_error_seen) {
  		/*
  		 * the error disappeared after reading page by page, or
  		 * the area was part of a huge bio and other parts of the
  		 * bio caused I/O errors, or the block layer merged several
  		 * read requests into one and the error is caused by a
  		 * different bio (usually one of the two latter cases is
  		 * the cause)
  		 */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
953
954
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.unverified_errors++;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
955
  		sblock_to_check->data_corrected = 1;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
956
  		spin_unlock(&sctx->stat_lock);
a2de733c7   Arne Jansen   btrfs: scrub
957

ff023aac3   Stefan Behrens   Btrfs: add code t...
958
959
  		if (sctx->is_dev_replace)
  			scrub_write_block_to_dev_replace(sblock_bad);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
960
  		goto out;
a2de733c7   Arne Jansen   btrfs: scrub
961
  	}
a2de733c7   Arne Jansen   btrfs: scrub
962

b5d67f64f   Stefan Behrens   Btrfs: change scr...
963
  	if (!sblock_bad->no_io_error_seen) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
964
965
966
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.read_errors++;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
967
968
  		if (__ratelimit(&_rs))
  			scrub_print_warning("i/o error", sblock_to_check);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
969
  		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
970
  	} else if (sblock_bad->checksum_error) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
971
972
973
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.csum_errors++;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
974
975
  		if (__ratelimit(&_rs))
  			scrub_print_warning("checksum error", sblock_to_check);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
976
  		btrfs_dev_stat_inc_and_print(dev,
442a4f630   Stefan Behrens   Btrfs: add device...
977
  					     BTRFS_DEV_STAT_CORRUPTION_ERRS);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
978
  	} else if (sblock_bad->header_error) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
979
980
981
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.verify_errors++;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
982
983
984
  		if (__ratelimit(&_rs))
  			scrub_print_warning("checksum/header error",
  					    sblock_to_check);
442a4f630   Stefan Behrens   Btrfs: add device...
985
  		if (sblock_bad->generation_error)
a36cf8b89   Stefan Behrens   Btrfs: remove the...
986
  			btrfs_dev_stat_inc_and_print(dev,
442a4f630   Stefan Behrens   Btrfs: add device...
987
988
  				BTRFS_DEV_STAT_GENERATION_ERRS);
  		else
a36cf8b89   Stefan Behrens   Btrfs: remove the...
989
  			btrfs_dev_stat_inc_and_print(dev,
442a4f630   Stefan Behrens   Btrfs: add device...
990
  				BTRFS_DEV_STAT_CORRUPTION_ERRS);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
991
  	}
a2de733c7   Arne Jansen   btrfs: scrub
992

33ef30add   Ilya Dryomov   Btrfs: do not inc...
993
994
995
996
  	if (sctx->readonly) {
  		ASSERT(!sctx->is_dev_replace);
  		goto out;
  	}
a2de733c7   Arne Jansen   btrfs: scrub
997

b5d67f64f   Stefan Behrens   Btrfs: change scr...
998
999
  	if (!is_metadata && !have_csum) {
  		struct scrub_fixup_nodatasum *fixup_nodatasum;
a2de733c7   Arne Jansen   btrfs: scrub
1000

ff023aac3   Stefan Behrens   Btrfs: add code t...
1001
1002
  nodatasum_case:
  		WARN_ON(sctx->is_dev_replace);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  		/*
  		 * !is_metadata and !have_csum, this means that the data
  		 * might not be COW'ed, that it might be modified
  		 * concurrently. The general strategy to work on the
  		 * commit root does not help in the case when COW is not
  		 * used.
  		 */
  		fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS);
  		if (!fixup_nodatasum)
  			goto did_not_correct_error;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1013
  		fixup_nodatasum->sctx = sctx;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
1014
  		fixup_nodatasum->dev = dev;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1015
1016
1017
  		fixup_nodatasum->logical = logical;
  		fixup_nodatasum->root = fs_info->extent_root;
  		fixup_nodatasum->mirror_num = failed_mirror_index + 1;
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
1018
  		scrub_pending_trans_workers_inc(sctx);
9e0af2376   Liu Bo   Btrfs: fix task h...
1019
1020
  		btrfs_init_work(&fixup_nodatasum->work, btrfs_scrub_helper,
  				scrub_fixup_nodatasum, NULL, NULL);
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
1021
1022
  		btrfs_queue_work(fs_info->scrub_workers,
  				 &fixup_nodatasum->work);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1023
  		goto out;
a2de733c7   Arne Jansen   btrfs: scrub
1024
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1025
1026
  	/*
  	 * now build and submit the bios for the other mirrors, check
cb2ced73d   Stefan Behrens   Btrfs: in scrub r...
1027
1028
  	 * checksums.
  	 * First try to pick the mirror which is completely without I/O
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  	 * errors and also does not have a checksum error.
  	 * If one is found, and if a checksum is present, the full block
  	 * that is known to contain an error is rewritten. Afterwards
  	 * the block is known to be corrected.
  	 * If a mirror is found which is completely correct, and no
  	 * checksum is present, only those pages are rewritten that had
  	 * an I/O error in the block to be repaired, since it cannot be
  	 * determined, which copy of the other pages is better (and it
  	 * could happen otherwise that a correct page would be
  	 * overwritten by a bad one).
  	 */
  	for (mirror_index = 0;
  	     mirror_index < BTRFS_MAX_MIRRORS &&
  	     sblocks_for_recheck[mirror_index].page_count > 0;
  	     mirror_index++) {
cb2ced73d   Stefan Behrens   Btrfs: in scrub r...
1044
  		struct scrub_block *sblock_other;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1045

cb2ced73d   Stefan Behrens   Btrfs: in scrub r...
1046
1047
1048
1049
1050
  		if (mirror_index == failed_mirror_index)
  			continue;
  		sblock_other = sblocks_for_recheck + mirror_index;
  
  		/* build and submit the bios, check checksums */
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1051
1052
  		scrub_recheck_block(fs_info, sblock_other, is_metadata,
  				    have_csum, csum, generation,
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1053
  				    sctx->csum_size, 0);
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1054
1055
  
  		if (!sblock_other->header_error &&
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1056
1057
  		    !sblock_other->checksum_error &&
  		    sblock_other->no_io_error_seen) {
ff023aac3   Stefan Behrens   Btrfs: add code t...
1058
1059
1060
1061
1062
1063
1064
1065
1066
  			if (sctx->is_dev_replace) {
  				scrub_write_block_to_dev_replace(sblock_other);
  			} else {
  				int force_write = is_metadata || have_csum;
  
  				ret = scrub_repair_block_from_good_copy(
  						sblock_bad, sblock_other,
  						force_write);
  			}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1067
1068
1069
1070
  			if (0 == ret)
  				goto corrected_error;
  		}
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1071
1072
  
  	/*
ff023aac3   Stefan Behrens   Btrfs: add code t...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  	 * for dev_replace, pick good pages and write to the target device.
  	 */
  	if (sctx->is_dev_replace) {
  		success = 1;
  		for (page_num = 0; page_num < sblock_bad->page_count;
  		     page_num++) {
  			int sub_success;
  
  			sub_success = 0;
  			for (mirror_index = 0;
  			     mirror_index < BTRFS_MAX_MIRRORS &&
  			     sblocks_for_recheck[mirror_index].page_count > 0;
  			     mirror_index++) {
  				struct scrub_block *sblock_other =
  					sblocks_for_recheck + mirror_index;
  				struct scrub_page *page_other =
  					sblock_other->pagev[page_num];
  
  				if (!page_other->io_error) {
  					ret = scrub_write_page_to_dev_replace(
  							sblock_other, page_num);
  					if (ret == 0) {
  						/* succeeded for this page */
  						sub_success = 1;
  						break;
  					} else {
  						btrfs_dev_replace_stats_inc(
  							&sctx->dev_root->
  							fs_info->dev_replace.
  							num_write_errors);
  					}
  				}
  			}
  
  			if (!sub_success) {
  				/*
  				 * did not find a mirror to fetch the page
  				 * from. scrub_write_page_to_dev_replace()
  				 * handles this case (page->io_error), by
  				 * filling the block with zeros before
  				 * submitting the write request
  				 */
  				success = 0;
  				ret = scrub_write_page_to_dev_replace(
  						sblock_bad, page_num);
  				if (ret)
  					btrfs_dev_replace_stats_inc(
  						&sctx->dev_root->fs_info->
  						dev_replace.num_write_errors);
  			}
  		}
  
  		goto out;
  	}
  
  	/*
  	 * for regular scrub, repair those pages that are errored.
  	 * In case of I/O errors in the area that is supposed to be
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
  	 * repaired, continue by picking good copies of those pages.
  	 * Select the good pages from mirrors to rewrite bad pages from
  	 * the area to fix. Afterwards verify the checksum of the block
  	 * that is supposed to be repaired. This verification step is
  	 * only done for the purpose of statistic counting and for the
  	 * final scrub report, whether errors remain.
  	 * A perfect algorithm could make use of the checksum and try
  	 * all possible combinations of pages from the different mirrors
  	 * until the checksum verification succeeds. For example, when
  	 * the 2nd page of mirror #1 faces I/O errors, and the 2nd page
  	 * of mirror #2 is readable but the final checksum test fails,
  	 * then the 2nd page of mirror #3 could be tried, whether now
  	 * the final checksum succeedes. But this would be a rare
  	 * exception and is therefore not implemented. At least it is
  	 * avoided that the good copy is overwritten.
  	 * A more useful improvement would be to pick the sectors
  	 * without I/O error based on sector sizes (512 bytes on legacy
  	 * disks) instead of on PAGE_SIZE. Then maybe 512 byte of one
  	 * mirror could be repaired by taking 512 byte of a different
  	 * mirror, even if other 512 byte sectors in the same PAGE_SIZE
  	 * area are unreadable.
a2de733c7   Arne Jansen   btrfs: scrub
1152
  	 */
a2de733c7   Arne Jansen   btrfs: scrub
1153

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1154
1155
1156
1157
1158
1159
  	/* can only fix I/O errors from here on */
  	if (sblock_bad->no_io_error_seen)
  		goto did_not_correct_error;
  
  	success = 1;
  	for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
7a9e99876   Stefan Behrens   Btrfs: make the s...
1160
  		struct scrub_page *page_bad = sblock_bad->pagev[page_num];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1161
1162
  
  		if (!page_bad->io_error)
a2de733c7   Arne Jansen   btrfs: scrub
1163
  			continue;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1164
1165
1166
1167
1168
1169
1170
  
  		for (mirror_index = 0;
  		     mirror_index < BTRFS_MAX_MIRRORS &&
  		     sblocks_for_recheck[mirror_index].page_count > 0;
  		     mirror_index++) {
  			struct scrub_block *sblock_other = sblocks_for_recheck +
  							   mirror_index;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1171
1172
  			struct scrub_page *page_other = sblock_other->pagev[
  							page_num];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1173
1174
1175
1176
1177
1178
1179
1180
1181
  
  			if (!page_other->io_error) {
  				ret = scrub_repair_page_from_good_copy(
  					sblock_bad, sblock_other, page_num, 0);
  				if (0 == ret) {
  					page_bad->io_error = 0;
  					break; /* succeeded for this page */
  				}
  			}
96e369208   Ilya Dryomov   btrfs scrub: make...
1182
  		}
a2de733c7   Arne Jansen   btrfs: scrub
1183

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1184
1185
1186
1187
  		if (page_bad->io_error) {
  			/* did not find a mirror to copy the page from */
  			success = 0;
  		}
a2de733c7   Arne Jansen   btrfs: scrub
1188
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1189

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
  	if (success) {
  		if (is_metadata || have_csum) {
  			/*
  			 * need to verify the checksum now that all
  			 * sectors on disk are repaired (the write
  			 * request for data to be repaired is on its way).
  			 * Just be lazy and use scrub_recheck_block()
  			 * which re-reads the data before the checksum
  			 * is verified, but most likely the data comes out
  			 * of the page cache.
  			 */
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1201
1202
  			scrub_recheck_block(fs_info, sblock_bad,
  					    is_metadata, have_csum, csum,
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1203
  					    generation, sctx->csum_size, 1);
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1204
  			if (!sblock_bad->header_error &&
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1205
1206
1207
1208
1209
1210
1211
  			    !sblock_bad->checksum_error &&
  			    sblock_bad->no_io_error_seen)
  				goto corrected_error;
  			else
  				goto did_not_correct_error;
  		} else {
  corrected_error:
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1212
1213
  			spin_lock(&sctx->stat_lock);
  			sctx->stat.corrected_errors++;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
1214
  			sblock_to_check->data_corrected = 1;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1215
  			spin_unlock(&sctx->stat_lock);
606686eea   Josef Bacik   Btrfs: use rcu to...
1216
  			printk_ratelimited_in_rcu(KERN_ERR
efe120a06   Frank Holton   Btrfs: convert pr...
1217
1218
  				"BTRFS: fixed up error at logical %llu on dev %s
  ",
c1c9ff7c9   Geert Uytterhoeven   Btrfs: Remove sup...
1219
  				logical, rcu_str_deref(dev->name));
8628764e1   Arne Jansen   btrfs: add readon...
1220
  		}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1221
1222
  	} else {
  did_not_correct_error:
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1223
1224
1225
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.uncorrectable_errors++;
  		spin_unlock(&sctx->stat_lock);
606686eea   Josef Bacik   Btrfs: use rcu to...
1226
  		printk_ratelimited_in_rcu(KERN_ERR
efe120a06   Frank Holton   Btrfs: convert pr...
1227
1228
  			"BTRFS: unable to fixup (regular) error at logical %llu on dev %s
  ",
c1c9ff7c9   Geert Uytterhoeven   Btrfs: Remove sup...
1229
  			logical, rcu_str_deref(dev->name));
96e369208   Ilya Dryomov   btrfs scrub: make...
1230
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1231

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1232
1233
1234
1235
1236
1237
  out:
  	if (sblocks_for_recheck) {
  		for (mirror_index = 0; mirror_index < BTRFS_MAX_MIRRORS;
  		     mirror_index++) {
  			struct scrub_block *sblock = sblocks_for_recheck +
  						     mirror_index;
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1238
  			struct scrub_recover *recover;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1239
  			int page_index;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1240
1241
1242
  			for (page_index = 0; page_index < sblock->page_count;
  			     page_index++) {
  				sblock->pagev[page_index]->sblock = NULL;
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1243
1244
1245
1246
1247
1248
  				recover = sblock->pagev[page_index]->recover;
  				if (recover) {
  					scrub_put_recover(recover);
  					sblock->pagev[page_index]->recover =
  									NULL;
  				}
7a9e99876   Stefan Behrens   Btrfs: make the s...
1249
1250
  				scrub_page_put(sblock->pagev[page_index]);
  			}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1251
1252
1253
  		}
  		kfree(sblocks_for_recheck);
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1254

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1255
1256
  	return 0;
  }
a2de733c7   Arne Jansen   btrfs: scrub
1257

af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
  static inline int scrub_nr_raid_mirrors(struct btrfs_bio *bbio, u64 *raid_map)
  {
  	if (raid_map) {
  		if (raid_map[bbio->num_stripes - 1] == RAID6_Q_STRIPE)
  			return 3;
  		else
  			return 2;
  	} else {
  		return (int)bbio->num_stripes;
  	}
  }
  
  static inline void scrub_stripe_index_and_offset(u64 logical, u64 *raid_map,
  						 u64 mapped_length,
  						 int nstripes, int mirror,
  						 int *stripe_index,
  						 u64 *stripe_offset)
  {
  	int i;
  
  	if (raid_map) {
  		/* RAID5/6 */
  		for (i = 0; i < nstripes; i++) {
  			if (raid_map[i] == RAID6_Q_STRIPE ||
  			    raid_map[i] == RAID5_P_STRIPE)
  				continue;
  
  			if (logical >= raid_map[i] &&
  			    logical < raid_map[i] + mapped_length)
  				break;
  		}
  
  		*stripe_index = i;
  		*stripe_offset = logical - raid_map[i];
  	} else {
  		/* The other RAID type */
  		*stripe_index = mirror;
  		*stripe_offset = 0;
  	}
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1298
  static int scrub_setup_recheck_block(struct scrub_ctx *sctx,
3ec706c83   Stefan Behrens   Btrfs: pass fs_in...
1299
  				     struct btrfs_fs_info *fs_info,
ff023aac3   Stefan Behrens   Btrfs: add code t...
1300
  				     struct scrub_block *original_sblock,
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1301
1302
1303
  				     u64 length, u64 logical,
  				     struct scrub_block *sblocks_for_recheck)
  {
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1304
1305
1306
1307
1308
1309
1310
  	struct scrub_recover *recover;
  	struct btrfs_bio *bbio;
  	u64 *raid_map;
  	u64 sublen;
  	u64 mapped_length;
  	u64 stripe_offset;
  	int stripe_index;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1311
1312
  	int page_index;
  	int mirror_index;
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1313
  	int nmirrors;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1314
1315
1316
  	int ret;
  
  	/*
7a9e99876   Stefan Behrens   Btrfs: make the s...
1317
  	 * note: the two members ref_count and outstanding_pages
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1318
1319
1320
1321
1322
1323
  	 * are not used (and not set) in the blocks that are used for
  	 * the recheck procedure
  	 */
  
  	page_index = 0;
  	while (length > 0) {
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1324
1325
1326
1327
  		sublen = min_t(u64, length, PAGE_SIZE);
  		mapped_length = sublen;
  		bbio = NULL;
  		raid_map = NULL;
a2de733c7   Arne Jansen   btrfs: scrub
1328

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1329
1330
1331
1332
  		/*
  		 * with a length of PAGE_SIZE, each returned stripe
  		 * represents one mirror
  		 */
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1333
1334
  		ret = btrfs_map_sblock(fs_info, REQ_GET_READ_MIRRORS, logical,
  				       &mapped_length, &bbio, 0, &raid_map);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1335
1336
  		if (ret || !bbio || mapped_length < sublen) {
  			kfree(bbio);
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1337
  			kfree(raid_map);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1338
1339
  			return -EIO;
  		}
a2de733c7   Arne Jansen   btrfs: scrub
1340

af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  		recover = kzalloc(sizeof(struct scrub_recover), GFP_NOFS);
  		if (!recover) {
  			kfree(bbio);
  			kfree(raid_map);
  			return -ENOMEM;
  		}
  
  		atomic_set(&recover->refs, 1);
  		recover->bbio = bbio;
  		recover->raid_map = raid_map;
  		recover->map_length = mapped_length;
ff023aac3   Stefan Behrens   Btrfs: add code t...
1352
  		BUG_ON(page_index >= SCRUB_PAGES_PER_RD_BIO);
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1353
1354
1355
  
  		nmirrors = scrub_nr_raid_mirrors(bbio, raid_map);
  		for (mirror_index = 0; mirror_index < nmirrors;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1356
1357
1358
1359
1360
1361
1362
1363
  		     mirror_index++) {
  			struct scrub_block *sblock;
  			struct scrub_page *page;
  
  			if (mirror_index >= BTRFS_MAX_MIRRORS)
  				continue;
  
  			sblock = sblocks_for_recheck + mirror_index;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1364
1365
1366
1367
  			sblock->sctx = sctx;
  			page = kzalloc(sizeof(*page), GFP_NOFS);
  			if (!page) {
  leave_nomem:
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1368
1369
1370
  				spin_lock(&sctx->stat_lock);
  				sctx->stat.malloc_errors++;
  				spin_unlock(&sctx->stat_lock);
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1371
  				scrub_put_recover(recover);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1372
1373
  				return -ENOMEM;
  			}
7a9e99876   Stefan Behrens   Btrfs: make the s...
1374
1375
1376
  			scrub_page_get(page);
  			sblock->pagev[page_index] = page;
  			page->logical = logical;
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  
  			scrub_stripe_index_and_offset(logical, raid_map,
  						      mapped_length,
  						      bbio->num_stripes,
  						      mirror_index,
  						      &stripe_index,
  						      &stripe_offset);
  			page->physical = bbio->stripes[stripe_index].physical +
  					 stripe_offset;
  			page->dev = bbio->stripes[stripe_index].dev;
ff023aac3   Stefan Behrens   Btrfs: add code t...
1387
1388
1389
1390
  			BUG_ON(page_index >= original_sblock->page_count);
  			page->physical_for_dev_replace =
  				original_sblock->pagev[page_index]->
  				physical_for_dev_replace;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1391
  			/* for missing devices, dev->bdev is NULL */
7a9e99876   Stefan Behrens   Btrfs: make the s...
1392
  			page->mirror_num = mirror_index + 1;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1393
  			sblock->page_count++;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1394
1395
1396
  			page->page = alloc_page(GFP_NOFS);
  			if (!page->page)
  				goto leave_nomem;
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1397
1398
1399
  
  			scrub_get_recover(recover);
  			page->recover = recover;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1400
  		}
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1401
  		scrub_put_recover(recover);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1402
1403
1404
1405
1406
1407
  		length -= sublen;
  		logical += sublen;
  		page_index++;
  	}
  
  	return 0;
96e369208   Ilya Dryomov   btrfs scrub: make...
1408
  }
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
  struct scrub_bio_ret {
  	struct completion event;
  	int error;
  };
  
  static void scrub_bio_wait_endio(struct bio *bio, int error)
  {
  	struct scrub_bio_ret *ret = bio->bi_private;
  
  	ret->error = error;
  	complete(&ret->event);
  }
  
  static inline int scrub_is_page_on_raid56(struct scrub_page *page)
  {
  	return page->recover && page->recover->raid_map;
  }
  
  static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info,
  					struct bio *bio,
  					struct scrub_page *page)
  {
  	struct scrub_bio_ret done;
  	int ret;
  
  	init_completion(&done.event);
  	done.error = 0;
  	bio->bi_iter.bi_sector = page->logical >> 9;
  	bio->bi_private = &done;
  	bio->bi_end_io = scrub_bio_wait_endio;
  
  	ret = raid56_parity_recover(fs_info->fs_root, bio, page->recover->bbio,
  				    page->recover->raid_map,
  				    page->recover->map_length,
4245215d6   Miao Xie   Btrfs, raid56: fi...
1443
  				    page->mirror_num, 0);
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1444
1445
1446
1447
1448
1449
1450
1451
1452
  	if (ret)
  		return ret;
  
  	wait_for_completion(&done.event);
  	if (done.error)
  		return -EIO;
  
  	return 0;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1453
1454
1455
1456
1457
1458
1459
  /*
   * this function will check the on disk data for checksum errors, header
   * errors and read I/O errors. If any I/O errors happen, the exact pages
   * which are errored are marked as being bad. The goal is to enable scrub
   * to take those pages that are not errored from all the mirrors so that
   * the pages that are errored in the just handled mirror can be repaired.
   */
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1460
1461
1462
  static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
  				struct scrub_block *sblock, int is_metadata,
  				int have_csum, u8 *csum, u64 generation,
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1463
  				u16 csum_size, int retry_failed_mirror)
96e369208   Ilya Dryomov   btrfs scrub: make...
1464
  {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1465
  	int page_num;
96e369208   Ilya Dryomov   btrfs scrub: make...
1466

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1467
1468
1469
  	sblock->no_io_error_seen = 1;
  	sblock->header_error = 0;
  	sblock->checksum_error = 0;
96e369208   Ilya Dryomov   btrfs scrub: make...
1470

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1471
1472
  	for (page_num = 0; page_num < sblock->page_count; page_num++) {
  		struct bio *bio;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1473
  		struct scrub_page *page = sblock->pagev[page_num];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1474

442a4f630   Stefan Behrens   Btrfs: add device...
1475
  		if (page->dev->bdev == NULL) {
ea9947b43   Stefan Behrens   Btrfs: fix crash ...
1476
1477
1478
1479
  			page->io_error = 1;
  			sblock->no_io_error_seen = 0;
  			continue;
  		}
7a9e99876   Stefan Behrens   Btrfs: make the s...
1480
  		WARN_ON(!page->page);
9be3395bc   Chris Mason   Btrfs: use a btrf...
1481
  		bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1482
1483
1484
1485
1486
  		if (!bio) {
  			page->io_error = 1;
  			sblock->no_io_error_seen = 0;
  			continue;
  		}
442a4f630   Stefan Behrens   Btrfs: add device...
1487
  		bio->bi_bdev = page->dev->bdev;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1488

34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1489
  		bio_add_page(bio, page->page, PAGE_SIZE, 0);
af8e2d1df   Miao Xie   Btrfs, scrub: rep...
1490
1491
1492
1493
1494
1495
1496
1497
1498
  		if (!retry_failed_mirror && scrub_is_page_on_raid56(page)) {
  			if (scrub_submit_raid56_bio_wait(fs_info, bio, page))
  				sblock->no_io_error_seen = 0;
  		} else {
  			bio->bi_iter.bi_sector = page->physical >> 9;
  
  			if (btrfsic_submit_bio_wait(READ, bio))
  				sblock->no_io_error_seen = 0;
  		}
33879d451   Kent Overstreet   block: submit_bio...
1499

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1500
1501
  		bio_put(bio);
  	}
96e369208   Ilya Dryomov   btrfs scrub: make...
1502

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1503
1504
1505
1506
  	if (sblock->no_io_error_seen)
  		scrub_recheck_block_checksum(fs_info, sblock, is_metadata,
  					     have_csum, csum, generation,
  					     csum_size);
34f5c8e90   Stefan Behrens   Btrfs: in scrub r...
1507
  	return;
a2de733c7   Arne Jansen   btrfs: scrub
1508
  }
17a9be2f2   Miao Xie   Btrfs: fix wrong ...
1509
1510
1511
1512
1513
1514
1515
1516
1517
  static inline int scrub_check_fsid(u8 fsid[],
  				   struct scrub_page *spage)
  {
  	struct btrfs_fs_devices *fs_devices = spage->dev->fs_devices;
  	int ret;
  
  	ret = memcmp(fsid, fs_devices->fsid, BTRFS_UUID_SIZE);
  	return !ret;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1518
1519
1520
1521
1522
  static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
  					 struct scrub_block *sblock,
  					 int is_metadata, int have_csum,
  					 const u8 *csum, u64 generation,
  					 u16 csum_size)
a2de733c7   Arne Jansen   btrfs: scrub
1523
  {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1524
1525
1526
  	int page_num;
  	u8 calculated_csum[BTRFS_CSUM_SIZE];
  	u32 crc = ~(u32)0;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1527
  	void *mapped_buffer;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1528
  	WARN_ON(!sblock->pagev[0]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1529
1530
  	if (is_metadata) {
  		struct btrfs_header *h;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1531
  		mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1532
  		h = (struct btrfs_header *)mapped_buffer;
3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1533
  		if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h) ||
17a9be2f2   Miao Xie   Btrfs: fix wrong ...
1534
  		    !scrub_check_fsid(h->fsid, sblock->pagev[0]) ||
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1535
  		    memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
442a4f630   Stefan Behrens   Btrfs: add device...
1536
  			   BTRFS_UUID_SIZE)) {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1537
  			sblock->header_error = 1;
3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1538
  		} else if (generation != btrfs_stack_header_generation(h)) {
442a4f630   Stefan Behrens   Btrfs: add device...
1539
1540
1541
  			sblock->header_error = 1;
  			sblock->generation_error = 1;
  		}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1542
1543
1544
1545
  		csum = h->csum;
  	} else {
  		if (!have_csum)
  			return;
a2de733c7   Arne Jansen   btrfs: scrub
1546

7a9e99876   Stefan Behrens   Btrfs: make the s...
1547
  		mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1548
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1549

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1550
1551
  	for (page_num = 0;;) {
  		if (page_num == 0 && is_metadata)
b0496686b   Liu Bo   Btrfs: cleanup un...
1552
  			crc = btrfs_csum_data(
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1553
1554
1555
  				((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE,
  				crc, PAGE_SIZE - BTRFS_CSUM_SIZE);
  		else
b0496686b   Liu Bo   Btrfs: cleanup un...
1556
  			crc = btrfs_csum_data(mapped_buffer, crc, PAGE_SIZE);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1557

9613bebb2   Linus Torvalds   Merge branch 'for...
1558
  		kunmap_atomic(mapped_buffer);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1559
1560
1561
  		page_num++;
  		if (page_num >= sblock->page_count)
  			break;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1562
  		WARN_ON(!sblock->pagev[page_num]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1563

7a9e99876   Stefan Behrens   Btrfs: make the s...
1564
  		mapped_buffer = kmap_atomic(sblock->pagev[page_num]->page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1565
1566
1567
1568
1569
  	}
  
  	btrfs_csum_final(crc, calculated_csum);
  	if (memcmp(calculated_csum, csum, csum_size))
  		sblock->checksum_error = 1;
a2de733c7   Arne Jansen   btrfs: scrub
1570
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1571
1572
1573
1574
1575
1576
  static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
  					     struct scrub_block *sblock_good,
  					     int force_write)
  {
  	int page_num;
  	int ret = 0;
96e369208   Ilya Dryomov   btrfs scrub: make...
1577

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1578
1579
  	for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
  		int ret_sub;
96e369208   Ilya Dryomov   btrfs scrub: make...
1580

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1581
1582
1583
1584
1585
1586
  		ret_sub = scrub_repair_page_from_good_copy(sblock_bad,
  							   sblock_good,
  							   page_num,
  							   force_write);
  		if (ret_sub)
  			ret = ret_sub;
a2de733c7   Arne Jansen   btrfs: scrub
1587
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1588
1589
1590
1591
1592
1593
1594
1595
  
  	return ret;
  }
  
  static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
  					    struct scrub_block *sblock_good,
  					    int page_num, int force_write)
  {
7a9e99876   Stefan Behrens   Btrfs: make the s...
1596
1597
  	struct scrub_page *page_bad = sblock_bad->pagev[page_num];
  	struct scrub_page *page_good = sblock_good->pagev[page_num];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1598

7a9e99876   Stefan Behrens   Btrfs: make the s...
1599
1600
  	BUG_ON(page_bad->page == NULL);
  	BUG_ON(page_good->page == NULL);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1601
1602
1603
1604
  	if (force_write || sblock_bad->header_error ||
  	    sblock_bad->checksum_error || page_bad->io_error) {
  		struct bio *bio;
  		int ret;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1605

ff023aac3   Stefan Behrens   Btrfs: add code t...
1606
  		if (!page_bad->dev->bdev) {
efe120a06   Frank Holton   Btrfs: convert pr...
1607
1608
1609
1610
  			printk_ratelimited(KERN_WARNING "BTRFS: "
  				"scrub_repair_page_from_good_copy(bdev == NULL) "
  				"is unexpected!
  ");
ff023aac3   Stefan Behrens   Btrfs: add code t...
1611
1612
  			return -EIO;
  		}
9be3395bc   Chris Mason   Btrfs: use a btrf...
1613
  		bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
e627ee7bc   Tsutomu Itoh   Btrfs: check retu...
1614
1615
  		if (!bio)
  			return -EIO;
442a4f630   Stefan Behrens   Btrfs: add device...
1616
  		bio->bi_bdev = page_bad->dev->bdev;
4f024f379   Kent Overstreet   block: Abstract o...
1617
  		bio->bi_iter.bi_sector = page_bad->physical >> 9;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1618
1619
1620
1621
1622
  
  		ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0);
  		if (PAGE_SIZE != ret) {
  			bio_put(bio);
  			return -EIO;
13db62b7a   Jan Schmidt   btrfs scrub: adde...
1623
  		}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1624

33879d451   Kent Overstreet   block: submit_bio...
1625
  		if (btrfsic_submit_bio_wait(WRITE, bio)) {
442a4f630   Stefan Behrens   Btrfs: add device...
1626
1627
  			btrfs_dev_stat_inc_and_print(page_bad->dev,
  				BTRFS_DEV_STAT_WRITE_ERRS);
ff023aac3   Stefan Behrens   Btrfs: add code t...
1628
1629
1630
  			btrfs_dev_replace_stats_inc(
  				&sblock_bad->sctx->dev_root->fs_info->
  				dev_replace.num_write_errors);
442a4f630   Stefan Behrens   Btrfs: add device...
1631
1632
1633
  			bio_put(bio);
  			return -EIO;
  		}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1634
  		bio_put(bio);
a2de733c7   Arne Jansen   btrfs: scrub
1635
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1636
1637
  	return 0;
  }
ff023aac3   Stefan Behrens   Btrfs: add code t...
1638
1639
1640
  static void scrub_write_block_to_dev_replace(struct scrub_block *sblock)
  {
  	int page_num;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
1641
1642
1643
1644
1645
1646
  	/*
  	 * This block is used for the check of the parity on the source device,
  	 * so the data needn't be written into the destination device.
  	 */
  	if (sblock->sparity)
  		return;
ff023aac3   Stefan Behrens   Btrfs: add code t...
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
  	for (page_num = 0; page_num < sblock->page_count; page_num++) {
  		int ret;
  
  		ret = scrub_write_page_to_dev_replace(sblock, page_num);
  		if (ret)
  			btrfs_dev_replace_stats_inc(
  				&sblock->sctx->dev_root->fs_info->dev_replace.
  				num_write_errors);
  	}
  }
  
  static int scrub_write_page_to_dev_replace(struct scrub_block *sblock,
  					   int page_num)
  {
  	struct scrub_page *spage = sblock->pagev[page_num];
  
  	BUG_ON(spage->page == NULL);
  	if (spage->io_error) {
  		void *mapped_buffer = kmap_atomic(spage->page);
  
  		memset(mapped_buffer, 0, PAGE_CACHE_SIZE);
  		flush_dcache_page(spage->page);
  		kunmap_atomic(mapped_buffer);
  	}
  	return scrub_add_page_to_wr_bio(sblock->sctx, spage);
  }
  
  static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
  				    struct scrub_page *spage)
  {
  	struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx;
  	struct scrub_bio *sbio;
  	int ret;
  
  	mutex_lock(&wr_ctx->wr_lock);
  again:
  	if (!wr_ctx->wr_curr_bio) {
  		wr_ctx->wr_curr_bio = kzalloc(sizeof(*wr_ctx->wr_curr_bio),
  					      GFP_NOFS);
  		if (!wr_ctx->wr_curr_bio) {
  			mutex_unlock(&wr_ctx->wr_lock);
  			return -ENOMEM;
  		}
  		wr_ctx->wr_curr_bio->sctx = sctx;
  		wr_ctx->wr_curr_bio->page_count = 0;
  	}
  	sbio = wr_ctx->wr_curr_bio;
  	if (sbio->page_count == 0) {
  		struct bio *bio;
  
  		sbio->physical = spage->physical_for_dev_replace;
  		sbio->logical = spage->logical;
  		sbio->dev = wr_ctx->tgtdev;
  		bio = sbio->bio;
  		if (!bio) {
9be3395bc   Chris Mason   Btrfs: use a btrf...
1702
  			bio = btrfs_io_bio_alloc(GFP_NOFS, wr_ctx->pages_per_wr_bio);
ff023aac3   Stefan Behrens   Btrfs: add code t...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
  			if (!bio) {
  				mutex_unlock(&wr_ctx->wr_lock);
  				return -ENOMEM;
  			}
  			sbio->bio = bio;
  		}
  
  		bio->bi_private = sbio;
  		bio->bi_end_io = scrub_wr_bio_end_io;
  		bio->bi_bdev = sbio->dev->bdev;
4f024f379   Kent Overstreet   block: Abstract o...
1713
  		bio->bi_iter.bi_sector = sbio->physical >> 9;
ff023aac3   Stefan Behrens   Btrfs: add code t...
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
  		sbio->err = 0;
  	} else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
  		   spage->physical_for_dev_replace ||
  		   sbio->logical + sbio->page_count * PAGE_SIZE !=
  		   spage->logical) {
  		scrub_wr_submit(sctx);
  		goto again;
  	}
  
  	ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
  	if (ret != PAGE_SIZE) {
  		if (sbio->page_count < 1) {
  			bio_put(sbio->bio);
  			sbio->bio = NULL;
  			mutex_unlock(&wr_ctx->wr_lock);
  			return -EIO;
  		}
  		scrub_wr_submit(sctx);
  		goto again;
  	}
  
  	sbio->pagev[sbio->page_count] = spage;
  	scrub_page_get(spage);
  	sbio->page_count++;
  	if (sbio->page_count == wr_ctx->pages_per_wr_bio)
  		scrub_wr_submit(sctx);
  	mutex_unlock(&wr_ctx->wr_lock);
  
  	return 0;
  }
  
  static void scrub_wr_submit(struct scrub_ctx *sctx)
  {
  	struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx;
  	struct scrub_bio *sbio;
  
  	if (!wr_ctx->wr_curr_bio)
  		return;
  
  	sbio = wr_ctx->wr_curr_bio;
  	wr_ctx->wr_curr_bio = NULL;
  	WARN_ON(!sbio->bio->bi_bdev);
  	scrub_pending_bio_inc(sctx);
  	/* process all writes in a single worker thread. Then the block layer
  	 * orders the requests before sending them to the driver which
  	 * doubled the write performance on spinning disks when measured
  	 * with Linux 3.5 */
  	btrfsic_submit_bio(WRITE, sbio->bio);
  }
  
  static void scrub_wr_bio_end_io(struct bio *bio, int err)
  {
  	struct scrub_bio *sbio = bio->bi_private;
  	struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
  
  	sbio->err = err;
  	sbio->bio = bio;
9e0af2376   Liu Bo   Btrfs: fix task h...
1771
1772
  	btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper,
  			 scrub_wr_bio_end_io_worker, NULL, NULL);
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
1773
  	btrfs_queue_work(fs_info->scrub_wr_completion_workers, &sbio->work);
ff023aac3   Stefan Behrens   Btrfs: add code t...
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
  }
  
  static void scrub_wr_bio_end_io_worker(struct btrfs_work *work)
  {
  	struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
  	struct scrub_ctx *sctx = sbio->sctx;
  	int i;
  
  	WARN_ON(sbio->page_count > SCRUB_PAGES_PER_WR_BIO);
  	if (sbio->err) {
  		struct btrfs_dev_replace *dev_replace =
  			&sbio->sctx->dev_root->fs_info->dev_replace;
  
  		for (i = 0; i < sbio->page_count; i++) {
  			struct scrub_page *spage = sbio->pagev[i];
  
  			spage->io_error = 1;
  			btrfs_dev_replace_stats_inc(&dev_replace->
  						    num_write_errors);
  		}
  	}
  
  	for (i = 0; i < sbio->page_count; i++)
  		scrub_page_put(sbio->pagev[i]);
  
  	bio_put(sbio->bio);
  	kfree(sbio);
  	scrub_pending_bio_dec(sctx);
  }
  
  static int scrub_checksum(struct scrub_block *sblock)
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1805
1806
1807
  {
  	u64 flags;
  	int ret;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1808
1809
  	WARN_ON(sblock->page_count < 1);
  	flags = sblock->pagev[0]->flags;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
  	ret = 0;
  	if (flags & BTRFS_EXTENT_FLAG_DATA)
  		ret = scrub_checksum_data(sblock);
  	else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
  		ret = scrub_checksum_tree_block(sblock);
  	else if (flags & BTRFS_EXTENT_FLAG_SUPER)
  		(void)scrub_checksum_super(sblock);
  	else
  		WARN_ON(1);
  	if (ret)
  		scrub_handle_errored_block(sblock);
ff023aac3   Stefan Behrens   Btrfs: add code t...
1821
1822
  
  	return ret;
a2de733c7   Arne Jansen   btrfs: scrub
1823
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1824
  static int scrub_checksum_data(struct scrub_block *sblock)
a2de733c7   Arne Jansen   btrfs: scrub
1825
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1826
  	struct scrub_ctx *sctx = sblock->sctx;
a2de733c7   Arne Jansen   btrfs: scrub
1827
  	u8 csum[BTRFS_CSUM_SIZE];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1828
1829
1830
  	u8 *on_disk_csum;
  	struct page *page;
  	void *buffer;
a2de733c7   Arne Jansen   btrfs: scrub
1831
1832
  	u32 crc = ~(u32)0;
  	int fail = 0;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1833
1834
  	u64 len;
  	int index;
a2de733c7   Arne Jansen   btrfs: scrub
1835

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1836
  	BUG_ON(sblock->page_count < 1);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1837
  	if (!sblock->pagev[0]->have_csum)
a2de733c7   Arne Jansen   btrfs: scrub
1838
  		return 0;
7a9e99876   Stefan Behrens   Btrfs: make the s...
1839
1840
  	on_disk_csum = sblock->pagev[0]->csum;
  	page = sblock->pagev[0]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1841
  	buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1842

d9d181c1b   Stefan Behrens   Btrfs: rename the...
1843
  	len = sctx->sectorsize;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1844
1845
1846
  	index = 0;
  	for (;;) {
  		u64 l = min_t(u64, len, PAGE_SIZE);
b0496686b   Liu Bo   Btrfs: cleanup un...
1847
  		crc = btrfs_csum_data(buffer, crc, l);
9613bebb2   Linus Torvalds   Merge branch 'for...
1848
  		kunmap_atomic(buffer);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1849
1850
1851
1852
1853
  		len -= l;
  		if (len == 0)
  			break;
  		index++;
  		BUG_ON(index >= sblock->page_count);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1854
1855
  		BUG_ON(!sblock->pagev[index]->page);
  		page = sblock->pagev[index]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1856
  		buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1857
  	}
a2de733c7   Arne Jansen   btrfs: scrub
1858
  	btrfs_csum_final(crc, csum);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1859
  	if (memcmp(csum, on_disk_csum, sctx->csum_size))
a2de733c7   Arne Jansen   btrfs: scrub
1860
  		fail = 1;
a2de733c7   Arne Jansen   btrfs: scrub
1861
1862
  	return fail;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1863
  static int scrub_checksum_tree_block(struct scrub_block *sblock)
a2de733c7   Arne Jansen   btrfs: scrub
1864
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1865
  	struct scrub_ctx *sctx = sblock->sctx;
a2de733c7   Arne Jansen   btrfs: scrub
1866
  	struct btrfs_header *h;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
1867
  	struct btrfs_root *root = sctx->dev_root;
a2de733c7   Arne Jansen   btrfs: scrub
1868
  	struct btrfs_fs_info *fs_info = root->fs_info;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1869
1870
1871
1872
1873
1874
  	u8 calculated_csum[BTRFS_CSUM_SIZE];
  	u8 on_disk_csum[BTRFS_CSUM_SIZE];
  	struct page *page;
  	void *mapped_buffer;
  	u64 mapped_size;
  	void *p;
a2de733c7   Arne Jansen   btrfs: scrub
1875
1876
1877
  	u32 crc = ~(u32)0;
  	int fail = 0;
  	int crc_fail = 0;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1878
1879
1880
1881
  	u64 len;
  	int index;
  
  	BUG_ON(sblock->page_count < 1);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1882
  	page = sblock->pagev[0]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1883
  	mapped_buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1884
  	h = (struct btrfs_header *)mapped_buffer;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1885
  	memcpy(on_disk_csum, h->csum, sctx->csum_size);
a2de733c7   Arne Jansen   btrfs: scrub
1886
1887
1888
1889
1890
1891
  
  	/*
  	 * we don't use the getter functions here, as we
  	 * a) don't have an extent buffer and
  	 * b) the page is already kmapped
  	 */
a2de733c7   Arne Jansen   btrfs: scrub
1892

3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1893
  	if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h))
a2de733c7   Arne Jansen   btrfs: scrub
1894
  		++fail;
3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1895
  	if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h))
a2de733c7   Arne Jansen   btrfs: scrub
1896
  		++fail;
17a9be2f2   Miao Xie   Btrfs: fix wrong ...
1897
  	if (!scrub_check_fsid(h->fsid, sblock->pagev[0]))
a2de733c7   Arne Jansen   btrfs: scrub
1898
1899
1900
1901
1902
  		++fail;
  
  	if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
  		   BTRFS_UUID_SIZE))
  		++fail;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1903
  	len = sctx->nodesize - BTRFS_CSUM_SIZE;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1904
1905
1906
1907
1908
  	mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
  	p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
  	index = 0;
  	for (;;) {
  		u64 l = min_t(u64, len, mapped_size);
b0496686b   Liu Bo   Btrfs: cleanup un...
1909
  		crc = btrfs_csum_data(p, crc, l);
9613bebb2   Linus Torvalds   Merge branch 'for...
1910
  		kunmap_atomic(mapped_buffer);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1911
1912
1913
1914
1915
  		len -= l;
  		if (len == 0)
  			break;
  		index++;
  		BUG_ON(index >= sblock->page_count);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1916
1917
  		BUG_ON(!sblock->pagev[index]->page);
  		page = sblock->pagev[index]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1918
  		mapped_buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1919
1920
1921
1922
1923
  		mapped_size = PAGE_SIZE;
  		p = mapped_buffer;
  	}
  
  	btrfs_csum_final(crc, calculated_csum);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1924
  	if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
a2de733c7   Arne Jansen   btrfs: scrub
1925
  		++crc_fail;
a2de733c7   Arne Jansen   btrfs: scrub
1926
1927
  	return fail || crc_fail;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1928
  static int scrub_checksum_super(struct scrub_block *sblock)
a2de733c7   Arne Jansen   btrfs: scrub
1929
1930
  {
  	struct btrfs_super_block *s;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1931
  	struct scrub_ctx *sctx = sblock->sctx;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1932
1933
1934
1935
1936
1937
  	u8 calculated_csum[BTRFS_CSUM_SIZE];
  	u8 on_disk_csum[BTRFS_CSUM_SIZE];
  	struct page *page;
  	void *mapped_buffer;
  	u64 mapped_size;
  	void *p;
a2de733c7   Arne Jansen   btrfs: scrub
1938
  	u32 crc = ~(u32)0;
442a4f630   Stefan Behrens   Btrfs: add device...
1939
1940
  	int fail_gen = 0;
  	int fail_cor = 0;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1941
1942
  	u64 len;
  	int index;
a2de733c7   Arne Jansen   btrfs: scrub
1943

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1944
  	BUG_ON(sblock->page_count < 1);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1945
  	page = sblock->pagev[0]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1946
  	mapped_buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1947
  	s = (struct btrfs_super_block *)mapped_buffer;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1948
  	memcpy(on_disk_csum, s->csum, sctx->csum_size);
a2de733c7   Arne Jansen   btrfs: scrub
1949

3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1950
  	if (sblock->pagev[0]->logical != btrfs_super_bytenr(s))
442a4f630   Stefan Behrens   Btrfs: add device...
1951
  		++fail_cor;
a2de733c7   Arne Jansen   btrfs: scrub
1952

3cae210fa   Qu Wenruo   btrfs: Cleanup fo...
1953
  	if (sblock->pagev[0]->generation != btrfs_super_generation(s))
442a4f630   Stefan Behrens   Btrfs: add device...
1954
  		++fail_gen;
a2de733c7   Arne Jansen   btrfs: scrub
1955

17a9be2f2   Miao Xie   Btrfs: fix wrong ...
1956
  	if (!scrub_check_fsid(s->fsid, sblock->pagev[0]))
442a4f630   Stefan Behrens   Btrfs: add device...
1957
  		++fail_cor;
a2de733c7   Arne Jansen   btrfs: scrub
1958

b5d67f64f   Stefan Behrens   Btrfs: change scr...
1959
1960
1961
1962
1963
1964
  	len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE;
  	mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
  	p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
  	index = 0;
  	for (;;) {
  		u64 l = min_t(u64, len, mapped_size);
b0496686b   Liu Bo   Btrfs: cleanup un...
1965
  		crc = btrfs_csum_data(p, crc, l);
9613bebb2   Linus Torvalds   Merge branch 'for...
1966
  		kunmap_atomic(mapped_buffer);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1967
1968
1969
1970
1971
  		len -= l;
  		if (len == 0)
  			break;
  		index++;
  		BUG_ON(index >= sblock->page_count);
7a9e99876   Stefan Behrens   Btrfs: make the s...
1972
1973
  		BUG_ON(!sblock->pagev[index]->page);
  		page = sblock->pagev[index]->page;
9613bebb2   Linus Torvalds   Merge branch 'for...
1974
  		mapped_buffer = kmap_atomic(page);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
1975
1976
1977
1978
1979
  		mapped_size = PAGE_SIZE;
  		p = mapped_buffer;
  	}
  
  	btrfs_csum_final(crc, calculated_csum);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1980
  	if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
442a4f630   Stefan Behrens   Btrfs: add device...
1981
  		++fail_cor;
a2de733c7   Arne Jansen   btrfs: scrub
1982

442a4f630   Stefan Behrens   Btrfs: add device...
1983
  	if (fail_cor + fail_gen) {
a2de733c7   Arne Jansen   btrfs: scrub
1984
1985
1986
1987
1988
  		/*
  		 * if we find an error in a super block, we just report it.
  		 * They will get written with the next transaction commit
  		 * anyway
  		 */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
1989
1990
1991
  		spin_lock(&sctx->stat_lock);
  		++sctx->stat.super_errors;
  		spin_unlock(&sctx->stat_lock);
442a4f630   Stefan Behrens   Btrfs: add device...
1992
  		if (fail_cor)
7a9e99876   Stefan Behrens   Btrfs: make the s...
1993
  			btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev,
442a4f630   Stefan Behrens   Btrfs: add device...
1994
1995
  				BTRFS_DEV_STAT_CORRUPTION_ERRS);
  		else
7a9e99876   Stefan Behrens   Btrfs: make the s...
1996
  			btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev,
442a4f630   Stefan Behrens   Btrfs: add device...
1997
  				BTRFS_DEV_STAT_GENERATION_ERRS);
a2de733c7   Arne Jansen   btrfs: scrub
1998
  	}
442a4f630   Stefan Behrens   Btrfs: add device...
1999
  	return fail_cor + fail_gen;
a2de733c7   Arne Jansen   btrfs: scrub
2000
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2001
2002
2003
2004
2005
2006
2007
2008
2009
  static void scrub_block_get(struct scrub_block *sblock)
  {
  	atomic_inc(&sblock->ref_count);
  }
  
  static void scrub_block_put(struct scrub_block *sblock)
  {
  	if (atomic_dec_and_test(&sblock->ref_count)) {
  		int i;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2010
2011
  		if (sblock->sparity)
  			scrub_parity_put(sblock->sparity);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2012
  		for (i = 0; i < sblock->page_count; i++)
7a9e99876   Stefan Behrens   Btrfs: make the s...
2013
  			scrub_page_put(sblock->pagev[i]);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2014
2015
2016
  		kfree(sblock);
  	}
  }
7a9e99876   Stefan Behrens   Btrfs: make the s...
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
  static void scrub_page_get(struct scrub_page *spage)
  {
  	atomic_inc(&spage->ref_count);
  }
  
  static void scrub_page_put(struct scrub_page *spage)
  {
  	if (atomic_dec_and_test(&spage->ref_count)) {
  		if (spage->page)
  			__free_page(spage->page);
  		kfree(spage);
  	}
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2030
  static void scrub_submit(struct scrub_ctx *sctx)
a2de733c7   Arne Jansen   btrfs: scrub
2031
2032
  {
  	struct scrub_bio *sbio;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2033
  	if (sctx->curr == -1)
1623edebe   Stefan Behrens   Btrfs: minor clea...
2034
  		return;
a2de733c7   Arne Jansen   btrfs: scrub
2035

d9d181c1b   Stefan Behrens   Btrfs: rename the...
2036
2037
  	sbio = sctx->bios[sctx->curr];
  	sctx->curr = -1;
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
2038
  	scrub_pending_bio_inc(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
2039

ff023aac3   Stefan Behrens   Btrfs: add code t...
2040
2041
2042
2043
2044
2045
2046
2047
2048
  	if (!sbio->bio->bi_bdev) {
  		/*
  		 * this case should not happen. If btrfs_map_block() is
  		 * wrong, it could happen for dev-replace operations on
  		 * missing devices when no mirrors are available, but in
  		 * this case it should already fail the mount.
  		 * This case is handled correctly (but _very_ slowly).
  		 */
  		printk_ratelimited(KERN_WARNING
efe120a06   Frank Holton   Btrfs: convert pr...
2049
2050
  			"BTRFS: scrub_submit(bio bdev == NULL) is unexpected!
  ");
ff023aac3   Stefan Behrens   Btrfs: add code t...
2051
2052
2053
2054
  		bio_endio(sbio->bio, -EIO);
  	} else {
  		btrfsic_submit_bio(READ, sbio->bio);
  	}
a2de733c7   Arne Jansen   btrfs: scrub
2055
  }
ff023aac3   Stefan Behrens   Btrfs: add code t...
2056
2057
  static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx,
  				    struct scrub_page *spage)
a2de733c7   Arne Jansen   btrfs: scrub
2058
  {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2059
  	struct scrub_block *sblock = spage->sblock;
a2de733c7   Arne Jansen   btrfs: scrub
2060
  	struct scrub_bio *sbio;
69f4cb526   Arne Jansen   Btrfs: handle bio...
2061
  	int ret;
a2de733c7   Arne Jansen   btrfs: scrub
2062
2063
2064
2065
2066
  
  again:
  	/*
  	 * grab a fresh bio or wait for one to become available
  	 */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2067
2068
2069
2070
2071
2072
2073
2074
  	while (sctx->curr == -1) {
  		spin_lock(&sctx->list_lock);
  		sctx->curr = sctx->first_free;
  		if (sctx->curr != -1) {
  			sctx->first_free = sctx->bios[sctx->curr]->next_free;
  			sctx->bios[sctx->curr]->next_free = -1;
  			sctx->bios[sctx->curr]->page_count = 0;
  			spin_unlock(&sctx->list_lock);
a2de733c7   Arne Jansen   btrfs: scrub
2075
  		} else {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2076
2077
  			spin_unlock(&sctx->list_lock);
  			wait_event(sctx->list_wait, sctx->first_free != -1);
a2de733c7   Arne Jansen   btrfs: scrub
2078
2079
  		}
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2080
  	sbio = sctx->bios[sctx->curr];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2081
  	if (sbio->page_count == 0) {
69f4cb526   Arne Jansen   Btrfs: handle bio...
2082
  		struct bio *bio;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2083
2084
  		sbio->physical = spage->physical;
  		sbio->logical = spage->logical;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2085
  		sbio->dev = spage->dev;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2086
2087
  		bio = sbio->bio;
  		if (!bio) {
9be3395bc   Chris Mason   Btrfs: use a btrf...
2088
  			bio = btrfs_io_bio_alloc(GFP_NOFS, sctx->pages_per_rd_bio);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2089
2090
2091
2092
  			if (!bio)
  				return -ENOMEM;
  			sbio->bio = bio;
  		}
69f4cb526   Arne Jansen   Btrfs: handle bio...
2093
2094
2095
  
  		bio->bi_private = sbio;
  		bio->bi_end_io = scrub_bio_end_io;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2096
  		bio->bi_bdev = sbio->dev->bdev;
4f024f379   Kent Overstreet   block: Abstract o...
2097
  		bio->bi_iter.bi_sector = sbio->physical >> 9;
69f4cb526   Arne Jansen   Btrfs: handle bio...
2098
  		sbio->err = 0;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2099
2100
2101
  	} else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
  		   spage->physical ||
  		   sbio->logical + sbio->page_count * PAGE_SIZE !=
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2102
2103
  		   spage->logical ||
  		   sbio->dev != spage->dev) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2104
  		scrub_submit(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
2105
2106
  		goto again;
  	}
69f4cb526   Arne Jansen   Btrfs: handle bio...
2107

b5d67f64f   Stefan Behrens   Btrfs: change scr...
2108
2109
2110
2111
2112
2113
2114
2115
  	sbio->pagev[sbio->page_count] = spage;
  	ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
  	if (ret != PAGE_SIZE) {
  		if (sbio->page_count < 1) {
  			bio_put(sbio->bio);
  			sbio->bio = NULL;
  			return -EIO;
  		}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2116
  		scrub_submit(sctx);
69f4cb526   Arne Jansen   Btrfs: handle bio...
2117
2118
  		goto again;
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
2119
  	scrub_block_get(sblock); /* one for the page added to the bio */
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2120
2121
  	atomic_inc(&sblock->outstanding_pages);
  	sbio->page_count++;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2122
  	if (sbio->page_count == sctx->pages_per_rd_bio)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2123
  		scrub_submit(sctx);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2124
2125
2126
  
  	return 0;
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2127
  static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2128
  		       u64 physical, struct btrfs_device *dev, u64 flags,
ff023aac3   Stefan Behrens   Btrfs: add code t...
2129
2130
  		       u64 gen, int mirror_num, u8 *csum, int force,
  		       u64 physical_for_dev_replace)
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2131
2132
2133
2134
2135
2136
  {
  	struct scrub_block *sblock;
  	int index;
  
  	sblock = kzalloc(sizeof(*sblock), GFP_NOFS);
  	if (!sblock) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2137
2138
2139
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2140
  		return -ENOMEM;
a2de733c7   Arne Jansen   btrfs: scrub
2141
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2142

7a9e99876   Stefan Behrens   Btrfs: make the s...
2143
2144
  	/* one ref inside this function, plus one for each page added to
  	 * a bio later on */
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2145
  	atomic_set(&sblock->ref_count, 1);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2146
  	sblock->sctx = sctx;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2147
2148
2149
  	sblock->no_io_error_seen = 1;
  
  	for (index = 0; len > 0; index++) {
7a9e99876   Stefan Behrens   Btrfs: make the s...
2150
  		struct scrub_page *spage;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2151
  		u64 l = min_t(u64, len, PAGE_SIZE);
7a9e99876   Stefan Behrens   Btrfs: make the s...
2152
2153
2154
  		spage = kzalloc(sizeof(*spage), GFP_NOFS);
  		if (!spage) {
  leave_nomem:
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2155
2156
2157
  			spin_lock(&sctx->stat_lock);
  			sctx->stat.malloc_errors++;
  			spin_unlock(&sctx->stat_lock);
7a9e99876   Stefan Behrens   Btrfs: make the s...
2158
  			scrub_block_put(sblock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2159
2160
  			return -ENOMEM;
  		}
7a9e99876   Stefan Behrens   Btrfs: make the s...
2161
2162
2163
  		BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK);
  		scrub_page_get(spage);
  		sblock->pagev[index] = spage;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2164
  		spage->sblock = sblock;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2165
  		spage->dev = dev;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2166
2167
2168
2169
  		spage->flags = flags;
  		spage->generation = gen;
  		spage->logical = logical;
  		spage->physical = physical;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2170
  		spage->physical_for_dev_replace = physical_for_dev_replace;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2171
2172
2173
  		spage->mirror_num = mirror_num;
  		if (csum) {
  			spage->have_csum = 1;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2174
  			memcpy(spage->csum, csum, sctx->csum_size);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2175
2176
2177
2178
  		} else {
  			spage->have_csum = 0;
  		}
  		sblock->page_count++;
7a9e99876   Stefan Behrens   Btrfs: make the s...
2179
2180
2181
  		spage->page = alloc_page(GFP_NOFS);
  		if (!spage->page)
  			goto leave_nomem;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2182
2183
2184
  		len -= l;
  		logical += l;
  		physical += l;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2185
  		physical_for_dev_replace += l;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2186
  	}
7a9e99876   Stefan Behrens   Btrfs: make the s...
2187
  	WARN_ON(sblock->page_count == 0);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2188
  	for (index = 0; index < sblock->page_count; index++) {
7a9e99876   Stefan Behrens   Btrfs: make the s...
2189
  		struct scrub_page *spage = sblock->pagev[index];
1bc877934   Arne Jansen   btrfs: scrub: don...
2190
  		int ret;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2191
  		ret = scrub_add_page_to_rd_bio(sctx, spage);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2192
2193
  		if (ret) {
  			scrub_block_put(sblock);
1bc877934   Arne Jansen   btrfs: scrub: don...
2194
  			return ret;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2195
  		}
1bc877934   Arne Jansen   btrfs: scrub: don...
2196
  	}
a2de733c7   Arne Jansen   btrfs: scrub
2197

b5d67f64f   Stefan Behrens   Btrfs: change scr...
2198
  	if (force)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2199
  		scrub_submit(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
2200

b5d67f64f   Stefan Behrens   Btrfs: change scr...
2201
2202
  	/* last one frees, either here or in bio completion for last page */
  	scrub_block_put(sblock);
a2de733c7   Arne Jansen   btrfs: scrub
2203
2204
  	return 0;
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2205
2206
2207
  static void scrub_bio_end_io(struct bio *bio, int err)
  {
  	struct scrub_bio *sbio = bio->bi_private;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2208
  	struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2209
2210
2211
  
  	sbio->err = err;
  	sbio->bio = bio;
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
2212
  	btrfs_queue_work(fs_info->scrub_workers, &sbio->work);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2213
2214
2215
2216
2217
  }
  
  static void scrub_bio_end_io_worker(struct btrfs_work *work)
  {
  	struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2218
  	struct scrub_ctx *sctx = sbio->sctx;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2219
  	int i;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2220
  	BUG_ON(sbio->page_count > SCRUB_PAGES_PER_RD_BIO);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
  	if (sbio->err) {
  		for (i = 0; i < sbio->page_count; i++) {
  			struct scrub_page *spage = sbio->pagev[i];
  
  			spage->io_error = 1;
  			spage->sblock->no_io_error_seen = 0;
  		}
  	}
  
  	/* now complete the scrub_block items that have all pages completed */
  	for (i = 0; i < sbio->page_count; i++) {
  		struct scrub_page *spage = sbio->pagev[i];
  		struct scrub_block *sblock = spage->sblock;
  
  		if (atomic_dec_and_test(&sblock->outstanding_pages))
  			scrub_block_complete(sblock);
  		scrub_block_put(sblock);
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2239
2240
  	bio_put(sbio->bio);
  	sbio->bio = NULL;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2241
2242
2243
2244
  	spin_lock(&sctx->list_lock);
  	sbio->next_free = sctx->first_free;
  	sctx->first_free = sbio->index;
  	spin_unlock(&sctx->list_lock);
ff023aac3   Stefan Behrens   Btrfs: add code t...
2245
2246
2247
2248
2249
2250
2251
  
  	if (sctx->is_dev_replace &&
  	    atomic_read(&sctx->wr_ctx.flush_all_writes)) {
  		mutex_lock(&sctx->wr_ctx.wr_lock);
  		scrub_wr_submit(sctx);
  		mutex_unlock(&sctx->wr_ctx.wr_lock);
  	}
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
2252
  	scrub_pending_bio_dec(sctx);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2253
  }
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
  static inline void __scrub_mark_bitmap(struct scrub_parity *sparity,
  				       unsigned long *bitmap,
  				       u64 start, u64 len)
  {
  	int offset;
  	int nsectors;
  	int sectorsize = sparity->sctx->dev_root->sectorsize;
  
  	if (len >= sparity->stripe_len) {
  		bitmap_set(bitmap, 0, sparity->nsectors);
  		return;
  	}
  
  	start -= sparity->logic_start;
  	offset = (int)do_div(start, sparity->stripe_len);
  	offset /= sectorsize;
  	nsectors = (int)len / sectorsize;
  
  	if (offset + nsectors <= sparity->nsectors) {
  		bitmap_set(bitmap, offset, nsectors);
  		return;
  	}
  
  	bitmap_set(bitmap, offset, sparity->nsectors - offset);
  	bitmap_set(bitmap, 0, nsectors - (sparity->nsectors - offset));
  }
  
  static inline void scrub_parity_mark_sectors_error(struct scrub_parity *sparity,
  						   u64 start, u64 len)
  {
  	__scrub_mark_bitmap(sparity, sparity->ebitmap, start, len);
  }
  
  static inline void scrub_parity_mark_sectors_data(struct scrub_parity *sparity,
  						  u64 start, u64 len)
  {
  	__scrub_mark_bitmap(sparity, sparity->dbitmap, start, len);
  }
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2292
2293
  static void scrub_block_complete(struct scrub_block *sblock)
  {
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2294
  	int corrupted = 0;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2295
  	if (!sblock->no_io_error_seen) {
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2296
  		corrupted = 1;
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2297
  		scrub_handle_errored_block(sblock);
ff023aac3   Stefan Behrens   Btrfs: add code t...
2298
2299
2300
2301
2302
2303
  	} else {
  		/*
  		 * if has checksum error, write via repair mechanism in
  		 * dev replace case, otherwise write here in dev replace
  		 * case.
  		 */
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2304
2305
  		corrupted = scrub_checksum(sblock);
  		if (!corrupted && sblock->sctx->is_dev_replace)
ff023aac3   Stefan Behrens   Btrfs: add code t...
2306
2307
  			scrub_write_block_to_dev_replace(sblock);
  	}
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2308
2309
2310
2311
2312
2313
2314
2315
2316
  
  	if (sblock->sparity && corrupted && !sblock->data_corrected) {
  		u64 start = sblock->pagev[0]->logical;
  		u64 end = sblock->pagev[sblock->page_count - 1]->logical +
  			  PAGE_SIZE;
  
  		scrub_parity_mark_sectors_error(sblock->sparity,
  						start, end - start);
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2317
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2318
  static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len,
a2de733c7   Arne Jansen   btrfs: scrub
2319
2320
2321
  			   u8 *csum)
  {
  	struct btrfs_ordered_sum *sum = NULL;
f51a4a182   Miao Xie   Btrfs: remove btr...
2322
  	unsigned long index;
a2de733c7   Arne Jansen   btrfs: scrub
2323
  	unsigned long num_sectors;
a2de733c7   Arne Jansen   btrfs: scrub
2324

d9d181c1b   Stefan Behrens   Btrfs: rename the...
2325
2326
  	while (!list_empty(&sctx->csum_list)) {
  		sum = list_first_entry(&sctx->csum_list,
a2de733c7   Arne Jansen   btrfs: scrub
2327
2328
2329
2330
2331
  				       struct btrfs_ordered_sum, list);
  		if (sum->bytenr > logical)
  			return 0;
  		if (sum->bytenr + sum->len > logical)
  			break;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2332
  		++sctx->stat.csum_discards;
a2de733c7   Arne Jansen   btrfs: scrub
2333
2334
2335
2336
2337
2338
  		list_del(&sum->list);
  		kfree(sum);
  		sum = NULL;
  	}
  	if (!sum)
  		return 0;
f51a4a182   Miao Xie   Btrfs: remove btr...
2339
  	index = ((u32)(logical - sum->bytenr)) / sctx->sectorsize;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2340
  	num_sectors = sum->len / sctx->sectorsize;
f51a4a182   Miao Xie   Btrfs: remove btr...
2341
2342
  	memcpy(csum, sum->sums + index, sctx->csum_size);
  	if (index == num_sectors - 1) {
a2de733c7   Arne Jansen   btrfs: scrub
2343
2344
2345
  		list_del(&sum->list);
  		kfree(sum);
  	}
f51a4a182   Miao Xie   Btrfs: remove btr...
2346
  	return 1;
a2de733c7   Arne Jansen   btrfs: scrub
2347
2348
2349
  }
  
  /* scrub extent tries to collect up to 64 kB for each bio */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2350
  static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2351
  			u64 physical, struct btrfs_device *dev, u64 flags,
ff023aac3   Stefan Behrens   Btrfs: add code t...
2352
  			u64 gen, int mirror_num, u64 physical_for_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
2353
2354
2355
  {
  	int ret;
  	u8 csum[BTRFS_CSUM_SIZE];
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2356
2357
2358
  	u32 blocksize;
  
  	if (flags & BTRFS_EXTENT_FLAG_DATA) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2359
2360
2361
2362
2363
  		blocksize = sctx->sectorsize;
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.data_extents_scrubbed++;
  		sctx->stat.data_bytes_scrubbed += len;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2364
  	} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2365
2366
2367
2368
2369
  		blocksize = sctx->nodesize;
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.tree_extents_scrubbed++;
  		sctx->stat.tree_bytes_scrubbed += len;
  		spin_unlock(&sctx->stat_lock);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2370
  	} else {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2371
  		blocksize = sctx->sectorsize;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2372
  		WARN_ON(1);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2373
  	}
a2de733c7   Arne Jansen   btrfs: scrub
2374
2375
  
  	while (len) {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2376
  		u64 l = min_t(u64, len, blocksize);
a2de733c7   Arne Jansen   btrfs: scrub
2377
2378
2379
2380
  		int have_csum = 0;
  
  		if (flags & BTRFS_EXTENT_FLAG_DATA) {
  			/* push csums to sbio */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2381
  			have_csum = scrub_find_csum(sctx, logical, l, csum);
a2de733c7   Arne Jansen   btrfs: scrub
2382
  			if (have_csum == 0)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2383
  				++sctx->stat.no_csum;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2384
2385
2386
2387
2388
2389
  			if (sctx->is_dev_replace && !have_csum) {
  				ret = copy_nocow_pages(sctx, logical, l,
  						       mirror_num,
  						      physical_for_dev_replace);
  				goto behind_scrub_pages;
  			}
a2de733c7   Arne Jansen   btrfs: scrub
2390
  		}
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2391
  		ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen,
ff023aac3   Stefan Behrens   Btrfs: add code t...
2392
2393
2394
  				  mirror_num, have_csum ? csum : NULL, 0,
  				  physical_for_dev_replace);
  behind_scrub_pages:
a2de733c7   Arne Jansen   btrfs: scrub
2395
2396
2397
2398
2399
  		if (ret)
  			return ret;
  		len -= l;
  		logical += l;
  		physical += l;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2400
  		physical_for_dev_replace += l;
a2de733c7   Arne Jansen   btrfs: scrub
2401
2402
2403
  	}
  	return 0;
  }
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
  static int scrub_pages_for_parity(struct scrub_parity *sparity,
  				  u64 logical, u64 len,
  				  u64 physical, struct btrfs_device *dev,
  				  u64 flags, u64 gen, int mirror_num, u8 *csum)
  {
  	struct scrub_ctx *sctx = sparity->sctx;
  	struct scrub_block *sblock;
  	int index;
  
  	sblock = kzalloc(sizeof(*sblock), GFP_NOFS);
  	if (!sblock) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
  		return -ENOMEM;
  	}
  
  	/* one ref inside this function, plus one for each page added to
  	 * a bio later on */
  	atomic_set(&sblock->ref_count, 1);
  	sblock->sctx = sctx;
  	sblock->no_io_error_seen = 1;
  	sblock->sparity = sparity;
  	scrub_parity_get(sparity);
  
  	for (index = 0; len > 0; index++) {
  		struct scrub_page *spage;
  		u64 l = min_t(u64, len, PAGE_SIZE);
  
  		spage = kzalloc(sizeof(*spage), GFP_NOFS);
  		if (!spage) {
  leave_nomem:
  			spin_lock(&sctx->stat_lock);
  			sctx->stat.malloc_errors++;
  			spin_unlock(&sctx->stat_lock);
  			scrub_block_put(sblock);
  			return -ENOMEM;
  		}
  		BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK);
  		/* For scrub block */
  		scrub_page_get(spage);
  		sblock->pagev[index] = spage;
  		/* For scrub parity */
  		scrub_page_get(spage);
  		list_add_tail(&spage->list, &sparity->spages);
  		spage->sblock = sblock;
  		spage->dev = dev;
  		spage->flags = flags;
  		spage->generation = gen;
  		spage->logical = logical;
  		spage->physical = physical;
  		spage->mirror_num = mirror_num;
  		if (csum) {
  			spage->have_csum = 1;
  			memcpy(spage->csum, csum, sctx->csum_size);
  		} else {
  			spage->have_csum = 0;
  		}
  		sblock->page_count++;
  		spage->page = alloc_page(GFP_NOFS);
  		if (!spage->page)
  			goto leave_nomem;
  		len -= l;
  		logical += l;
  		physical += l;
  	}
  
  	WARN_ON(sblock->page_count == 0);
  	for (index = 0; index < sblock->page_count; index++) {
  		struct scrub_page *spage = sblock->pagev[index];
  		int ret;
  
  		ret = scrub_add_page_to_rd_bio(sctx, spage);
  		if (ret) {
  			scrub_block_put(sblock);
  			return ret;
  		}
  	}
  
  	/* last one frees, either here or in bio completion for last page */
  	scrub_block_put(sblock);
  	return 0;
  }
  
  static int scrub_extent_for_parity(struct scrub_parity *sparity,
  				   u64 logical, u64 len,
  				   u64 physical, struct btrfs_device *dev,
  				   u64 flags, u64 gen, int mirror_num)
  {
  	struct scrub_ctx *sctx = sparity->sctx;
  	int ret;
  	u8 csum[BTRFS_CSUM_SIZE];
  	u32 blocksize;
  
  	if (flags & BTRFS_EXTENT_FLAG_DATA) {
  		blocksize = sctx->sectorsize;
  	} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
  		blocksize = sctx->nodesize;
  	} else {
  		blocksize = sctx->sectorsize;
  		WARN_ON(1);
  	}
  
  	while (len) {
  		u64 l = min_t(u64, len, blocksize);
  		int have_csum = 0;
  
  		if (flags & BTRFS_EXTENT_FLAG_DATA) {
  			/* push csums to sbio */
  			have_csum = scrub_find_csum(sctx, logical, l, csum);
  			if (have_csum == 0)
  				goto skip;
  		}
  		ret = scrub_pages_for_parity(sparity, logical, l, physical, dev,
  					     flags, gen, mirror_num,
  					     have_csum ? csum : NULL);
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2520
2521
  		if (ret)
  			return ret;
6b6d24b38   Dan Carpenter   Btrfs, scrub: uni...
2522
  skip:
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2523
2524
2525
2526
2527
2528
  		len -= l;
  		logical += l;
  		physical += l;
  	}
  	return 0;
  }
3b080b256   Wang Shilong   Btrfs: scrub raid...
2529
2530
2531
2532
2533
2534
2535
2536
  /*
   * Given a physical address, this will calculate it's
   * logical offset. if this is a parity stripe, it will return
   * the most left data stripe's logical offset.
   *
   * return 0 if it is a data stripe, 1 means parity stripe.
   */
  static int get_raid56_logic_offset(u64 physical, int num,
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2537
2538
  				   struct map_lookup *map, u64 *offset,
  				   u64 *stripe_start)
3b080b256   Wang Shilong   Btrfs: scrub raid...
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
  {
  	int i;
  	int j = 0;
  	u64 stripe_nr;
  	u64 last_offset;
  	int stripe_index;
  	int rot;
  
  	last_offset = (physical - map->stripes[num].physical) *
  		      nr_data_stripes(map);
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2549
2550
  	if (stripe_start)
  		*stripe_start = last_offset;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
  	*offset = last_offset;
  	for (i = 0; i < nr_data_stripes(map); i++) {
  		*offset = last_offset + i * map->stripe_len;
  
  		stripe_nr = *offset;
  		do_div(stripe_nr, map->stripe_len);
  		do_div(stripe_nr, nr_data_stripes(map));
  
  		/* Work out the disk rotation on this stripe-set */
  		rot = do_div(stripe_nr, map->num_stripes);
  		/* calculate which stripe this data locates */
  		rot += i;
e4fbaee29   Wang Shilong   Btrfs: fix compil...
2563
  		stripe_index = rot % map->num_stripes;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2564
2565
2566
2567
2568
2569
2570
2571
  		if (stripe_index == num)
  			return 0;
  		if (stripe_index < num)
  			j++;
  	}
  	*offset = last_offset + j * map->stripe_len;
  	return 1;
  }
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
  static void scrub_free_parity(struct scrub_parity *sparity)
  {
  	struct scrub_ctx *sctx = sparity->sctx;
  	struct scrub_page *curr, *next;
  	int nbits;
  
  	nbits = bitmap_weight(sparity->ebitmap, sparity->nsectors);
  	if (nbits) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.read_errors += nbits;
  		sctx->stat.uncorrectable_errors += nbits;
  		spin_unlock(&sctx->stat_lock);
  	}
  
  	list_for_each_entry_safe(curr, next, &sparity->spages, list) {
  		list_del_init(&curr->list);
  		scrub_page_put(curr);
  	}
  
  	kfree(sparity);
  }
  
  static void scrub_parity_bio_endio(struct bio *bio, int error)
  {
  	struct scrub_parity *sparity = (struct scrub_parity *)bio->bi_private;
  	struct scrub_ctx *sctx = sparity->sctx;
  
  	if (error)
  		bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap,
  			  sparity->nsectors);
  
  	scrub_free_parity(sparity);
  	scrub_pending_bio_dec(sctx);
  	bio_put(bio);
  }
  
  static void scrub_parity_check_and_repair(struct scrub_parity *sparity)
  {
  	struct scrub_ctx *sctx = sparity->sctx;
  	struct bio *bio;
  	struct btrfs_raid_bio *rbio;
  	struct scrub_page *spage;
  	struct btrfs_bio *bbio = NULL;
  	u64 *raid_map = NULL;
  	u64 length;
  	int ret;
  
  	if (!bitmap_andnot(sparity->dbitmap, sparity->dbitmap, sparity->ebitmap,
  			   sparity->nsectors))
  		goto out;
  
  	length = sparity->logic_end - sparity->logic_start + 1;
760359769   Miao Xie   Btrfs, replace: w...
2624
  	ret = btrfs_map_sblock(sctx->dev_root->fs_info, WRITE,
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
  			       sparity->logic_start,
  			       &length, &bbio, 0, &raid_map);
  	if (ret || !bbio || !raid_map)
  		goto bbio_out;
  
  	bio = btrfs_io_bio_alloc(GFP_NOFS, 0);
  	if (!bio)
  		goto bbio_out;
  
  	bio->bi_iter.bi_sector = sparity->logic_start >> 9;
  	bio->bi_private = sparity;
  	bio->bi_end_io = scrub_parity_bio_endio;
  
  	rbio = raid56_parity_alloc_scrub_rbio(sctx->dev_root, bio, bbio,
  					      raid_map, length,
  					      sparity->scrub_dev,
  					      sparity->dbitmap,
  					      sparity->nsectors);
  	if (!rbio)
  		goto rbio_out;
  
  	list_for_each_entry(spage, &sparity->spages, list)
  		raid56_parity_add_scrub_pages(rbio, spage->page,
  					      spage->logical);
  
  	scrub_pending_bio_inc(sctx);
  	raid56_parity_submit_scrub_rbio(rbio);
  	return;
  
  rbio_out:
  	bio_put(bio);
  bbio_out:
  	kfree(bbio);
  	kfree(raid_map);
  	bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap,
  		  sparity->nsectors);
  	spin_lock(&sctx->stat_lock);
  	sctx->stat.malloc_errors++;
  	spin_unlock(&sctx->stat_lock);
  out:
  	scrub_free_parity(sparity);
  }
  
  static inline int scrub_calc_parity_bitmap_len(int nsectors)
  {
  	return DIV_ROUND_UP(nsectors, BITS_PER_LONG) * (BITS_PER_LONG / 8);
  }
  
  static void scrub_parity_get(struct scrub_parity *sparity)
  {
  	atomic_inc(&sparity->ref_count);
  }
  
  static void scrub_parity_put(struct scrub_parity *sparity)
  {
  	if (!atomic_dec_and_test(&sparity->ref_count))
  		return;
  
  	scrub_parity_check_and_repair(sparity);
  }
  
  static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx,
  						  struct map_lookup *map,
  						  struct btrfs_device *sdev,
  						  struct btrfs_path *path,
  						  u64 logic_start,
  						  u64 logic_end)
  {
  	struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
  	struct btrfs_root *root = fs_info->extent_root;
  	struct btrfs_root *csum_root = fs_info->csum_root;
  	struct btrfs_extent_item *extent;
  	u64 flags;
  	int ret;
  	int slot;
  	struct extent_buffer *l;
  	struct btrfs_key key;
  	u64 generation;
  	u64 extent_logical;
  	u64 extent_physical;
  	u64 extent_len;
  	struct btrfs_device *extent_dev;
  	struct scrub_parity *sparity;
  	int nsectors;
  	int bitmap_len;
  	int extent_mirror_num;
  	int stop_loop = 0;
  
  	nsectors = map->stripe_len / root->sectorsize;
  	bitmap_len = scrub_calc_parity_bitmap_len(nsectors);
  	sparity = kzalloc(sizeof(struct scrub_parity) + 2 * bitmap_len,
  			  GFP_NOFS);
  	if (!sparity) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
  		return -ENOMEM;
  	}
  
  	sparity->stripe_len = map->stripe_len;
  	sparity->nsectors = nsectors;
  	sparity->sctx = sctx;
  	sparity->scrub_dev = sdev;
  	sparity->logic_start = logic_start;
  	sparity->logic_end = logic_end;
  	atomic_set(&sparity->ref_count, 1);
  	INIT_LIST_HEAD(&sparity->spages);
  	sparity->dbitmap = sparity->bitmap;
  	sparity->ebitmap = (void *)sparity->bitmap + bitmap_len;
  
  	ret = 0;
  	while (logic_start < logic_end) {
  		if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
  			key.type = BTRFS_METADATA_ITEM_KEY;
  		else
  			key.type = BTRFS_EXTENT_ITEM_KEY;
  		key.objectid = logic_start;
  		key.offset = (u64)-1;
  
  		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
  		if (ret < 0)
  			goto out;
  
  		if (ret > 0) {
  			ret = btrfs_previous_extent_item(root, path, 0);
  			if (ret < 0)
  				goto out;
  			if (ret > 0) {
  				btrfs_release_path(path);
  				ret = btrfs_search_slot(NULL, root, &key,
  							path, 0, 0);
  				if (ret < 0)
  					goto out;
  			}
  		}
  
  		stop_loop = 0;
  		while (1) {
  			u64 bytes;
  
  			l = path->nodes[0];
  			slot = path->slots[0];
  			if (slot >= btrfs_header_nritems(l)) {
  				ret = btrfs_next_leaf(root, path);
  				if (ret == 0)
  					continue;
  				if (ret < 0)
  					goto out;
  
  				stop_loop = 1;
  				break;
  			}
  			btrfs_item_key_to_cpu(l, &key, slot);
  
  			if (key.type == BTRFS_METADATA_ITEM_KEY)
  				bytes = root->nodesize;
  			else
  				bytes = key.offset;
  
  			if (key.objectid + bytes <= logic_start)
  				goto next;
  
  			if (key.type != BTRFS_EXTENT_ITEM_KEY &&
  			    key.type != BTRFS_METADATA_ITEM_KEY)
  				goto next;
  
  			if (key.objectid > logic_end) {
  				stop_loop = 1;
  				break;
  			}
  
  			while (key.objectid >= logic_start + map->stripe_len)
  				logic_start += map->stripe_len;
  
  			extent = btrfs_item_ptr(l, slot,
  						struct btrfs_extent_item);
  			flags = btrfs_extent_flags(l, extent);
  			generation = btrfs_extent_generation(l, extent);
  
  			if (key.objectid < logic_start &&
  			    (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) {
  				btrfs_err(fs_info,
  					  "scrub: tree block %llu spanning stripes, ignored. logical=%llu",
  					   key.objectid, logic_start);
  				goto next;
  			}
  again:
  			extent_logical = key.objectid;
  			extent_len = bytes;
  
  			if (extent_logical < logic_start) {
  				extent_len -= logic_start - extent_logical;
  				extent_logical = logic_start;
  			}
  
  			if (extent_logical + extent_len >
  			    logic_start + map->stripe_len)
  				extent_len = logic_start + map->stripe_len -
  					     extent_logical;
  
  			scrub_parity_mark_sectors_data(sparity, extent_logical,
  						       extent_len);
  
  			scrub_remap_extent(fs_info, extent_logical,
  					   extent_len, &extent_physical,
  					   &extent_dev,
  					   &extent_mirror_num);
  
  			ret = btrfs_lookup_csums_range(csum_root,
  						extent_logical,
  						extent_logical + extent_len - 1,
  						&sctx->csum_list, 1);
  			if (ret)
  				goto out;
  
  			ret = scrub_extent_for_parity(sparity, extent_logical,
  						      extent_len,
  						      extent_physical,
  						      extent_dev, flags,
  						      generation,
  						      extent_mirror_num);
  			if (ret)
  				goto out;
  
  			scrub_free_csums(sctx);
  			if (extent_logical + extent_len <
  			    key.objectid + bytes) {
  				logic_start += map->stripe_len;
  
  				if (logic_start >= logic_end) {
  					stop_loop = 1;
  					break;
  				}
  
  				if (logic_start < key.objectid + bytes) {
  					cond_resched();
  					goto again;
  				}
  			}
  next:
  			path->slots[0]++;
  		}
  
  		btrfs_release_path(path);
  
  		if (stop_loop)
  			break;
  
  		logic_start += map->stripe_len;
  	}
  out:
  	if (ret < 0)
  		scrub_parity_mark_sectors_error(sparity, logic_start,
  						logic_end - logic_start + 1);
  	scrub_parity_put(sparity);
  	scrub_submit(sctx);
  	mutex_lock(&sctx->wr_ctx.wr_lock);
  	scrub_wr_submit(sctx);
  	mutex_unlock(&sctx->wr_ctx.wr_lock);
  
  	btrfs_release_path(path);
  	return ret < 0 ? ret : 0;
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2888
  static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2889
2890
  					   struct map_lookup *map,
  					   struct btrfs_device *scrub_dev,
ff023aac3   Stefan Behrens   Btrfs: add code t...
2891
2892
  					   int num, u64 base, u64 length,
  					   int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
2893
  {
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2894
  	struct btrfs_path *path, *ppath;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
2895
  	struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
a2de733c7   Arne Jansen   btrfs: scrub
2896
2897
2898
  	struct btrfs_root *root = fs_info->extent_root;
  	struct btrfs_root *csum_root = fs_info->csum_root;
  	struct btrfs_extent_item *extent;
e7786c3ae   Arne Jansen   btrfs: scrub: add...
2899
  	struct blk_plug plug;
a2de733c7   Arne Jansen   btrfs: scrub
2900
2901
2902
  	u64 flags;
  	int ret;
  	int slot;
a2de733c7   Arne Jansen   btrfs: scrub
2903
  	u64 nstripes;
a2de733c7   Arne Jansen   btrfs: scrub
2904
2905
2906
2907
  	struct extent_buffer *l;
  	struct btrfs_key key;
  	u64 physical;
  	u64 logical;
625f1c8dc   Liu Bo   Btrfs: improve th...
2908
  	u64 logic_end;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2909
  	u64 physical_end;
a2de733c7   Arne Jansen   btrfs: scrub
2910
  	u64 generation;
e12fa9cd3   Jan Schmidt   btrfs scrub: use ...
2911
  	int mirror_num;
7a26285ee   Arne Jansen   btrfs: use readah...
2912
2913
2914
2915
  	struct reada_control *reada1;
  	struct reada_control *reada2;
  	struct btrfs_key key_start;
  	struct btrfs_key key_end;
a2de733c7   Arne Jansen   btrfs: scrub
2916
2917
  	u64 increment = map->stripe_len;
  	u64 offset;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2918
2919
2920
  	u64 extent_logical;
  	u64 extent_physical;
  	u64 extent_len;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2921
2922
  	u64 stripe_logical;
  	u64 stripe_end;
ff023aac3   Stefan Behrens   Btrfs: add code t...
2923
2924
  	struct btrfs_device *extent_dev;
  	int extent_mirror_num;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2925
  	int stop_loop = 0;
53b381b3a   David Woodhouse   Btrfs: RAID5 and ...
2926

a2de733c7   Arne Jansen   btrfs: scrub
2927
  	nstripes = length;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2928
  	physical = map->stripes[num].physical;
a2de733c7   Arne Jansen   btrfs: scrub
2929
2930
2931
2932
2933
  	offset = 0;
  	do_div(nstripes, map->stripe_len);
  	if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
  		offset = map->stripe_len * num;
  		increment = map->stripe_len * map->num_stripes;
193ea74b2   Jan Schmidt   btrfs scrub: bugf...
2934
  		mirror_num = 1;
a2de733c7   Arne Jansen   btrfs: scrub
2935
2936
2937
2938
  	} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
  		int factor = map->num_stripes / map->sub_stripes;
  		offset = map->stripe_len * (num / map->sub_stripes);
  		increment = map->stripe_len * factor;
193ea74b2   Jan Schmidt   btrfs scrub: bugf...
2939
  		mirror_num = num % map->sub_stripes + 1;
a2de733c7   Arne Jansen   btrfs: scrub
2940
2941
  	} else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
  		increment = map->stripe_len;
193ea74b2   Jan Schmidt   btrfs scrub: bugf...
2942
  		mirror_num = num % map->num_stripes + 1;
a2de733c7   Arne Jansen   btrfs: scrub
2943
2944
  	} else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
  		increment = map->stripe_len;
193ea74b2   Jan Schmidt   btrfs scrub: bugf...
2945
  		mirror_num = num % map->num_stripes + 1;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2946
2947
  	} else if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
  				BTRFS_BLOCK_GROUP_RAID6)) {
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2948
  		get_raid56_logic_offset(physical, num, map, &offset, NULL);
3b080b256   Wang Shilong   Btrfs: scrub raid...
2949
2950
  		increment = map->stripe_len * nr_data_stripes(map);
  		mirror_num = 1;
a2de733c7   Arne Jansen   btrfs: scrub
2951
2952
  	} else {
  		increment = map->stripe_len;
193ea74b2   Jan Schmidt   btrfs scrub: bugf...
2953
  		mirror_num = 1;
a2de733c7   Arne Jansen   btrfs: scrub
2954
2955
2956
2957
2958
  	}
  
  	path = btrfs_alloc_path();
  	if (!path)
  		return -ENOMEM;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2959
2960
2961
2962
2963
  	ppath = btrfs_alloc_path();
  	if (!ppath) {
  		btrfs_free_path(ppath);
  		return -ENOMEM;
  	}
b5d67f64f   Stefan Behrens   Btrfs: change scr...
2964
2965
2966
2967
2968
  	/*
  	 * work on commit root. The related disk blocks are static as
  	 * long as COW is applied. This means, it is save to rewrite
  	 * them to repair disk errors without any race conditions
  	 */
a2de733c7   Arne Jansen   btrfs: scrub
2969
2970
2971
2972
  	path->search_commit_root = 1;
  	path->skip_locking = 1;
  
  	/*
7a26285ee   Arne Jansen   btrfs: use readah...
2973
2974
2975
  	 * trigger the readahead for extent tree csum tree and wait for
  	 * completion. During readahead, the scrub is officially paused
  	 * to not hold off transaction commits
a2de733c7   Arne Jansen   btrfs: scrub
2976
2977
  	 */
  	logical = base + offset;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2978
2979
2980
2981
  	physical_end = physical + nstripes * map->stripe_len;
  	if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
  			 BTRFS_BLOCK_GROUP_RAID6)) {
  		get_raid56_logic_offset(physical_end, num,
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
2982
  					map, &logic_end, NULL);
3b080b256   Wang Shilong   Btrfs: scrub raid...
2983
2984
2985
2986
  		logic_end += base;
  	} else {
  		logic_end = logical + increment * nstripes;
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
2987
  	wait_event(sctx->list_wait,
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
2988
  		   atomic_read(&sctx->bios_in_flight) == 0);
cb7ab0215   Wang Shilong   Btrfs: wrap repea...
2989
  	scrub_blocked_if_needed(fs_info);
7a26285ee   Arne Jansen   btrfs: use readah...
2990
2991
2992
2993
2994
  
  	/* FIXME it might be better to start readahead at commit root */
  	key_start.objectid = logical;
  	key_start.type = BTRFS_EXTENT_ITEM_KEY;
  	key_start.offset = (u64)0;
3b080b256   Wang Shilong   Btrfs: scrub raid...
2995
  	key_end.objectid = logic_end;
3173a18f7   Josef Bacik   Btrfs: add a inco...
2996
2997
  	key_end.type = BTRFS_METADATA_ITEM_KEY;
  	key_end.offset = (u64)-1;
7a26285ee   Arne Jansen   btrfs: use readah...
2998
2999
3000
3001
3002
3003
3004
  	reada1 = btrfs_reada_add(root, &key_start, &key_end);
  
  	key_start.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
  	key_start.type = BTRFS_EXTENT_CSUM_KEY;
  	key_start.offset = logical;
  	key_end.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
  	key_end.type = BTRFS_EXTENT_CSUM_KEY;
3b080b256   Wang Shilong   Btrfs: scrub raid...
3005
  	key_end.offset = logic_end;
7a26285ee   Arne Jansen   btrfs: use readah...
3006
3007
3008
3009
3010
3011
  	reada2 = btrfs_reada_add(csum_root, &key_start, &key_end);
  
  	if (!IS_ERR(reada1))
  		btrfs_reada_wait(reada1);
  	if (!IS_ERR(reada2))
  		btrfs_reada_wait(reada2);
a2de733c7   Arne Jansen   btrfs: scrub
3012
3013
3014
3015
3016
  
  	/*
  	 * collect all data csums for the stripe to avoid seeking during
  	 * the scrub. This might currently (crc32) end up to be about 1MB
  	 */
e7786c3ae   Arne Jansen   btrfs: scrub: add...
3017
  	blk_start_plug(&plug);
a2de733c7   Arne Jansen   btrfs: scrub
3018

a2de733c7   Arne Jansen   btrfs: scrub
3019
3020
3021
  	/*
  	 * now find all extents for each stripe and scrub them
  	 */
a2de733c7   Arne Jansen   btrfs: scrub
3022
  	ret = 0;
3b080b256   Wang Shilong   Btrfs: scrub raid...
3023
3024
3025
3026
3027
  	while (physical < physical_end) {
  		/* for raid56, we skip parity stripe */
  		if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
  				BTRFS_BLOCK_GROUP_RAID6)) {
  			ret = get_raid56_logic_offset(physical, num,
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
3028
  					map, &logical, &stripe_logical);
3b080b256   Wang Shilong   Btrfs: scrub raid...
3029
  			logical += base;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
3030
3031
3032
3033
3034
3035
3036
3037
  			if (ret) {
  				stripe_logical += base;
  				stripe_end = stripe_logical + increment - 1;
  				ret = scrub_raid56_parity(sctx, map, scrub_dev,
  						ppath, stripe_logical,
  						stripe_end);
  				if (ret)
  					goto out;
3b080b256   Wang Shilong   Btrfs: scrub raid...
3038
  				goto skip;
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
3039
  			}
3b080b256   Wang Shilong   Btrfs: scrub raid...
3040
  		}
a2de733c7   Arne Jansen   btrfs: scrub
3041
3042
3043
3044
  		/*
  		 * canceled?
  		 */
  		if (atomic_read(&fs_info->scrub_cancel_req) ||
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3045
  		    atomic_read(&sctx->cancel_req)) {
a2de733c7   Arne Jansen   btrfs: scrub
3046
3047
3048
3049
3050
3051
3052
3053
  			ret = -ECANCELED;
  			goto out;
  		}
  		/*
  		 * check to see if we have to pause
  		 */
  		if (atomic_read(&fs_info->scrub_pause_req)) {
  			/* push queued extents */
ff023aac3   Stefan Behrens   Btrfs: add code t...
3054
  			atomic_set(&sctx->wr_ctx.flush_all_writes, 1);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3055
  			scrub_submit(sctx);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3056
3057
3058
  			mutex_lock(&sctx->wr_ctx.wr_lock);
  			scrub_wr_submit(sctx);
  			mutex_unlock(&sctx->wr_ctx.wr_lock);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3059
  			wait_event(sctx->list_wait,
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
3060
  				   atomic_read(&sctx->bios_in_flight) == 0);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3061
  			atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
3062
  			scrub_blocked_if_needed(fs_info);
a2de733c7   Arne Jansen   btrfs: scrub
3063
  		}
7c76edb77   Wang Shilong   Btrfs: fix missin...
3064
3065
3066
3067
  		if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
  			key.type = BTRFS_METADATA_ITEM_KEY;
  		else
  			key.type = BTRFS_EXTENT_ITEM_KEY;
a2de733c7   Arne Jansen   btrfs: scrub
3068
  		key.objectid = logical;
625f1c8dc   Liu Bo   Btrfs: improve th...
3069
  		key.offset = (u64)-1;
a2de733c7   Arne Jansen   btrfs: scrub
3070
3071
3072
3073
  
  		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
  		if (ret < 0)
  			goto out;
3173a18f7   Josef Bacik   Btrfs: add a inco...
3074

8c51032f9   Arne Jansen   btrfs: scrub: err...
3075
  		if (ret > 0) {
ade2e0b3e   Wang Shilong   Btrfs: fix to sea...
3076
  			ret = btrfs_previous_extent_item(root, path, 0);
a2de733c7   Arne Jansen   btrfs: scrub
3077
3078
  			if (ret < 0)
  				goto out;
8c51032f9   Arne Jansen   btrfs: scrub: err...
3079
3080
3081
3082
3083
3084
3085
3086
3087
  			if (ret > 0) {
  				/* there's no smaller item, so stick with the
  				 * larger one */
  				btrfs_release_path(path);
  				ret = btrfs_search_slot(NULL, root, &key,
  							path, 0, 0);
  				if (ret < 0)
  					goto out;
  			}
a2de733c7   Arne Jansen   btrfs: scrub
3088
  		}
625f1c8dc   Liu Bo   Btrfs: improve th...
3089
  		stop_loop = 0;
a2de733c7   Arne Jansen   btrfs: scrub
3090
  		while (1) {
3173a18f7   Josef Bacik   Btrfs: add a inco...
3091
  			u64 bytes;
a2de733c7   Arne Jansen   btrfs: scrub
3092
3093
3094
3095
3096
3097
3098
3099
  			l = path->nodes[0];
  			slot = path->slots[0];
  			if (slot >= btrfs_header_nritems(l)) {
  				ret = btrfs_next_leaf(root, path);
  				if (ret == 0)
  					continue;
  				if (ret < 0)
  					goto out;
625f1c8dc   Liu Bo   Btrfs: improve th...
3100
  				stop_loop = 1;
a2de733c7   Arne Jansen   btrfs: scrub
3101
3102
3103
  				break;
  			}
  			btrfs_item_key_to_cpu(l, &key, slot);
3173a18f7   Josef Bacik   Btrfs: add a inco...
3104
  			if (key.type == BTRFS_METADATA_ITEM_KEY)
707e8a071   David Sterba   btrfs: use nodesi...
3105
  				bytes = root->nodesize;
3173a18f7   Josef Bacik   Btrfs: add a inco...
3106
3107
3108
3109
  			else
  				bytes = key.offset;
  
  			if (key.objectid + bytes <= logical)
a2de733c7   Arne Jansen   btrfs: scrub
3110
  				goto next;
625f1c8dc   Liu Bo   Btrfs: improve th...
3111
3112
3113
  			if (key.type != BTRFS_EXTENT_ITEM_KEY &&
  			    key.type != BTRFS_METADATA_ITEM_KEY)
  				goto next;
a2de733c7   Arne Jansen   btrfs: scrub
3114

625f1c8dc   Liu Bo   Btrfs: improve th...
3115
3116
3117
3118
3119
3120
  			if (key.objectid >= logical + map->stripe_len) {
  				/* out of this device extent */
  				if (key.objectid >= logic_end)
  					stop_loop = 1;
  				break;
  			}
a2de733c7   Arne Jansen   btrfs: scrub
3121
3122
3123
3124
3125
3126
3127
3128
  
  			extent = btrfs_item_ptr(l, slot,
  						struct btrfs_extent_item);
  			flags = btrfs_extent_flags(l, extent);
  			generation = btrfs_extent_generation(l, extent);
  
  			if (key.objectid < logical &&
  			    (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) {
efe120a06   Frank Holton   Btrfs: convert pr...
3129
3130
3131
  				btrfs_err(fs_info,
  					   "scrub: tree block %llu spanning "
  					   "stripes, ignored. logical=%llu",
c1c9ff7c9   Geert Uytterhoeven   Btrfs: Remove sup...
3132
  				       key.objectid, logical);
a2de733c7   Arne Jansen   btrfs: scrub
3133
3134
  				goto next;
  			}
625f1c8dc   Liu Bo   Btrfs: improve th...
3135
3136
3137
  again:
  			extent_logical = key.objectid;
  			extent_len = bytes;
a2de733c7   Arne Jansen   btrfs: scrub
3138
3139
3140
  			/*
  			 * trim extent to this stripe
  			 */
625f1c8dc   Liu Bo   Btrfs: improve th...
3141
3142
3143
  			if (extent_logical < logical) {
  				extent_len -= logical - extent_logical;
  				extent_logical = logical;
a2de733c7   Arne Jansen   btrfs: scrub
3144
  			}
625f1c8dc   Liu Bo   Btrfs: improve th...
3145
  			if (extent_logical + extent_len >
a2de733c7   Arne Jansen   btrfs: scrub
3146
  			    logical + map->stripe_len) {
625f1c8dc   Liu Bo   Btrfs: improve th...
3147
3148
  				extent_len = logical + map->stripe_len -
  					     extent_logical;
a2de733c7   Arne Jansen   btrfs: scrub
3149
  			}
625f1c8dc   Liu Bo   Btrfs: improve th...
3150
  			extent_physical = extent_logical - logical + physical;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3151
3152
3153
3154
3155
3156
3157
  			extent_dev = scrub_dev;
  			extent_mirror_num = mirror_num;
  			if (is_dev_replace)
  				scrub_remap_extent(fs_info, extent_logical,
  						   extent_len, &extent_physical,
  						   &extent_dev,
  						   &extent_mirror_num);
625f1c8dc   Liu Bo   Btrfs: improve th...
3158
3159
3160
3161
3162
3163
  
  			ret = btrfs_lookup_csums_range(csum_root, logical,
  						logical + map->stripe_len - 1,
  						&sctx->csum_list, 1);
  			if (ret)
  				goto out;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3164
3165
3166
  			ret = scrub_extent(sctx, extent_logical, extent_len,
  					   extent_physical, extent_dev, flags,
  					   generation, extent_mirror_num,
115930cb2   Stefan Behrens   Btrfs: fix wrong ...
3167
  					   extent_logical - logical + physical);
a2de733c7   Arne Jansen   btrfs: scrub
3168
3169
  			if (ret)
  				goto out;
d88d46c6e   Josef Bacik   Btrfs: free csums...
3170
  			scrub_free_csums(sctx);
625f1c8dc   Liu Bo   Btrfs: improve th...
3171
3172
  			if (extent_logical + extent_len <
  			    key.objectid + bytes) {
3b080b256   Wang Shilong   Btrfs: scrub raid...
3173
3174
3175
3176
3177
3178
  				if (map->type & (BTRFS_BLOCK_GROUP_RAID5 |
  					BTRFS_BLOCK_GROUP_RAID6)) {
  					/*
  					 * loop until we find next data stripe
  					 * or we have finished all stripes.
  					 */
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
  loop:
  					physical += map->stripe_len;
  					ret = get_raid56_logic_offset(physical,
  							num, map, &logical,
  							&stripe_logical);
  					logical += base;
  
  					if (ret && physical < physical_end) {
  						stripe_logical += base;
  						stripe_end = stripe_logical +
  								increment - 1;
  						ret = scrub_raid56_parity(sctx,
  							map, scrub_dev, ppath,
  							stripe_logical,
  							stripe_end);
  						if (ret)
  							goto out;
  						goto loop;
  					}
3b080b256   Wang Shilong   Btrfs: scrub raid...
3198
3199
3200
3201
  				} else {
  					physical += map->stripe_len;
  					logical += increment;
  				}
625f1c8dc   Liu Bo   Btrfs: improve th...
3202
3203
3204
3205
  				if (logical < key.objectid + bytes) {
  					cond_resched();
  					goto again;
  				}
3b080b256   Wang Shilong   Btrfs: scrub raid...
3206
  				if (physical >= physical_end) {
625f1c8dc   Liu Bo   Btrfs: improve th...
3207
3208
3209
3210
  					stop_loop = 1;
  					break;
  				}
  			}
a2de733c7   Arne Jansen   btrfs: scrub
3211
3212
3213
  next:
  			path->slots[0]++;
  		}
712673339   Chris Mason   Merge branch 'for...
3214
  		btrfs_release_path(path);
3b080b256   Wang Shilong   Btrfs: scrub raid...
3215
  skip:
a2de733c7   Arne Jansen   btrfs: scrub
3216
3217
  		logical += increment;
  		physical += map->stripe_len;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3218
  		spin_lock(&sctx->stat_lock);
625f1c8dc   Liu Bo   Btrfs: improve th...
3219
3220
3221
3222
3223
  		if (stop_loop)
  			sctx->stat.last_physical = map->stripes[num].physical +
  						   length;
  		else
  			sctx->stat.last_physical = physical;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3224
  		spin_unlock(&sctx->stat_lock);
625f1c8dc   Liu Bo   Btrfs: improve th...
3225
3226
  		if (stop_loop)
  			break;
a2de733c7   Arne Jansen   btrfs: scrub
3227
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
3228
  out:
a2de733c7   Arne Jansen   btrfs: scrub
3229
  	/* push queued extents */
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3230
  	scrub_submit(sctx);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3231
3232
3233
  	mutex_lock(&sctx->wr_ctx.wr_lock);
  	scrub_wr_submit(sctx);
  	mutex_unlock(&sctx->wr_ctx.wr_lock);
a2de733c7   Arne Jansen   btrfs: scrub
3234

e7786c3ae   Arne Jansen   btrfs: scrub: add...
3235
  	blk_finish_plug(&plug);
a2de733c7   Arne Jansen   btrfs: scrub
3236
  	btrfs_free_path(path);
5a6ac9eac   Miao Xie   Btrfs, raid56: su...
3237
  	btrfs_free_path(ppath);
a2de733c7   Arne Jansen   btrfs: scrub
3238
3239
  	return ret < 0 ? ret : 0;
  }
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3240
  static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3241
3242
3243
  					  struct btrfs_device *scrub_dev,
  					  u64 chunk_tree, u64 chunk_objectid,
  					  u64 chunk_offset, u64 length,
ff023aac3   Stefan Behrens   Btrfs: add code t...
3244
  					  u64 dev_offset, int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
3245
3246
  {
  	struct btrfs_mapping_tree *map_tree =
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3247
  		&sctx->dev_root->fs_info->mapping_tree;
a2de733c7   Arne Jansen   btrfs: scrub
3248
3249
3250
  	struct map_lookup *map;
  	struct extent_map *em;
  	int i;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3251
  	int ret = 0;
a2de733c7   Arne Jansen   btrfs: scrub
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
  
  	read_lock(&map_tree->map_tree.lock);
  	em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
  	read_unlock(&map_tree->map_tree.lock);
  
  	if (!em)
  		return -EINVAL;
  
  	map = (struct map_lookup *)em->bdev;
  	if (em->start != chunk_offset)
  		goto out;
  
  	if (em->len < length)
  		goto out;
  
  	for (i = 0; i < map->num_stripes; ++i) {
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3268
  		if (map->stripes[i].dev->bdev == scrub_dev->bdev &&
859acaf1a   Arne Jansen   btrfs: don't chec...
3269
  		    map->stripes[i].physical == dev_offset) {
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3270
  			ret = scrub_stripe(sctx, map, scrub_dev, i,
ff023aac3   Stefan Behrens   Btrfs: add code t...
3271
3272
  					   chunk_offset, length,
  					   is_dev_replace);
a2de733c7   Arne Jansen   btrfs: scrub
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
  			if (ret)
  				goto out;
  		}
  	}
  out:
  	free_extent_map(em);
  
  	return ret;
  }
  
  static noinline_for_stack
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3284
  int scrub_enumerate_chunks(struct scrub_ctx *sctx,
ff023aac3   Stefan Behrens   Btrfs: add code t...
3285
3286
  			   struct btrfs_device *scrub_dev, u64 start, u64 end,
  			   int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
3287
3288
3289
  {
  	struct btrfs_dev_extent *dev_extent = NULL;
  	struct btrfs_path *path;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3290
  	struct btrfs_root *root = sctx->dev_root;
a2de733c7   Arne Jansen   btrfs: scrub
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
  	struct btrfs_fs_info *fs_info = root->fs_info;
  	u64 length;
  	u64 chunk_tree;
  	u64 chunk_objectid;
  	u64 chunk_offset;
  	int ret;
  	int slot;
  	struct extent_buffer *l;
  	struct btrfs_key key;
  	struct btrfs_key found_key;
  	struct btrfs_block_group_cache *cache;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3302
  	struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
a2de733c7   Arne Jansen   btrfs: scrub
3303
3304
3305
3306
3307
3308
3309
3310
  
  	path = btrfs_alloc_path();
  	if (!path)
  		return -ENOMEM;
  
  	path->reada = 2;
  	path->search_commit_root = 1;
  	path->skip_locking = 1;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3311
  	key.objectid = scrub_dev->devid;
a2de733c7   Arne Jansen   btrfs: scrub
3312
3313
  	key.offset = 0ull;
  	key.type = BTRFS_DEV_EXTENT_KEY;
a2de733c7   Arne Jansen   btrfs: scrub
3314
3315
3316
  	while (1) {
  		ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
  		if (ret < 0)
8c51032f9   Arne Jansen   btrfs: scrub: err...
3317
3318
3319
3320
3321
3322
3323
3324
3325
  			break;
  		if (ret > 0) {
  			if (path->slots[0] >=
  			    btrfs_header_nritems(path->nodes[0])) {
  				ret = btrfs_next_leaf(root, path);
  				if (ret)
  					break;
  			}
  		}
a2de733c7   Arne Jansen   btrfs: scrub
3326
3327
3328
3329
3330
  
  		l = path->nodes[0];
  		slot = path->slots[0];
  
  		btrfs_item_key_to_cpu(l, &found_key, slot);
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3331
  		if (found_key.objectid != scrub_dev->devid)
a2de733c7   Arne Jansen   btrfs: scrub
3332
  			break;
962a298f3   David Sterba   btrfs: kill the k...
3333
  		if (found_key.type != BTRFS_DEV_EXTENT_KEY)
a2de733c7   Arne Jansen   btrfs: scrub
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
  			break;
  
  		if (found_key.offset >= end)
  			break;
  
  		if (found_key.offset < key.offset)
  			break;
  
  		dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
  		length = btrfs_dev_extent_length(l, dev_extent);
ced96edc4   Qu Wenruo   btrfs: Skip scrub...
3344
3345
  		if (found_key.offset + length <= start)
  			goto skip;
a2de733c7   Arne Jansen   btrfs: scrub
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
  
  		chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
  		chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
  		chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
  
  		/*
  		 * get a reference on the corresponding block group to prevent
  		 * the chunk from going away while we scrub it
  		 */
  		cache = btrfs_lookup_block_group(fs_info, chunk_offset);
ced96edc4   Qu Wenruo   btrfs: Skip scrub...
3356
3357
3358
3359
3360
  
  		/* some chunks are removed but not committed to disk yet,
  		 * continue scrubbing */
  		if (!cache)
  			goto skip;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3361
3362
3363
  		dev_replace->cursor_right = found_key.offset + length;
  		dev_replace->cursor_left = found_key.offset;
  		dev_replace->item_needs_writeback = 1;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3364
  		ret = scrub_chunk(sctx, scrub_dev, chunk_tree, chunk_objectid,
ff023aac3   Stefan Behrens   Btrfs: add code t...
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
  				  chunk_offset, length, found_key.offset,
  				  is_dev_replace);
  
  		/*
  		 * flush, submit all pending read and write bios, afterwards
  		 * wait for them.
  		 * Note that in the dev replace case, a read request causes
  		 * write requests that are submitted in the read completion
  		 * worker. Therefore in the current situation, it is required
  		 * that all write requests are flushed, so that all read and
  		 * write requests are really completed when bios_in_flight
  		 * changes to 0.
  		 */
  		atomic_set(&sctx->wr_ctx.flush_all_writes, 1);
  		scrub_submit(sctx);
  		mutex_lock(&sctx->wr_ctx.wr_lock);
  		scrub_wr_submit(sctx);
  		mutex_unlock(&sctx->wr_ctx.wr_lock);
  
  		wait_event(sctx->list_wait,
  			   atomic_read(&sctx->bios_in_flight) == 0);
12cf93728   Wang Shilong   Btrfs: device_rep...
3386
3387
3388
3389
3390
3391
3392
3393
  		atomic_inc(&fs_info->scrubs_paused);
  		wake_up(&fs_info->scrub_pause_wait);
  
  		/*
  		 * must be called before we decrease @scrub_paused.
  		 * make sure we don't block transaction commit while
  		 * we are waiting pending workers finished.
  		 */
ff023aac3   Stefan Behrens   Btrfs: add code t...
3394
3395
  		wait_event(sctx->list_wait,
  			   atomic_read(&sctx->workers_pending) == 0);
12cf93728   Wang Shilong   Btrfs: device_rep...
3396
3397
3398
3399
3400
3401
3402
  		atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
  
  		mutex_lock(&fs_info->scrub_lock);
  		__scrub_blocked_if_needed(fs_info);
  		atomic_dec(&fs_info->scrubs_paused);
  		mutex_unlock(&fs_info->scrub_lock);
  		wake_up(&fs_info->scrub_pause_wait);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3403

a2de733c7   Arne Jansen   btrfs: scrub
3404
3405
3406
  		btrfs_put_block_group(cache);
  		if (ret)
  			break;
af1be4f85   Stefan Behrens   Btrfs: fix a scru...
3407
3408
  		if (is_dev_replace &&
  		    atomic64_read(&dev_replace->num_write_errors) > 0) {
ff023aac3   Stefan Behrens   Btrfs: add code t...
3409
3410
3411
3412
3413
3414
3415
  			ret = -EIO;
  			break;
  		}
  		if (sctx->stat.malloc_errors > 0) {
  			ret = -ENOMEM;
  			break;
  		}
a2de733c7   Arne Jansen   btrfs: scrub
3416

539f358a3   Ilya Dryomov   Btrfs: fix the de...
3417
3418
  		dev_replace->cursor_left = dev_replace->cursor_right;
  		dev_replace->item_needs_writeback = 1;
ced96edc4   Qu Wenruo   btrfs: Skip scrub...
3419
  skip:
a2de733c7   Arne Jansen   btrfs: scrub
3420
  		key.offset = found_key.offset + length;
712673339   Chris Mason   Merge branch 'for...
3421
  		btrfs_release_path(path);
a2de733c7   Arne Jansen   btrfs: scrub
3422
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3423
  	btrfs_free_path(path);
8c51032f9   Arne Jansen   btrfs: scrub: err...
3424
3425
3426
3427
3428
3429
  
  	/*
  	 * ret can still be 1 from search_slot or next_leaf,
  	 * that's not an error
  	 */
  	return ret < 0 ? ret : 0;
a2de733c7   Arne Jansen   btrfs: scrub
3430
  }
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3431
3432
  static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
  					   struct btrfs_device *scrub_dev)
a2de733c7   Arne Jansen   btrfs: scrub
3433
3434
3435
3436
3437
  {
  	int	i;
  	u64	bytenr;
  	u64	gen;
  	int	ret;
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3438
  	struct btrfs_root *root = sctx->dev_root;
a2de733c7   Arne Jansen   btrfs: scrub
3439

87533c475   Miao Xie   Btrfs: use bit op...
3440
  	if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
79787eaab   Jeff Mahoney   btrfs: replace ma...
3441
  		return -EIO;
5f546063c   Miao Xie   Btrfs: fix wrong ...
3442
3443
3444
3445
3446
  	/* Seed devices of a new filesystem has their own generation. */
  	if (scrub_dev->fs_devices != root->fs_info->fs_devices)
  		gen = scrub_dev->generation;
  	else
  		gen = root->fs_info->last_trans_committed;
a2de733c7   Arne Jansen   btrfs: scrub
3447
3448
3449
  
  	for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
  		bytenr = btrfs_sb_offset(i);
935e5cc93   Miao Xie   Btrfs: fix wrong ...
3450
3451
  		if (bytenr + BTRFS_SUPER_INFO_SIZE >
  		    scrub_dev->commit_total_bytes)
a2de733c7   Arne Jansen   btrfs: scrub
3452
  			break;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3453
  		ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
a36cf8b89   Stefan Behrens   Btrfs: remove the...
3454
  				  scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i,
ff023aac3   Stefan Behrens   Btrfs: add code t...
3455
  				  NULL, 1, bytenr);
a2de733c7   Arne Jansen   btrfs: scrub
3456
3457
3458
  		if (ret)
  			return ret;
  	}
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
3459
  	wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
a2de733c7   Arne Jansen   btrfs: scrub
3460
3461
3462
3463
3464
3465
3466
  
  	return 0;
  }
  
  /*
   * get a reference count on fs_info->scrub_workers. start worker if necessary
   */
ff023aac3   Stefan Behrens   Btrfs: add code t...
3467
3468
  static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
  						int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
3469
  {
0dc3b84a7   Josef Bacik   Btrfs: fix num_wo...
3470
  	int ret = 0;
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3471
3472
  	int flags = WQ_FREEZABLE | WQ_UNBOUND;
  	int max_active = fs_info->thread_pool_size;
a2de733c7   Arne Jansen   btrfs: scrub
3473

632dd772f   Arne Jansen   btrfs: reinitiali...
3474
  	if (fs_info->scrub_workers_refcnt == 0) {
ff023aac3   Stefan Behrens   Btrfs: add code t...
3475
  		if (is_dev_replace)
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3476
3477
3478
  			fs_info->scrub_workers =
  				btrfs_alloc_workqueue("btrfs-scrub", flags,
  						      1, 4);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3479
  		else
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3480
3481
3482
3483
3484
  			fs_info->scrub_workers =
  				btrfs_alloc_workqueue("btrfs-scrub", flags,
  						      max_active, 4);
  		if (!fs_info->scrub_workers) {
  			ret = -ENOMEM;
0dc3b84a7   Josef Bacik   Btrfs: fix num_wo...
3485
  			goto out;
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3486
3487
3488
3489
3490
3491
  		}
  		fs_info->scrub_wr_completion_workers =
  			btrfs_alloc_workqueue("btrfs-scrubwrc", flags,
  					      max_active, 2);
  		if (!fs_info->scrub_wr_completion_workers) {
  			ret = -ENOMEM;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3492
  			goto out;
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3493
3494
3495
3496
3497
  		}
  		fs_info->scrub_nocow_workers =
  			btrfs_alloc_workqueue("btrfs-scrubnc", flags, 1, 0);
  		if (!fs_info->scrub_nocow_workers) {
  			ret = -ENOMEM;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3498
  			goto out;
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3499
  		}
632dd772f   Arne Jansen   btrfs: reinitiali...
3500
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3501
  	++fs_info->scrub_workers_refcnt;
0dc3b84a7   Josef Bacik   Btrfs: fix num_wo...
3502
  out:
0dc3b84a7   Josef Bacik   Btrfs: fix num_wo...
3503
  	return ret;
a2de733c7   Arne Jansen   btrfs: scrub
3504
  }
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3505
  static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
a2de733c7   Arne Jansen   btrfs: scrub
3506
  {
ff023aac3   Stefan Behrens   Btrfs: add code t...
3507
  	if (--fs_info->scrub_workers_refcnt == 0) {
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3508
3509
3510
  		btrfs_destroy_workqueue(fs_info->scrub_workers);
  		btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers);
  		btrfs_destroy_workqueue(fs_info->scrub_nocow_workers);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3511
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3512
  	WARN_ON(fs_info->scrub_workers_refcnt < 0);
a2de733c7   Arne Jansen   btrfs: scrub
3513
  }
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3514
3515
  int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
  		    u64 end, struct btrfs_scrub_progress *progress,
63a212abc   Stefan Behrens   Btrfs: disallow s...
3516
  		    int readonly, int is_dev_replace)
a2de733c7   Arne Jansen   btrfs: scrub
3517
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3518
  	struct scrub_ctx *sctx;
a2de733c7   Arne Jansen   btrfs: scrub
3519
3520
  	int ret;
  	struct btrfs_device *dev;
5d68da3b8   Miao Xie   Btrfs: don't writ...
3521
  	struct rcu_string *name;
a2de733c7   Arne Jansen   btrfs: scrub
3522

aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3523
  	if (btrfs_fs_closing(fs_info))
a2de733c7   Arne Jansen   btrfs: scrub
3524
  		return -EINVAL;
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3525
  	if (fs_info->chunk_root->nodesize > BTRFS_STRIPE_LEN) {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
3526
3527
3528
3529
3530
  		/*
  		 * in this case scrub is unable to calculate the checksum
  		 * the way scrub is implemented. Do not handle this
  		 * situation at all because it won't ever happen.
  		 */
efe120a06   Frank Holton   Btrfs: convert pr...
3531
3532
  		btrfs_err(fs_info,
  			   "scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails",
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3533
  		       fs_info->chunk_root->nodesize, BTRFS_STRIPE_LEN);
b5d67f64f   Stefan Behrens   Btrfs: change scr...
3534
3535
  		return -EINVAL;
  	}
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3536
  	if (fs_info->chunk_root->sectorsize != PAGE_SIZE) {
b5d67f64f   Stefan Behrens   Btrfs: change scr...
3537
  		/* not supported for data w/o checksums */
efe120a06   Frank Holton   Btrfs: convert pr...
3538
3539
3540
  		btrfs_err(fs_info,
  			   "scrub: size assumption sectorsize != PAGE_SIZE "
  			   "(%d != %lu) fails",
27f9f0235   Geert Uytterhoeven   Btrfs: Format PAG...
3541
  		       fs_info->chunk_root->sectorsize, PAGE_SIZE);
a2de733c7   Arne Jansen   btrfs: scrub
3542
3543
  		return -EINVAL;
  	}
7a9e99876   Stefan Behrens   Btrfs: make the s...
3544
3545
3546
3547
3548
3549
3550
3551
  	if (fs_info->chunk_root->nodesize >
  	    PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK ||
  	    fs_info->chunk_root->sectorsize >
  	    PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK) {
  		/*
  		 * would exhaust the array bounds of pagev member in
  		 * struct scrub_block
  		 */
efe120a06   Frank Holton   Btrfs: convert pr...
3552
3553
  		btrfs_err(fs_info, "scrub: size assumption nodesize and sectorsize "
  			   "<= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails",
7a9e99876   Stefan Behrens   Btrfs: make the s...
3554
3555
3556
3557
3558
3559
  		       fs_info->chunk_root->nodesize,
  		       SCRUB_MAX_PAGES_PER_BLOCK,
  		       fs_info->chunk_root->sectorsize,
  		       SCRUB_MAX_PAGES_PER_BLOCK);
  		return -EINVAL;
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3560

aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3561
3562
  	mutex_lock(&fs_info->fs_devices->device_list_mutex);
  	dev = btrfs_find_device(fs_info, devid, NULL, NULL);
63a212abc   Stefan Behrens   Btrfs: disallow s...
3563
  	if (!dev || (dev->missing && !is_dev_replace)) {
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3564
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
a2de733c7   Arne Jansen   btrfs: scrub
3565
3566
  		return -ENODEV;
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3567

5d68da3b8   Miao Xie   Btrfs: don't writ...
3568
3569
3570
3571
3572
3573
3574
3575
3576
  	if (!is_dev_replace && !readonly && !dev->writeable) {
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
  		rcu_read_lock();
  		name = rcu_dereference(dev->name);
  		btrfs_err(fs_info, "scrub: device %s is not writable",
  			  name->str);
  		rcu_read_unlock();
  		return -EROFS;
  	}
3b7a016f4   Wang Shilong   Btrfs: avoid unne...
3577
  	mutex_lock(&fs_info->scrub_lock);
63a212abc   Stefan Behrens   Btrfs: disallow s...
3578
  	if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
a2de733c7   Arne Jansen   btrfs: scrub
3579
  		mutex_unlock(&fs_info->scrub_lock);
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3580
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3581
  		return -EIO;
a2de733c7   Arne Jansen   btrfs: scrub
3582
  	}
8dabb7420   Stefan Behrens   Btrfs: change cor...
3583
3584
3585
3586
3587
  	btrfs_dev_replace_lock(&fs_info->dev_replace);
  	if (dev->scrub_device ||
  	    (!is_dev_replace &&
  	     btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
  		btrfs_dev_replace_unlock(&fs_info->dev_replace);
a2de733c7   Arne Jansen   btrfs: scrub
3588
  		mutex_unlock(&fs_info->scrub_lock);
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3589
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
a2de733c7   Arne Jansen   btrfs: scrub
3590
3591
  		return -EINPROGRESS;
  	}
8dabb7420   Stefan Behrens   Btrfs: change cor...
3592
  	btrfs_dev_replace_unlock(&fs_info->dev_replace);
3b7a016f4   Wang Shilong   Btrfs: avoid unne...
3593
3594
3595
3596
3597
3598
3599
  
  	ret = scrub_workers_get(fs_info, is_dev_replace);
  	if (ret) {
  		mutex_unlock(&fs_info->scrub_lock);
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
  		return ret;
  	}
63a212abc   Stefan Behrens   Btrfs: disallow s...
3600
  	sctx = scrub_setup_ctx(dev, is_dev_replace);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3601
  	if (IS_ERR(sctx)) {
a2de733c7   Arne Jansen   btrfs: scrub
3602
  		mutex_unlock(&fs_info->scrub_lock);
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3603
3604
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
  		scrub_workers_put(fs_info);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3605
  		return PTR_ERR(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
3606
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3607
3608
  	sctx->readonly = readonly;
  	dev->scrub_device = sctx;
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
3609
  	mutex_unlock(&fs_info->fs_devices->device_list_mutex);
a2de733c7   Arne Jansen   btrfs: scrub
3610

3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
3611
3612
3613
3614
  	/*
  	 * checking @scrub_pause_req here, we can avoid
  	 * race between committing transaction and scrubbing.
  	 */
cb7ab0215   Wang Shilong   Btrfs: wrap repea...
3615
  	__scrub_blocked_if_needed(fs_info);
a2de733c7   Arne Jansen   btrfs: scrub
3616
3617
  	atomic_inc(&fs_info->scrubs_running);
  	mutex_unlock(&fs_info->scrub_lock);
a2de733c7   Arne Jansen   btrfs: scrub
3618

ff023aac3   Stefan Behrens   Btrfs: add code t...
3619
  	if (!is_dev_replace) {
9b011adfe   Wang Shilong   Btrfs: remove scr...
3620
3621
3622
3623
  		/*
  		 * by holding device list mutex, we can
  		 * kick off writing super in log tree sync.
  		 */
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
3624
  		mutex_lock(&fs_info->fs_devices->device_list_mutex);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3625
  		ret = scrub_supers(sctx, dev);
3cb0929ad   Wang Shilong   Btrfs: fix wrong ...
3626
  		mutex_unlock(&fs_info->fs_devices->device_list_mutex);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3627
  	}
a2de733c7   Arne Jansen   btrfs: scrub
3628
3629
  
  	if (!ret)
ff023aac3   Stefan Behrens   Btrfs: add code t...
3630
3631
  		ret = scrub_enumerate_chunks(sctx, dev, start, end,
  					     is_dev_replace);
a2de733c7   Arne Jansen   btrfs: scrub
3632

b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
3633
  	wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
a2de733c7   Arne Jansen   btrfs: scrub
3634
3635
  	atomic_dec(&fs_info->scrubs_running);
  	wake_up(&fs_info->scrub_pause_wait);
b6bfebc13   Stefan Behrens   Btrfs: cleanup sc...
3636
  	wait_event(sctx->list_wait, atomic_read(&sctx->workers_pending) == 0);
0ef8e4515   Jan Schmidt   btrfs scrub: add ...
3637

a2de733c7   Arne Jansen   btrfs: scrub
3638
  	if (progress)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3639
  		memcpy(progress, &sctx->stat, sizeof(*progress));
a2de733c7   Arne Jansen   btrfs: scrub
3640
3641
3642
  
  	mutex_lock(&fs_info->scrub_lock);
  	dev->scrub_device = NULL;
3b7a016f4   Wang Shilong   Btrfs: avoid unne...
3643
  	scrub_workers_put(fs_info);
a2de733c7   Arne Jansen   btrfs: scrub
3644
  	mutex_unlock(&fs_info->scrub_lock);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3645
  	scrub_free_ctx(sctx);
a2de733c7   Arne Jansen   btrfs: scrub
3646
3647
3648
  
  	return ret;
  }
143bede52   Jeff Mahoney   btrfs: return voi...
3649
  void btrfs_scrub_pause(struct btrfs_root *root)
a2de733c7   Arne Jansen   btrfs: scrub
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
  {
  	struct btrfs_fs_info *fs_info = root->fs_info;
  
  	mutex_lock(&fs_info->scrub_lock);
  	atomic_inc(&fs_info->scrub_pause_req);
  	while (atomic_read(&fs_info->scrubs_paused) !=
  	       atomic_read(&fs_info->scrubs_running)) {
  		mutex_unlock(&fs_info->scrub_lock);
  		wait_event(fs_info->scrub_pause_wait,
  			   atomic_read(&fs_info->scrubs_paused) ==
  			   atomic_read(&fs_info->scrubs_running));
  		mutex_lock(&fs_info->scrub_lock);
  	}
  	mutex_unlock(&fs_info->scrub_lock);
a2de733c7   Arne Jansen   btrfs: scrub
3664
  }
143bede52   Jeff Mahoney   btrfs: return voi...
3665
  void btrfs_scrub_continue(struct btrfs_root *root)
a2de733c7   Arne Jansen   btrfs: scrub
3666
3667
3668
3669
3670
  {
  	struct btrfs_fs_info *fs_info = root->fs_info;
  
  	atomic_dec(&fs_info->scrub_pause_req);
  	wake_up(&fs_info->scrub_pause_wait);
a2de733c7   Arne Jansen   btrfs: scrub
3671
  }
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3672
  int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
a2de733c7   Arne Jansen   btrfs: scrub
3673
  {
a2de733c7   Arne Jansen   btrfs: scrub
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
  	mutex_lock(&fs_info->scrub_lock);
  	if (!atomic_read(&fs_info->scrubs_running)) {
  		mutex_unlock(&fs_info->scrub_lock);
  		return -ENOTCONN;
  	}
  
  	atomic_inc(&fs_info->scrub_cancel_req);
  	while (atomic_read(&fs_info->scrubs_running)) {
  		mutex_unlock(&fs_info->scrub_lock);
  		wait_event(fs_info->scrub_pause_wait,
  			   atomic_read(&fs_info->scrubs_running) == 0);
  		mutex_lock(&fs_info->scrub_lock);
  	}
  	atomic_dec(&fs_info->scrub_cancel_req);
  	mutex_unlock(&fs_info->scrub_lock);
  
  	return 0;
  }
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3692
3693
  int btrfs_scrub_cancel_dev(struct btrfs_fs_info *fs_info,
  			   struct btrfs_device *dev)
49b25e054   Jeff Mahoney   btrfs: enhance tr...
3694
  {
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3695
  	struct scrub_ctx *sctx;
a2de733c7   Arne Jansen   btrfs: scrub
3696
3697
  
  	mutex_lock(&fs_info->scrub_lock);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3698
3699
  	sctx = dev->scrub_device;
  	if (!sctx) {
a2de733c7   Arne Jansen   btrfs: scrub
3700
3701
3702
  		mutex_unlock(&fs_info->scrub_lock);
  		return -ENOTCONN;
  	}
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3703
  	atomic_inc(&sctx->cancel_req);
a2de733c7   Arne Jansen   btrfs: scrub
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
  	while (dev->scrub_device) {
  		mutex_unlock(&fs_info->scrub_lock);
  		wait_event(fs_info->scrub_pause_wait,
  			   dev->scrub_device == NULL);
  		mutex_lock(&fs_info->scrub_lock);
  	}
  	mutex_unlock(&fs_info->scrub_lock);
  
  	return 0;
  }
1623edebe   Stefan Behrens   Btrfs: minor clea...
3714

a2de733c7   Arne Jansen   btrfs: scrub
3715
3716
3717
3718
  int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
  			 struct btrfs_scrub_progress *progress)
  {
  	struct btrfs_device *dev;
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3719
  	struct scrub_ctx *sctx = NULL;
a2de733c7   Arne Jansen   btrfs: scrub
3720
3721
  
  	mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
aa1b8cd40   Stefan Behrens   Btrfs: pass fs_in...
3722
  	dev = btrfs_find_device(root->fs_info, devid, NULL, NULL);
a2de733c7   Arne Jansen   btrfs: scrub
3723
  	if (dev)
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3724
3725
3726
  		sctx = dev->scrub_device;
  	if (sctx)
  		memcpy(progress, &sctx->stat, sizeof(*progress));
a2de733c7   Arne Jansen   btrfs: scrub
3727
  	mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
d9d181c1b   Stefan Behrens   Btrfs: rename the...
3728
  	return dev ? (sctx ? 0 : -ENOTCONN) : -ENODEV;
a2de733c7   Arne Jansen   btrfs: scrub
3729
  }
ff023aac3   Stefan Behrens   Btrfs: add code t...
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
  
  static void scrub_remap_extent(struct btrfs_fs_info *fs_info,
  			       u64 extent_logical, u64 extent_len,
  			       u64 *extent_physical,
  			       struct btrfs_device **extent_dev,
  			       int *extent_mirror_num)
  {
  	u64 mapped_length;
  	struct btrfs_bio *bbio = NULL;
  	int ret;
  
  	mapped_length = extent_len;
  	ret = btrfs_map_block(fs_info, READ, extent_logical,
  			      &mapped_length, &bbio, 0);
  	if (ret || !bbio || mapped_length < extent_len ||
  	    !bbio->stripes[0].dev->bdev) {
  		kfree(bbio);
  		return;
  	}
  
  	*extent_physical = bbio->stripes[0].physical;
  	*extent_mirror_num = bbio->mirror_num;
  	*extent_dev = bbio->stripes[0].dev;
  	kfree(bbio);
  }
  
  static int scrub_setup_wr_ctx(struct scrub_ctx *sctx,
  			      struct scrub_wr_ctx *wr_ctx,
  			      struct btrfs_fs_info *fs_info,
  			      struct btrfs_device *dev,
  			      int is_dev_replace)
  {
  	WARN_ON(wr_ctx->wr_curr_bio != NULL);
  
  	mutex_init(&wr_ctx->wr_lock);
  	wr_ctx->wr_curr_bio = NULL;
  	if (!is_dev_replace)
  		return 0;
  
  	WARN_ON(!dev->bdev);
  	wr_ctx->pages_per_wr_bio = min_t(int, SCRUB_PAGES_PER_WR_BIO,
  					 bio_get_nr_vecs(dev->bdev));
  	wr_ctx->tgtdev = dev;
  	atomic_set(&wr_ctx->flush_all_writes, 0);
  	return 0;
  }
  
  static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx)
  {
  	mutex_lock(&wr_ctx->wr_lock);
  	kfree(wr_ctx->wr_curr_bio);
  	wr_ctx->wr_curr_bio = NULL;
  	mutex_unlock(&wr_ctx->wr_lock);
  }
  
  static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
  			    int mirror_num, u64 physical_for_dev_replace)
  {
  	struct scrub_copy_nocow_ctx *nocow_ctx;
  	struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
  
  	nocow_ctx = kzalloc(sizeof(*nocow_ctx), GFP_NOFS);
  	if (!nocow_ctx) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
  		return -ENOMEM;
  	}
  
  	scrub_pending_trans_workers_inc(sctx);
  
  	nocow_ctx->sctx = sctx;
  	nocow_ctx->logical = logical;
  	nocow_ctx->len = len;
  	nocow_ctx->mirror_num = mirror_num;
  	nocow_ctx->physical_for_dev_replace = physical_for_dev_replace;
9e0af2376   Liu Bo   Btrfs: fix task h...
3806
3807
  	btrfs_init_work(&nocow_ctx->work, btrfs_scrubnc_helper,
  			copy_nocow_pages_worker, NULL, NULL);
652f25a29   Josef Bacik   Btrfs: improve re...
3808
  	INIT_LIST_HEAD(&nocow_ctx->inodes);
0339ef2f4   Qu Wenruo   btrfs: Replace fs...
3809
3810
  	btrfs_queue_work(fs_info->scrub_nocow_workers,
  			 &nocow_ctx->work);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3811
3812
3813
  
  	return 0;
  }
652f25a29   Josef Bacik   Btrfs: improve re...
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
  static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx)
  {
  	struct scrub_copy_nocow_ctx *nocow_ctx = ctx;
  	struct scrub_nocow_inode *nocow_inode;
  
  	nocow_inode = kzalloc(sizeof(*nocow_inode), GFP_NOFS);
  	if (!nocow_inode)
  		return -ENOMEM;
  	nocow_inode->inum = inum;
  	nocow_inode->offset = offset;
  	nocow_inode->root = root;
  	list_add_tail(&nocow_inode->list, &nocow_ctx->inodes);
  	return 0;
  }
  
  #define COPY_COMPLETE 1
ff023aac3   Stefan Behrens   Btrfs: add code t...
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
  static void copy_nocow_pages_worker(struct btrfs_work *work)
  {
  	struct scrub_copy_nocow_ctx *nocow_ctx =
  		container_of(work, struct scrub_copy_nocow_ctx, work);
  	struct scrub_ctx *sctx = nocow_ctx->sctx;
  	u64 logical = nocow_ctx->logical;
  	u64 len = nocow_ctx->len;
  	int mirror_num = nocow_ctx->mirror_num;
  	u64 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
  	int ret;
  	struct btrfs_trans_handle *trans = NULL;
  	struct btrfs_fs_info *fs_info;
  	struct btrfs_path *path;
  	struct btrfs_root *root;
  	int not_written = 0;
  
  	fs_info = sctx->dev_root->fs_info;
  	root = fs_info->extent_root;
  
  	path = btrfs_alloc_path();
  	if (!path) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
  		not_written = 1;
  		goto out;
  	}
  
  	trans = btrfs_join_transaction(root);
  	if (IS_ERR(trans)) {
  		not_written = 1;
  		goto out;
  	}
  
  	ret = iterate_inodes_from_logical(logical, fs_info, path,
652f25a29   Josef Bacik   Btrfs: improve re...
3865
  					  record_inode_for_nocow, nocow_ctx);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3866
  	if (ret != 0 && ret != -ENOENT) {
efe120a06   Frank Holton   Btrfs: convert pr...
3867
3868
  		btrfs_warn(fs_info, "iterate_inodes_from_logical() failed: log %llu, "
  			"phys %llu, len %llu, mir %u, ret %d",
118a0a251   Geert Uytterhoeven   Btrfs: Format mir...
3869
3870
  			logical, physical_for_dev_replace, len, mirror_num,
  			ret);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3871
3872
3873
  		not_written = 1;
  		goto out;
  	}
652f25a29   Josef Bacik   Btrfs: improve re...
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
  	btrfs_end_transaction(trans, root);
  	trans = NULL;
  	while (!list_empty(&nocow_ctx->inodes)) {
  		struct scrub_nocow_inode *entry;
  		entry = list_first_entry(&nocow_ctx->inodes,
  					 struct scrub_nocow_inode,
  					 list);
  		list_del_init(&entry->list);
  		ret = copy_nocow_pages_for_inode(entry->inum, entry->offset,
  						 entry->root, nocow_ctx);
  		kfree(entry);
  		if (ret == COPY_COMPLETE) {
  			ret = 0;
  			break;
  		} else if (ret) {
  			break;
  		}
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
3892
  out:
652f25a29   Josef Bacik   Btrfs: improve re...
3893
3894
3895
3896
3897
3898
3899
3900
  	while (!list_empty(&nocow_ctx->inodes)) {
  		struct scrub_nocow_inode *entry;
  		entry = list_first_entry(&nocow_ctx->inodes,
  					 struct scrub_nocow_inode,
  					 list);
  		list_del_init(&entry->list);
  		kfree(entry);
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
  	if (trans && !IS_ERR(trans))
  		btrfs_end_transaction(trans, root);
  	if (not_written)
  		btrfs_dev_replace_stats_inc(&fs_info->dev_replace.
  					    num_uncorrectable_read_errors);
  
  	btrfs_free_path(path);
  	kfree(nocow_ctx);
  
  	scrub_pending_trans_workers_dec(sctx);
  }
321592427   Gui Hecheng   btrfs: fix dead l...
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
  static int check_extent_to_block(struct inode *inode, u64 start, u64 len,
  				 u64 logical)
  {
  	struct extent_state *cached_state = NULL;
  	struct btrfs_ordered_extent *ordered;
  	struct extent_io_tree *io_tree;
  	struct extent_map *em;
  	u64 lockstart = start, lockend = start + len - 1;
  	int ret = 0;
  
  	io_tree = &BTRFS_I(inode)->io_tree;
  
  	lock_extent_bits(io_tree, lockstart, lockend, 0, &cached_state);
  	ordered = btrfs_lookup_ordered_range(inode, lockstart, len);
  	if (ordered) {
  		btrfs_put_ordered_extent(ordered);
  		ret = 1;
  		goto out_unlock;
  	}
  
  	em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
  	if (IS_ERR(em)) {
  		ret = PTR_ERR(em);
  		goto out_unlock;
  	}
  
  	/*
  	 * This extent does not actually cover the logical extent anymore,
  	 * move on to the next inode.
  	 */
  	if (em->block_start > logical ||
  	    em->block_start + em->block_len < logical + len) {
  		free_extent_map(em);
  		ret = 1;
  		goto out_unlock;
  	}
  	free_extent_map(em);
  
  out_unlock:
  	unlock_extent_cached(io_tree, lockstart, lockend, &cached_state,
  			     GFP_NOFS);
  	return ret;
  }
652f25a29   Josef Bacik   Btrfs: improve re...
3955
3956
  static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
  				      struct scrub_copy_nocow_ctx *nocow_ctx)
ff023aac3   Stefan Behrens   Btrfs: add code t...
3957
  {
826aa0a82   Miao Xie   Btrfs: cleanup th...
3958
  	struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3959
  	struct btrfs_key key;
826aa0a82   Miao Xie   Btrfs: cleanup th...
3960
3961
  	struct inode *inode;
  	struct page *page;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3962
  	struct btrfs_root *local_root;
652f25a29   Josef Bacik   Btrfs: improve re...
3963
  	struct extent_io_tree *io_tree;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3964
  	u64 physical_for_dev_replace;
321592427   Gui Hecheng   btrfs: fix dead l...
3965
  	u64 nocow_ctx_logical;
652f25a29   Josef Bacik   Btrfs: improve re...
3966
  	u64 len = nocow_ctx->len;
826aa0a82   Miao Xie   Btrfs: cleanup th...
3967
  	unsigned long index;
6f1c36055   Liu Bo   Btrfs: fix race b...
3968
  	int srcu_index;
652f25a29   Josef Bacik   Btrfs: improve re...
3969
3970
  	int ret = 0;
  	int err = 0;
ff023aac3   Stefan Behrens   Btrfs: add code t...
3971
3972
3973
3974
  
  	key.objectid = root;
  	key.type = BTRFS_ROOT_ITEM_KEY;
  	key.offset = (u64)-1;
6f1c36055   Liu Bo   Btrfs: fix race b...
3975
3976
  
  	srcu_index = srcu_read_lock(&fs_info->subvol_srcu);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3977
  	local_root = btrfs_read_fs_root_no_name(fs_info, &key);
6f1c36055   Liu Bo   Btrfs: fix race b...
3978
3979
  	if (IS_ERR(local_root)) {
  		srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3980
  		return PTR_ERR(local_root);
6f1c36055   Liu Bo   Btrfs: fix race b...
3981
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
3982
3983
3984
3985
3986
  
  	key.type = BTRFS_INODE_ITEM_KEY;
  	key.objectid = inum;
  	key.offset = 0;
  	inode = btrfs_iget(fs_info->sb, &key, local_root, NULL);
6f1c36055   Liu Bo   Btrfs: fix race b...
3987
  	srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3988
3989
  	if (IS_ERR(inode))
  		return PTR_ERR(inode);
edd1400be   Miao Xie   Btrfs: fix severa...
3990
3991
3992
  	/* Avoid truncate/dio/punch hole.. */
  	mutex_lock(&inode->i_mutex);
  	inode_dio_wait(inode);
ff023aac3   Stefan Behrens   Btrfs: add code t...
3993
  	physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
652f25a29   Josef Bacik   Btrfs: improve re...
3994
  	io_tree = &BTRFS_I(inode)->io_tree;
321592427   Gui Hecheng   btrfs: fix dead l...
3995
  	nocow_ctx_logical = nocow_ctx->logical;
652f25a29   Josef Bacik   Btrfs: improve re...
3996

321592427   Gui Hecheng   btrfs: fix dead l...
3997
3998
3999
4000
  	ret = check_extent_to_block(inode, offset, len, nocow_ctx_logical);
  	if (ret) {
  		ret = ret > 0 ? 0 : ret;
  		goto out;
652f25a29   Josef Bacik   Btrfs: improve re...
4001
  	}
652f25a29   Josef Bacik   Btrfs: improve re...
4002

ff023aac3   Stefan Behrens   Btrfs: add code t...
4003
  	while (len >= PAGE_CACHE_SIZE) {
ff023aac3   Stefan Behrens   Btrfs: add code t...
4004
  		index = offset >> PAGE_CACHE_SHIFT;
edd1400be   Miao Xie   Btrfs: fix severa...
4005
  again:
ff023aac3   Stefan Behrens   Btrfs: add code t...
4006
4007
  		page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
  		if (!page) {
efe120a06   Frank Holton   Btrfs: convert pr...
4008
  			btrfs_err(fs_info, "find_or_create_page() failed");
ff023aac3   Stefan Behrens   Btrfs: add code t...
4009
  			ret = -ENOMEM;
826aa0a82   Miao Xie   Btrfs: cleanup th...
4010
  			goto out;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4011
4012
4013
4014
4015
4016
4017
  		}
  
  		if (PageUptodate(page)) {
  			if (PageDirty(page))
  				goto next_page;
  		} else {
  			ClearPageError(page);
321592427   Gui Hecheng   btrfs: fix dead l...
4018
  			err = extent_read_full_page(io_tree, page,
652f25a29   Josef Bacik   Btrfs: improve re...
4019
4020
  							   btrfs_get_extent,
  							   nocow_ctx->mirror_num);
826aa0a82   Miao Xie   Btrfs: cleanup th...
4021
4022
  			if (err) {
  				ret = err;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4023
4024
  				goto next_page;
  			}
edd1400be   Miao Xie   Btrfs: fix severa...
4025

26b258919   Miao Xie   Btrfs: fix oops w...
4026
  			lock_page(page);
edd1400be   Miao Xie   Btrfs: fix severa...
4027
4028
4029
4030
4031
4032
4033
  			/*
  			 * If the page has been remove from the page cache,
  			 * the data on it is meaningless, because it may be
  			 * old one, the new data may be written into the new
  			 * page in the page cache.
  			 */
  			if (page->mapping != inode->i_mapping) {
652f25a29   Josef Bacik   Btrfs: improve re...
4034
  				unlock_page(page);
edd1400be   Miao Xie   Btrfs: fix severa...
4035
4036
4037
  				page_cache_release(page);
  				goto again;
  			}
ff023aac3   Stefan Behrens   Btrfs: add code t...
4038
4039
4040
4041
4042
  			if (!PageUptodate(page)) {
  				ret = -EIO;
  				goto next_page;
  			}
  		}
321592427   Gui Hecheng   btrfs: fix dead l...
4043
4044
4045
4046
4047
4048
4049
  
  		ret = check_extent_to_block(inode, offset, len,
  					    nocow_ctx_logical);
  		if (ret) {
  			ret = ret > 0 ? 0 : ret;
  			goto next_page;
  		}
826aa0a82   Miao Xie   Btrfs: cleanup th...
4050
4051
4052
4053
  		err = write_page_nocow(nocow_ctx->sctx,
  				       physical_for_dev_replace, page);
  		if (err)
  			ret = err;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4054
  next_page:
826aa0a82   Miao Xie   Btrfs: cleanup th...
4055
4056
4057
4058
4059
  		unlock_page(page);
  		page_cache_release(page);
  
  		if (ret)
  			break;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4060
4061
  		offset += PAGE_CACHE_SIZE;
  		physical_for_dev_replace += PAGE_CACHE_SIZE;
321592427   Gui Hecheng   btrfs: fix dead l...
4062
  		nocow_ctx_logical += PAGE_CACHE_SIZE;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4063
4064
  		len -= PAGE_CACHE_SIZE;
  	}
652f25a29   Josef Bacik   Btrfs: improve re...
4065
  	ret = COPY_COMPLETE;
826aa0a82   Miao Xie   Btrfs: cleanup th...
4066
  out:
edd1400be   Miao Xie   Btrfs: fix severa...
4067
  	mutex_unlock(&inode->i_mutex);
826aa0a82   Miao Xie   Btrfs: cleanup th...
4068
  	iput(inode);
ff023aac3   Stefan Behrens   Btrfs: add code t...
4069
4070
4071
4072
4073
4074
4075
4076
4077
  	return ret;
  }
  
  static int write_page_nocow(struct scrub_ctx *sctx,
  			    u64 physical_for_dev_replace, struct page *page)
  {
  	struct bio *bio;
  	struct btrfs_device *dev;
  	int ret;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4078
4079
4080
4081
4082
4083
  
  	dev = sctx->wr_ctx.tgtdev;
  	if (!dev)
  		return -EIO;
  	if (!dev->bdev) {
  		printk_ratelimited(KERN_WARNING
efe120a06   Frank Holton   Btrfs: convert pr...
4084
4085
  			"BTRFS: scrub write_page_nocow(bdev == NULL) is unexpected!
  ");
ff023aac3   Stefan Behrens   Btrfs: add code t...
4086
4087
  		return -EIO;
  	}
9be3395bc   Chris Mason   Btrfs: use a btrf...
4088
  	bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
ff023aac3   Stefan Behrens   Btrfs: add code t...
4089
4090
4091
4092
4093
4094
  	if (!bio) {
  		spin_lock(&sctx->stat_lock);
  		sctx->stat.malloc_errors++;
  		spin_unlock(&sctx->stat_lock);
  		return -ENOMEM;
  	}
4f024f379   Kent Overstreet   block: Abstract o...
4095
4096
  	bio->bi_iter.bi_size = 0;
  	bio->bi_iter.bi_sector = physical_for_dev_replace >> 9;
ff023aac3   Stefan Behrens   Btrfs: add code t...
4097
4098
4099
4100
4101
4102
4103
4104
  	bio->bi_bdev = dev->bdev;
  	ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
  	if (ret != PAGE_CACHE_SIZE) {
  leave_with_eio:
  		bio_put(bio);
  		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
  		return -EIO;
  	}
ff023aac3   Stefan Behrens   Btrfs: add code t...
4105

33879d451   Kent Overstreet   block: submit_bio...
4106
  	if (btrfsic_submit_bio_wait(WRITE_SYNC, bio))
ff023aac3   Stefan Behrens   Btrfs: add code t...
4107
4108
4109
4110
4111
  		goto leave_with_eio;
  
  	bio_put(bio);
  	return 0;
  }