aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/recovery.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2010-08-26 13:22:27 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-08-26 13:22:27 -0400
commitf632265d0ffb5acf331252d98c64939849d96bb2 (patch)
tree31187d9a726bf1ca6ca12e26ad8e7c609eaf4d8b /fs/nilfs2/recovery.c
parent7d94784293096c0a46897acdb83be5abd9278ece (diff)
parentda5cabf80e2433131bf0ed8993abc0f7ea618c73 (diff)
Merge commit 'v2.6.36-rc1' into HEAD
Diffstat (limited to 'fs/nilfs2/recovery.c')
-rw-r--r--fs/nilfs2/recovery.c359
1 files changed, 201 insertions, 158 deletions
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c
index bae2a516b4ee..d0c35ef39f6a 100644
--- a/fs/nilfs2/recovery.c
+++ b/fs/nilfs2/recovery.c
@@ -91,27 +91,9 @@ static int nilfs_warn_segment_error(int err)
91 return -EINVAL; 91 return -EINVAL;
92} 92}
93 93
94static void store_segsum_info(struct nilfs_segsum_info *ssi,
95 struct nilfs_segment_summary *sum,
96 unsigned int blocksize)
97{
98 ssi->flags = le16_to_cpu(sum->ss_flags);
99 ssi->seg_seq = le64_to_cpu(sum->ss_seq);
100 ssi->ctime = le64_to_cpu(sum->ss_create);
101 ssi->next = le64_to_cpu(sum->ss_next);
102 ssi->nblocks = le32_to_cpu(sum->ss_nblocks);
103 ssi->nfinfo = le32_to_cpu(sum->ss_nfinfo);
104 ssi->sumbytes = le32_to_cpu(sum->ss_sumbytes);
105
106 ssi->nsumblk = DIV_ROUND_UP(ssi->sumbytes, blocksize);
107 ssi->nfileblk = ssi->nblocks - ssi->nsumblk - !!NILFS_SEG_HAS_SR(ssi);
108
109 /* need to verify ->ss_bytes field if read ->ss_cno */
110}
111
112/** 94/**
113 * calc_crc_cont - check CRC of blocks continuously 95 * nilfs_compute_checksum - compute checksum of blocks continuously
114 * @sbi: nilfs_sb_info 96 * @nilfs: nilfs object
115 * @bhs: buffer head of start block 97 * @bhs: buffer head of start block
116 * @sum: place to store result 98 * @sum: place to store result
117 * @offset: offset bytes in the first block 99 * @offset: offset bytes in the first block
@@ -119,23 +101,25 @@ static void store_segsum_info(struct nilfs_segsum_info *ssi,
119 * @start: DBN of start block 101 * @start: DBN of start block
120 * @nblock: number of blocks to be checked 102 * @nblock: number of blocks to be checked
121 */ 103 */
122static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs, 104static int nilfs_compute_checksum(struct the_nilfs *nilfs,
123 u32 *sum, unsigned long offset, u64 check_bytes, 105 struct buffer_head *bhs, u32 *sum,
124 sector_t start, unsigned long nblock) 106 unsigned long offset, u64 check_bytes,
107 sector_t start, unsigned long nblock)
125{ 108{
126 unsigned long blocksize = sbi->s_super->s_blocksize; 109 unsigned int blocksize = nilfs->ns_blocksize;
127 unsigned long size; 110 unsigned long size;
128 u32 crc; 111 u32 crc;
129 112
130 BUG_ON(offset >= blocksize); 113 BUG_ON(offset >= blocksize);
131 check_bytes -= offset; 114 check_bytes -= offset;
132 size = min_t(u64, check_bytes, blocksize - offset); 115 size = min_t(u64, check_bytes, blocksize - offset);
133 crc = crc32_le(sbi->s_nilfs->ns_crc_seed, 116 crc = crc32_le(nilfs->ns_crc_seed,
134 (unsigned char *)bhs->b_data + offset, size); 117 (unsigned char *)bhs->b_data + offset, size);
135 if (--nblock > 0) { 118 if (--nblock > 0) {
136 do { 119 do {
137 struct buffer_head *bh 120 struct buffer_head *bh;
138 = sb_bread(sbi->s_super, ++start); 121
122 bh = __bread(nilfs->ns_bdev, ++start, blocksize);
139 if (!bh) 123 if (!bh)
140 return -EIO; 124 return -EIO;
141 check_bytes -= size; 125 check_bytes -= size;
@@ -150,12 +134,12 @@ static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
150 134
151/** 135/**
152 * nilfs_read_super_root_block - read super root block 136 * nilfs_read_super_root_block - read super root block
153 * @sb: super_block 137 * @nilfs: nilfs object
154 * @sr_block: disk block number of the super root block 138 * @sr_block: disk block number of the super root block
155 * @pbh: address of a buffer_head pointer to return super root buffer 139 * @pbh: address of a buffer_head pointer to return super root buffer
156 * @check: CRC check flag 140 * @check: CRC check flag
157 */ 141 */
158int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block, 142int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
159 struct buffer_head **pbh, int check) 143 struct buffer_head **pbh, int check)
160{ 144{
161 struct buffer_head *bh_sr; 145 struct buffer_head *bh_sr;
@@ -164,7 +148,7 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
164 int ret; 148 int ret;
165 149
166 *pbh = NULL; 150 *pbh = NULL;
167 bh_sr = sb_bread(sb, sr_block); 151 bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);
168 if (unlikely(!bh_sr)) { 152 if (unlikely(!bh_sr)) {
169 ret = NILFS_SEG_FAIL_IO; 153 ret = NILFS_SEG_FAIL_IO;
170 goto failed; 154 goto failed;
@@ -174,12 +158,13 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
174 if (check) { 158 if (check) {
175 unsigned bytes = le16_to_cpu(sr->sr_bytes); 159 unsigned bytes = le16_to_cpu(sr->sr_bytes);
176 160
177 if (bytes == 0 || bytes > sb->s_blocksize) { 161 if (bytes == 0 || bytes > nilfs->ns_blocksize) {
178 ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT; 162 ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
179 goto failed_bh; 163 goto failed_bh;
180 } 164 }
181 if (calc_crc_cont(NILFS_SB(sb), bh_sr, &crc, 165 if (nilfs_compute_checksum(
182 sizeof(sr->sr_sum), bytes, sr_block, 1)) { 166 nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,
167 sr_block, 1)) {
183 ret = NILFS_SEG_FAIL_IO; 168 ret = NILFS_SEG_FAIL_IO;
184 goto failed_bh; 169 goto failed_bh;
185 } 170 }
@@ -199,64 +184,76 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
199} 184}
200 185
201/** 186/**
202 * load_segment_summary - read segment summary of the specified partial segment 187 * nilfs_read_log_header - read summary header of the specified log
203 * @sbi: nilfs_sb_info 188 * @nilfs: nilfs object
204 * @pseg_start: start disk block number of partial segment 189 * @start_blocknr: start block number of the log
205 * @seg_seq: sequence number requested 190 * @sum: pointer to return segment summary structure
206 * @ssi: pointer to nilfs_segsum_info struct to store information
207 */ 191 */
208static int 192static struct buffer_head *
209load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start, 193nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
210 u64 seg_seq, struct nilfs_segsum_info *ssi) 194 struct nilfs_segment_summary **sum)
211{ 195{
212 struct buffer_head *bh_sum; 196 struct buffer_head *bh_sum;
213 struct nilfs_segment_summary *sum; 197
198 bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
199 if (bh_sum)
200 *sum = (struct nilfs_segment_summary *)bh_sum->b_data;
201 return bh_sum;
202}
203
204/**
205 * nilfs_validate_log - verify consistency of log
206 * @nilfs: nilfs object
207 * @seg_seq: sequence number of segment
208 * @bh_sum: buffer head of summary block
209 * @sum: segment summary struct
210 */
211static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,
212 struct buffer_head *bh_sum,
213 struct nilfs_segment_summary *sum)
214{
214 unsigned long nblock; 215 unsigned long nblock;
215 u32 crc; 216 u32 crc;
216 int ret = NILFS_SEG_FAIL_IO; 217 int ret;
217 218
218 bh_sum = sb_bread(sbi->s_super, pseg_start); 219 ret = NILFS_SEG_FAIL_MAGIC;
219 if (!bh_sum) 220 if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
220 goto out; 221 goto out;
221 222
222 sum = (struct nilfs_segment_summary *)bh_sum->b_data; 223 ret = NILFS_SEG_FAIL_SEQ;
223 224 if (le64_to_cpu(sum->ss_seq) != seg_seq)
224 /* Check consistency of segment summary */ 225 goto out;
225 if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC) {
226 ret = NILFS_SEG_FAIL_MAGIC;
227 goto failed;
228 }
229 store_segsum_info(ssi, sum, sbi->s_super->s_blocksize);
230 if (seg_seq != ssi->seg_seq) {
231 ret = NILFS_SEG_FAIL_SEQ;
232 goto failed;
233 }
234 226
235 nblock = ssi->nblocks; 227 nblock = le32_to_cpu(sum->ss_nblocks);
236 if (unlikely(nblock == 0 || 228 ret = NILFS_SEG_FAIL_CONSISTENCY;
237 nblock > sbi->s_nilfs->ns_blocks_per_segment)) { 229 if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
238 /* This limits the number of blocks read in the CRC check */ 230 /* This limits the number of blocks read in the CRC check */
239 ret = NILFS_SEG_FAIL_CONSISTENCY; 231 goto out;
240 goto failed; 232
241 } 233 ret = NILFS_SEG_FAIL_IO;
242 if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum), 234 if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
243 ((u64)nblock << sbi->s_super->s_blocksize_bits), 235 ((u64)nblock << nilfs->ns_blocksize_bits),
244 pseg_start, nblock)) { 236 bh_sum->b_blocknr, nblock))
245 ret = NILFS_SEG_FAIL_IO; 237 goto out;
246 goto failed; 238
247 } 239 ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
248 if (crc == le32_to_cpu(sum->ss_datasum)) 240 if (crc != le32_to_cpu(sum->ss_datasum))
249 ret = 0; 241 goto out;
250 else 242 ret = 0;
251 ret = NILFS_SEG_FAIL_CHECKSUM_FULL; 243out:
252 failed:
253 brelse(bh_sum);
254 out:
255 return ret; 244 return ret;
256} 245}
257 246
258static void *segsum_get(struct super_block *sb, struct buffer_head **pbh, 247/**
259 unsigned int *offset, unsigned int bytes) 248 * nilfs_read_summary_info - read an item on summary blocks of a log
249 * @nilfs: nilfs object
250 * @pbh: the current buffer head on summary blocks [in, out]
251 * @offset: the current byte offset on summary blocks [in, out]
252 * @bytes: byte size of the item to be read
253 */
254static void *nilfs_read_summary_info(struct the_nilfs *nilfs,
255 struct buffer_head **pbh,
256 unsigned int *offset, unsigned int bytes)
260{ 257{
261 void *ptr; 258 void *ptr;
262 sector_t blocknr; 259 sector_t blocknr;
@@ -265,7 +262,8 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
265 if (bytes > (*pbh)->b_size - *offset) { 262 if (bytes > (*pbh)->b_size - *offset) {
266 blocknr = (*pbh)->b_blocknr; 263 blocknr = (*pbh)->b_blocknr;
267 brelse(*pbh); 264 brelse(*pbh);
268 *pbh = sb_bread(sb, blocknr + 1); 265 *pbh = __bread(nilfs->ns_bdev, blocknr + 1,
266 nilfs->ns_blocksize);
269 if (unlikely(!*pbh)) 267 if (unlikely(!*pbh))
270 return NULL; 268 return NULL;
271 *offset = 0; 269 *offset = 0;
@@ -275,9 +273,18 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
275 return ptr; 273 return ptr;
276} 274}
277 275
278static void segsum_skip(struct super_block *sb, struct buffer_head **pbh, 276/**
279 unsigned int *offset, unsigned int bytes, 277 * nilfs_skip_summary_info - skip items on summary blocks of a log
280 unsigned long count) 278 * @nilfs: nilfs object
279 * @pbh: the current buffer head on summary blocks [in, out]
280 * @offset: the current byte offset on summary blocks [in, out]
281 * @bytes: byte size of the item to be skipped
282 * @count: number of items to be skipped
283 */
284static void nilfs_skip_summary_info(struct the_nilfs *nilfs,
285 struct buffer_head **pbh,
286 unsigned int *offset, unsigned int bytes,
287 unsigned long count)
281{ 288{
282 unsigned int rest_item_in_current_block 289 unsigned int rest_item_in_current_block
283 = ((*pbh)->b_size - *offset) / bytes; 290 = ((*pbh)->b_size - *offset) / bytes;
@@ -294,36 +301,46 @@ static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
294 *offset = bytes * (count - (bcnt - 1) * nitem_per_block); 301 *offset = bytes * (count - (bcnt - 1) * nitem_per_block);
295 302
296 brelse(*pbh); 303 brelse(*pbh);
297 *pbh = sb_bread(sb, blocknr + bcnt); 304 *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,
305 nilfs->ns_blocksize);
298 } 306 }
299} 307}
300 308
301static int 309/**
302collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr, 310 * nilfs_scan_dsync_log - get block information of a log written for data sync
303 struct nilfs_segsum_info *ssi, 311 * @nilfs: nilfs object
304 struct list_head *head) 312 * @start_blocknr: start block number of the log
313 * @sum: log summary information
314 * @head: list head to add nilfs_recovery_block struct
315 */
316static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,
317 struct nilfs_segment_summary *sum,
318 struct list_head *head)
305{ 319{
306 struct buffer_head *bh; 320 struct buffer_head *bh;
307 unsigned int offset; 321 unsigned int offset;
308 unsigned long nfinfo = ssi->nfinfo; 322 u32 nfinfo, sumbytes;
309 sector_t blocknr = sum_blocknr + ssi->nsumblk; 323 sector_t blocknr;
310 ino_t ino; 324 ino_t ino;
311 int err = -EIO; 325 int err = -EIO;
312 326
327 nfinfo = le32_to_cpu(sum->ss_nfinfo);
313 if (!nfinfo) 328 if (!nfinfo)
314 return 0; 329 return 0;
315 330
316 bh = sb_bread(sbi->s_super, sum_blocknr); 331 sumbytes = le32_to_cpu(sum->ss_sumbytes);
332 blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);
333 bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
317 if (unlikely(!bh)) 334 if (unlikely(!bh))
318 goto out; 335 goto out;
319 336
320 offset = le16_to_cpu( 337 offset = le16_to_cpu(sum->ss_bytes);
321 ((struct nilfs_segment_summary *)bh->b_data)->ss_bytes);
322 for (;;) { 338 for (;;) {
323 unsigned long nblocks, ndatablk, nnodeblk; 339 unsigned long nblocks, ndatablk, nnodeblk;
324 struct nilfs_finfo *finfo; 340 struct nilfs_finfo *finfo;
325 341
326 finfo = segsum_get(sbi->s_super, &bh, &offset, sizeof(*finfo)); 342 finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
343 sizeof(*finfo));
327 if (unlikely(!finfo)) 344 if (unlikely(!finfo))
328 goto out; 345 goto out;
329 346
@@ -336,8 +353,8 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
336 struct nilfs_recovery_block *rb; 353 struct nilfs_recovery_block *rb;
337 struct nilfs_binfo_v *binfo; 354 struct nilfs_binfo_v *binfo;
338 355
339 binfo = segsum_get(sbi->s_super, &bh, &offset, 356 binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
340 sizeof(*binfo)); 357 sizeof(*binfo));
341 if (unlikely(!binfo)) 358 if (unlikely(!binfo))
342 goto out; 359 goto out;
343 360
@@ -355,9 +372,9 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
355 } 372 }
356 if (--nfinfo == 0) 373 if (--nfinfo == 0)
357 break; 374 break;
358 blocknr += nnodeblk; /* always 0 for the data sync segments */ 375 blocknr += nnodeblk; /* always 0 for data sync logs */
359 segsum_skip(sbi->s_super, &bh, &offset, sizeof(__le64), 376 nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),
360 nnodeblk); 377 nnodeblk);
361 if (unlikely(!bh)) 378 if (unlikely(!bh))
362 goto out; 379 goto out;
363 } 380 }
@@ -467,14 +484,14 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
467 return err; 484 return err;
468} 485}
469 486
470static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi, 487static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
471 struct nilfs_recovery_block *rb, 488 struct nilfs_recovery_block *rb,
472 struct page *page) 489 struct page *page)
473{ 490{
474 struct buffer_head *bh_org; 491 struct buffer_head *bh_org;
475 void *kaddr; 492 void *kaddr;
476 493
477 bh_org = sb_bread(sbi->s_super, rb->blocknr); 494 bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);
478 if (unlikely(!bh_org)) 495 if (unlikely(!bh_org))
479 return -EIO; 496 return -EIO;
480 497
@@ -485,13 +502,14 @@ static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
485 return 0; 502 return 0;
486} 503}
487 504
488static int recover_dsync_blocks(struct nilfs_sb_info *sbi, 505static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
489 struct list_head *head, 506 struct nilfs_sb_info *sbi,
490 unsigned long *nr_salvaged_blocks) 507 struct list_head *head,
508 unsigned long *nr_salvaged_blocks)
491{ 509{
492 struct inode *inode; 510 struct inode *inode;
493 struct nilfs_recovery_block *rb, *n; 511 struct nilfs_recovery_block *rb, *n;
494 unsigned blocksize = sbi->s_super->s_blocksize; 512 unsigned blocksize = nilfs->ns_blocksize;
495 struct page *page; 513 struct page *page;
496 loff_t pos; 514 loff_t pos;
497 int err = 0, err2 = 0; 515 int err = 0, err2 = 0;
@@ -505,13 +523,16 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
505 } 523 }
506 524
507 pos = rb->blkoff << inode->i_blkbits; 525 pos = rb->blkoff << inode->i_blkbits;
508 page = NULL; 526 err = block_write_begin(inode->i_mapping, pos, blocksize,
509 err = block_write_begin(NULL, inode->i_mapping, pos, blocksize, 527 0, &page, nilfs_get_block);
510 0, &page, NULL, nilfs_get_block); 528 if (unlikely(err)) {
511 if (unlikely(err)) 529 loff_t isize = inode->i_size;
530 if (pos + blocksize > isize)
531 vmtruncate(inode, isize);
512 goto failed_inode; 532 goto failed_inode;
533 }
513 534
514 err = nilfs_recovery_copy_block(sbi, rb, page); 535 err = nilfs_recovery_copy_block(nilfs, rb, page);
515 if (unlikely(err)) 536 if (unlikely(err))
516 goto failed_page; 537 goto failed_page;
517 538
@@ -551,18 +572,20 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
551/** 572/**
552 * nilfs_do_roll_forward - salvage logical segments newer than the latest 573 * nilfs_do_roll_forward - salvage logical segments newer than the latest
553 * checkpoint 574 * checkpoint
575 * @nilfs: nilfs object
554 * @sbi: nilfs_sb_info 576 * @sbi: nilfs_sb_info
555 * @nilfs: the_nilfs
556 * @ri: pointer to a nilfs_recovery_info 577 * @ri: pointer to a nilfs_recovery_info
557 */ 578 */
558static int nilfs_do_roll_forward(struct the_nilfs *nilfs, 579static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
559 struct nilfs_sb_info *sbi, 580 struct nilfs_sb_info *sbi,
560 struct nilfs_recovery_info *ri) 581 struct nilfs_recovery_info *ri)
561{ 582{
562 struct nilfs_segsum_info ssi; 583 struct buffer_head *bh_sum = NULL;
584 struct nilfs_segment_summary *sum;
563 sector_t pseg_start; 585 sector_t pseg_start;
564 sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */ 586 sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */
565 unsigned long nsalvaged_blocks = 0; 587 unsigned long nsalvaged_blocks = 0;
588 unsigned int flags;
566 u64 seg_seq; 589 u64 seg_seq;
567 __u64 segnum, nextnum = 0; 590 __u64 segnum, nextnum = 0;
568 int empty_seg = 0; 591 int empty_seg = 0;
@@ -581,8 +604,14 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
581 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end); 604 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
582 605
583 while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) { 606 while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
607 brelse(bh_sum);
608 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
609 if (!bh_sum) {
610 err = -EIO;
611 goto failed;
612 }
584 613
585 ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi); 614 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
586 if (ret) { 615 if (ret) {
587 if (ret == NILFS_SEG_FAIL_IO) { 616 if (ret == NILFS_SEG_FAIL_IO) {
588 err = -EIO; 617 err = -EIO;
@@ -590,33 +619,38 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
590 } 619 }
591 goto strayed; 620 goto strayed;
592 } 621 }
593 if (unlikely(NILFS_SEG_HAS_SR(&ssi))) 622
623 flags = le16_to_cpu(sum->ss_flags);
624 if (flags & NILFS_SS_SR)
594 goto confused; 625 goto confused;
595 626
596 /* Found a valid partial segment; do recovery actions */ 627 /* Found a valid partial segment; do recovery actions */
597 nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next); 628 nextnum = nilfs_get_segnum_of_block(nilfs,
629 le64_to_cpu(sum->ss_next));
598 empty_seg = 0; 630 empty_seg = 0;
599 nilfs->ns_ctime = ssi.ctime; 631 nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
600 if (!(ssi.flags & NILFS_SS_GC)) 632 if (!(flags & NILFS_SS_GC))
601 nilfs->ns_nongc_ctime = ssi.ctime; 633 nilfs->ns_nongc_ctime = nilfs->ns_ctime;
602 634
603 switch (state) { 635 switch (state) {
604 case RF_INIT_ST: 636 case RF_INIT_ST:
605 if (!NILFS_SEG_LOGBGN(&ssi) || !NILFS_SEG_DSYNC(&ssi)) 637 if (!(flags & NILFS_SS_LOGBGN) ||
638 !(flags & NILFS_SS_SYNDT))
606 goto try_next_pseg; 639 goto try_next_pseg;
607 state = RF_DSYNC_ST; 640 state = RF_DSYNC_ST;
608 /* Fall through */ 641 /* Fall through */
609 case RF_DSYNC_ST: 642 case RF_DSYNC_ST:
610 if (!NILFS_SEG_DSYNC(&ssi)) 643 if (!(flags & NILFS_SS_SYNDT))
611 goto confused; 644 goto confused;
612 645
613 err = collect_blocks_from_segsum( 646 err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
614 sbi, pseg_start, &ssi, &dsync_blocks); 647 &dsync_blocks);
615 if (unlikely(err)) 648 if (unlikely(err))
616 goto failed; 649 goto failed;
617 if (NILFS_SEG_LOGEND(&ssi)) { 650 if (flags & NILFS_SS_LOGEND) {
618 err = recover_dsync_blocks( 651 err = nilfs_recover_dsync_blocks(
619 sbi, &dsync_blocks, &nsalvaged_blocks); 652 nilfs, sbi, &dsync_blocks,
653 &nsalvaged_blocks);
620 if (unlikely(err)) 654 if (unlikely(err))
621 goto failed; 655 goto failed;
622 state = RF_INIT_ST; 656 state = RF_INIT_ST;
@@ -627,7 +661,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
627 try_next_pseg: 661 try_next_pseg:
628 if (pseg_start == ri->ri_lsegs_end) 662 if (pseg_start == ri->ri_lsegs_end)
629 break; 663 break;
630 pseg_start += ssi.nblocks; 664 pseg_start += le32_to_cpu(sum->ss_nblocks);
631 if (pseg_start < seg_end) 665 if (pseg_start < seg_end)
632 continue; 666 continue;
633 goto feed_segment; 667 goto feed_segment;
@@ -652,8 +686,9 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
652 ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE; 686 ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
653 } 687 }
654 out: 688 out:
689 brelse(bh_sum);
655 dispose_recovery_list(&dsync_blocks); 690 dispose_recovery_list(&dsync_blocks);
656 nilfs_detach_writer(sbi->s_nilfs, sbi); 691 nilfs_detach_writer(nilfs, sbi);
657 return err; 692 return err;
658 693
659 confused: 694 confused:
@@ -667,7 +702,6 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
667} 702}
668 703
669static void nilfs_finish_roll_forward(struct the_nilfs *nilfs, 704static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
670 struct nilfs_sb_info *sbi,
671 struct nilfs_recovery_info *ri) 705 struct nilfs_recovery_info *ri)
672{ 706{
673 struct buffer_head *bh; 707 struct buffer_head *bh;
@@ -677,7 +711,7 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
677 nilfs_get_segnum_of_block(nilfs, ri->ri_super_root)) 711 nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))
678 return; 712 return;
679 713
680 bh = sb_getblk(sbi->s_super, ri->ri_lsegs_start); 714 bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);
681 BUG_ON(!bh); 715 BUG_ON(!bh);
682 memset(bh->b_data, 0, bh->b_size); 716 memset(bh->b_data, 0, bh->b_size);
683 set_buffer_dirty(bh); 717 set_buffer_dirty(bh);
@@ -690,9 +724,8 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
690} 724}
691 725
692/** 726/**
693 * nilfs_recover_logical_segments - salvage logical segments written after 727 * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
694 * the latest super root 728 * @nilfs: nilfs object
695 * @nilfs: the_nilfs
696 * @sbi: nilfs_sb_info 729 * @sbi: nilfs_sb_info
697 * @ri: pointer to a nilfs_recovery_info struct to store search results. 730 * @ri: pointer to a nilfs_recovery_info struct to store search results.
698 * 731 *
@@ -709,9 +742,9 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
709 * 742 *
710 * %-ENOMEM - Insufficient memory available. 743 * %-ENOMEM - Insufficient memory available.
711 */ 744 */
712int nilfs_recover_logical_segments(struct the_nilfs *nilfs, 745int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
713 struct nilfs_sb_info *sbi, 746 struct nilfs_sb_info *sbi,
714 struct nilfs_recovery_info *ri) 747 struct nilfs_recovery_info *ri)
715{ 748{
716 int err; 749 int err;
717 750
@@ -751,7 +784,7 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
751 goto failed; 784 goto failed;
752 } 785 }
753 786
754 nilfs_finish_roll_forward(nilfs, sbi, ri); 787 nilfs_finish_roll_forward(nilfs, ri);
755 } 788 }
756 789
757 failed: 790 failed:
@@ -762,7 +795,6 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
762/** 795/**
763 * nilfs_search_super_root - search the latest valid super root 796 * nilfs_search_super_root - search the latest valid super root
764 * @nilfs: the_nilfs 797 * @nilfs: the_nilfs
765 * @sbi: nilfs_sb_info
766 * @ri: pointer to a nilfs_recovery_info struct to store search results. 798 * @ri: pointer to a nilfs_recovery_info struct to store search results.
767 * 799 *
768 * nilfs_search_super_root() looks for the latest super-root from a partial 800 * nilfs_search_super_root() looks for the latest super-root from a partial
@@ -775,14 +807,19 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
775 * %-EINVAL - No valid segment found 807 * %-EINVAL - No valid segment found
776 * 808 *
777 * %-EIO - I/O error 809 * %-EIO - I/O error
810 *
811 * %-ENOMEM - Insufficient memory available.
778 */ 812 */
779int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, 813int nilfs_search_super_root(struct the_nilfs *nilfs,
780 struct nilfs_recovery_info *ri) 814 struct nilfs_recovery_info *ri)
781{ 815{
782 struct nilfs_segsum_info ssi; 816 struct buffer_head *bh_sum = NULL;
817 struct nilfs_segment_summary *sum;
783 sector_t pseg_start, pseg_end, sr_pseg_start = 0; 818 sector_t pseg_start, pseg_end, sr_pseg_start = 0;
784 sector_t seg_start, seg_end; /* range of full segment (block number) */ 819 sector_t seg_start, seg_end; /* range of full segment (block number) */
785 sector_t b, end; 820 sector_t b, end;
821 unsigned long nblocks;
822 unsigned int flags;
786 u64 seg_seq; 823 u64 seg_seq;
787 __u64 segnum, nextnum = 0; 824 __u64 segnum, nextnum = 0;
788 __u64 cno; 825 __u64 cno;
@@ -801,17 +838,24 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
801 /* Read ahead segment */ 838 /* Read ahead segment */
802 b = seg_start; 839 b = seg_start;
803 while (b <= seg_end) 840 while (b <= seg_end)
804 sb_breadahead(sbi->s_super, b++); 841 __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
805 842
806 for (;;) { 843 for (;;) {
807 /* Load segment summary */ 844 brelse(bh_sum);
808 ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi); 845 ret = NILFS_SEG_FAIL_IO;
846 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
847 if (!bh_sum)
848 goto failed;
849
850 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
809 if (ret) { 851 if (ret) {
810 if (ret == NILFS_SEG_FAIL_IO) 852 if (ret == NILFS_SEG_FAIL_IO)
811 goto failed; 853 goto failed;
812 goto strayed; 854 goto strayed;
813 } 855 }
814 pseg_end = pseg_start + ssi.nblocks - 1; 856
857 nblocks = le32_to_cpu(sum->ss_nblocks);
858 pseg_end = pseg_start + nblocks - 1;
815 if (unlikely(pseg_end > seg_end)) { 859 if (unlikely(pseg_end > seg_end)) {
816 ret = NILFS_SEG_FAIL_CONSISTENCY; 860 ret = NILFS_SEG_FAIL_CONSISTENCY;
817 goto strayed; 861 goto strayed;
@@ -821,11 +865,13 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
821 ri->ri_pseg_start = pseg_start; 865 ri->ri_pseg_start = pseg_start;
822 ri->ri_seq = seg_seq; 866 ri->ri_seq = seg_seq;
823 ri->ri_segnum = segnum; 867 ri->ri_segnum = segnum;
824 nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next); 868 nextnum = nilfs_get_segnum_of_block(nilfs,
869 le64_to_cpu(sum->ss_next));
825 ri->ri_nextnum = nextnum; 870 ri->ri_nextnum = nextnum;
826 empty_seg = 0; 871 empty_seg = 0;
827 872
828 if (!NILFS_SEG_HAS_SR(&ssi) && !scan_newer) { 873 flags = le16_to_cpu(sum->ss_flags);
874 if (!(flags & NILFS_SS_SR) && !scan_newer) {
829 /* This will never happen because a superblock 875 /* This will never happen because a superblock
830 (last_segment) always points to a pseg 876 (last_segment) always points to a pseg
831 having a super root. */ 877 having a super root. */
@@ -836,14 +882,15 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
836 if (pseg_start == seg_start) { 882 if (pseg_start == seg_start) {
837 nilfs_get_segment_range(nilfs, nextnum, &b, &end); 883 nilfs_get_segment_range(nilfs, nextnum, &b, &end);
838 while (b <= end) 884 while (b <= end)
839 sb_breadahead(sbi->s_super, b++); 885 __breadahead(nilfs->ns_bdev, b++,
886 nilfs->ns_blocksize);
840 } 887 }
841 if (!NILFS_SEG_HAS_SR(&ssi)) { 888 if (!(flags & NILFS_SS_SR)) {
842 if (!ri->ri_lsegs_start && NILFS_SEG_LOGBGN(&ssi)) { 889 if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {
843 ri->ri_lsegs_start = pseg_start; 890 ri->ri_lsegs_start = pseg_start;
844 ri->ri_lsegs_start_seq = seg_seq; 891 ri->ri_lsegs_start_seq = seg_seq;
845 } 892 }
846 if (NILFS_SEG_LOGEND(&ssi)) 893 if (flags & NILFS_SS_LOGEND)
847 ri->ri_lsegs_end = pseg_start; 894 ri->ri_lsegs_end = pseg_start;
848 goto try_next_pseg; 895 goto try_next_pseg;
849 } 896 }
@@ -854,12 +901,12 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
854 ri->ri_lsegs_start = ri->ri_lsegs_end = 0; 901 ri->ri_lsegs_start = ri->ri_lsegs_end = 0;
855 902
856 nilfs_dispose_segment_list(&segments); 903 nilfs_dispose_segment_list(&segments);
857 nilfs->ns_pseg_offset = (sr_pseg_start = pseg_start) 904 sr_pseg_start = pseg_start;
858 + ssi.nblocks - seg_start; 905 nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;
859 nilfs->ns_seg_seq = seg_seq; 906 nilfs->ns_seg_seq = seg_seq;
860 nilfs->ns_segnum = segnum; 907 nilfs->ns_segnum = segnum;
861 nilfs->ns_cno = cno; /* nilfs->ns_cno = ri->ri_cno + 1 */ 908 nilfs->ns_cno = cno; /* nilfs->ns_cno = ri->ri_cno + 1 */
862 nilfs->ns_ctime = ssi.ctime; 909 nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
863 nilfs->ns_nextnum = nextnum; 910 nilfs->ns_nextnum = nextnum;
864 911
865 if (scan_newer) 912 if (scan_newer)
@@ -870,15 +917,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
870 scan_newer = 1; 917 scan_newer = 1;
871 } 918 }
872 919
873 /* reset region for roll-forward */
874 pseg_start += ssi.nblocks;
875 if (pseg_start < seg_end)
876 continue;
877 goto feed_segment;
878
879 try_next_pseg: 920 try_next_pseg:
880 /* Standing on a course, or met an inconsistent state */ 921 /* Standing on a course, or met an inconsistent state */
881 pseg_start += ssi.nblocks; 922 pseg_start += nblocks;
882 if (pseg_start < seg_end) 923 if (pseg_start < seg_end)
883 continue; 924 continue;
884 goto feed_segment; 925 goto feed_segment;
@@ -909,6 +950,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
909 950
910 super_root_found: 951 super_root_found:
911 /* Updating pointers relating to the latest checkpoint */ 952 /* Updating pointers relating to the latest checkpoint */
953 brelse(bh_sum);
912 list_splice_tail(&segments, &ri->ri_used_segments); 954 list_splice_tail(&segments, &ri->ri_used_segments);
913 nilfs->ns_last_pseg = sr_pseg_start; 955 nilfs->ns_last_pseg = sr_pseg_start;
914 nilfs->ns_last_seq = nilfs->ns_seg_seq; 956 nilfs->ns_last_seq = nilfs->ns_seg_seq;
@@ -916,6 +958,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
916 return 0; 958 return 0;
917 959
918 failed: 960 failed:
961 brelse(bh_sum);
919 nilfs_dispose_segment_list(&segments); 962 nilfs_dispose_segment_list(&segments);
920 return (ret < 0) ? ret : nilfs_warn_segment_error(ret); 963 return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
921} 964}