linux/fs/nilfs2/recovery.c
<<
>>
Prefs
   1/*
   2 * recovery.c - NILFS recovery logic
   3 *
   4 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  19 *
  20 * Written by Ryusuke Konishi <ryusuke@osrg.net>
  21 */
  22
  23#include <linux/buffer_head.h>
  24#include <linux/blkdev.h>
  25#include <linux/swap.h>
  26#include <linux/slab.h>
  27#include <linux/crc32.h>
  28#include "nilfs.h"
  29#include "segment.h"
  30#include "sufile.h"
  31#include "page.h"
  32#include "segbuf.h"
  33
  34/*
  35 * Segment check result
  36 */
  37enum {
  38        NILFS_SEG_VALID,
  39        NILFS_SEG_NO_SUPER_ROOT,
  40        NILFS_SEG_FAIL_IO,
  41        NILFS_SEG_FAIL_MAGIC,
  42        NILFS_SEG_FAIL_SEQ,
  43        NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,
  44        NILFS_SEG_FAIL_CHECKSUM_FULL,
  45        NILFS_SEG_FAIL_CONSISTENCY,
  46};
  47
  48/* work structure for recovery */
  49struct nilfs_recovery_block {
  50        ino_t ino;              /* Inode number of the file that this block
  51                                   belongs to */
  52        sector_t blocknr;       /* block number */
  53        __u64 vblocknr;         /* virtual block number */
  54        unsigned long blkoff;   /* File offset of the data block (per block) */
  55        struct list_head list;
  56};
  57
  58
  59static int nilfs_warn_segment_error(int err)
  60{
  61        switch (err) {
  62        case NILFS_SEG_FAIL_IO:
  63                printk(KERN_WARNING
  64                       "NILFS warning: I/O error on loading last segment\n");
  65                return -EIO;
  66        case NILFS_SEG_FAIL_MAGIC:
  67                printk(KERN_WARNING
  68                       "NILFS warning: Segment magic number invalid\n");
  69                break;
  70        case NILFS_SEG_FAIL_SEQ:
  71                printk(KERN_WARNING
  72                       "NILFS warning: Sequence number mismatch\n");
  73                break;
  74        case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:
  75                printk(KERN_WARNING
  76                       "NILFS warning: Checksum error in super root\n");
  77                break;
  78        case NILFS_SEG_FAIL_CHECKSUM_FULL:
  79                printk(KERN_WARNING
  80                       "NILFS warning: Checksum error in segment payload\n");
  81                break;
  82        case NILFS_SEG_FAIL_CONSISTENCY:
  83                printk(KERN_WARNING
  84                       "NILFS warning: Inconsistent segment\n");
  85                break;
  86        case NILFS_SEG_NO_SUPER_ROOT:
  87                printk(KERN_WARNING
  88                       "NILFS warning: No super root in the last segment\n");
  89                break;
  90        }
  91        return -EINVAL;
  92}
  93
  94/**
  95 * nilfs_compute_checksum - compute checksum of blocks continuously
  96 * @nilfs: nilfs object
  97 * @bhs: buffer head of start block
  98 * @sum: place to store result
  99 * @offset: offset bytes in the first block
 100 * @check_bytes: number of bytes to be checked
 101 * @start: DBN of start block
 102 * @nblock: number of blocks to be checked
 103 */
 104static int nilfs_compute_checksum(struct the_nilfs *nilfs,
 105                                  struct buffer_head *bhs, u32 *sum,
 106                                  unsigned long offset, u64 check_bytes,
 107                                  sector_t start, unsigned long nblock)
 108{
 109        unsigned int blocksize = nilfs->ns_blocksize;
 110        unsigned long size;
 111        u32 crc;
 112
 113        BUG_ON(offset >= blocksize);
 114        check_bytes -= offset;
 115        size = min_t(u64, check_bytes, blocksize - offset);
 116        crc = crc32_le(nilfs->ns_crc_seed,
 117                       (unsigned char *)bhs->b_data + offset, size);
 118        if (--nblock > 0) {
 119                do {
 120                        struct buffer_head *bh;
 121
 122                        bh = __bread(nilfs->ns_bdev, ++start, blocksize);
 123                        if (!bh)
 124                                return -EIO;
 125                        check_bytes -= size;
 126                        size = min_t(u64, check_bytes, blocksize);
 127                        crc = crc32_le(crc, bh->b_data, size);
 128                        brelse(bh);
 129                } while (--nblock > 0);
 130        }
 131        *sum = crc;
 132        return 0;
 133}
 134
 135/**
 136 * nilfs_read_super_root_block - read super root block
 137 * @nilfs: nilfs object
 138 * @sr_block: disk block number of the super root block
 139 * @pbh: address of a buffer_head pointer to return super root buffer
 140 * @check: CRC check flag
 141 */
 142int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
 143                                struct buffer_head **pbh, int check)
 144{
 145        struct buffer_head *bh_sr;
 146        struct nilfs_super_root *sr;
 147        u32 crc;
 148        int ret;
 149
 150        *pbh = NULL;
 151        bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);
 152        if (unlikely(!bh_sr)) {
 153                ret = NILFS_SEG_FAIL_IO;
 154                goto failed;
 155        }
 156
 157        sr = (struct nilfs_super_root *)bh_sr->b_data;
 158        if (check) {
 159                unsigned bytes = le16_to_cpu(sr->sr_bytes);
 160
 161                if (bytes == 0 || bytes > nilfs->ns_blocksize) {
 162                        ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
 163                        goto failed_bh;
 164                }
 165                if (nilfs_compute_checksum(
 166                            nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,
 167                            sr_block, 1)) {
 168                        ret = NILFS_SEG_FAIL_IO;
 169                        goto failed_bh;
 170                }
 171                if (crc != le32_to_cpu(sr->sr_sum)) {
 172                        ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
 173                        goto failed_bh;
 174                }
 175        }
 176        *pbh = bh_sr;
 177        return 0;
 178
 179 failed_bh:
 180        brelse(bh_sr);
 181
 182 failed:
 183        return nilfs_warn_segment_error(ret);
 184}
 185
 186/**
 187 * nilfs_read_log_header - read summary header of the specified log
 188 * @nilfs: nilfs object
 189 * @start_blocknr: start block number of the log
 190 * @sum: pointer to return segment summary structure
 191 */
 192static struct buffer_head *
 193nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
 194                      struct nilfs_segment_summary **sum)
 195{
 196        struct buffer_head *bh_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{
 215        unsigned long nblock;
 216        u32 crc;
 217        int ret;
 218
 219        ret = NILFS_SEG_FAIL_MAGIC;
 220        if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
 221                goto out;
 222
 223        ret = NILFS_SEG_FAIL_SEQ;
 224        if (le64_to_cpu(sum->ss_seq) != seg_seq)
 225                goto out;
 226
 227        nblock = le32_to_cpu(sum->ss_nblocks);
 228        ret = NILFS_SEG_FAIL_CONSISTENCY;
 229        if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
 230                /* This limits the number of blocks read in the CRC check */
 231                goto out;
 232
 233        ret = NILFS_SEG_FAIL_IO;
 234        if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
 235                                   ((u64)nblock << nilfs->ns_blocksize_bits),
 236                                   bh_sum->b_blocknr, nblock))
 237                goto out;
 238
 239        ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
 240        if (crc != le32_to_cpu(sum->ss_datasum))
 241                goto out;
 242        ret = 0;
 243out:
 244        return ret;
 245}
 246
 247/**
 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)
 257{
 258        void *ptr;
 259        sector_t blocknr;
 260
 261        BUG_ON((*pbh)->b_size < *offset);
 262        if (bytes > (*pbh)->b_size - *offset) {
 263                blocknr = (*pbh)->b_blocknr;
 264                brelse(*pbh);
 265                *pbh = __bread(nilfs->ns_bdev, blocknr + 1,
 266                               nilfs->ns_blocksize);
 267                if (unlikely(!*pbh))
 268                        return NULL;
 269                *offset = 0;
 270        }
 271        ptr = (*pbh)->b_data + *offset;
 272        *offset += bytes;
 273        return ptr;
 274}
 275
 276/**
 277 * nilfs_skip_summary_info - skip items on summary blocks of a log
 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)
 288{
 289        unsigned int rest_item_in_current_block
 290                = ((*pbh)->b_size - *offset) / bytes;
 291
 292        if (count <= rest_item_in_current_block) {
 293                *offset += bytes * count;
 294        } else {
 295                sector_t blocknr = (*pbh)->b_blocknr;
 296                unsigned int nitem_per_block = (*pbh)->b_size / bytes;
 297                unsigned int bcnt;
 298
 299                count -= rest_item_in_current_block;
 300                bcnt = DIV_ROUND_UP(count, nitem_per_block);
 301                *offset = bytes * (count - (bcnt - 1) * nitem_per_block);
 302
 303                brelse(*pbh);
 304                *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,
 305                               nilfs->ns_blocksize);
 306        }
 307}
 308
 309/**
 310 * nilfs_scan_dsync_log - get block information of a log written for data sync
 311 * @nilfs: nilfs object
 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)
 319{
 320        struct buffer_head *bh;
 321        unsigned int offset;
 322        u32 nfinfo, sumbytes;
 323        sector_t blocknr;
 324        ino_t ino;
 325        int err = -EIO;
 326
 327        nfinfo = le32_to_cpu(sum->ss_nfinfo);
 328        if (!nfinfo)
 329                return 0;
 330
 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);
 334        if (unlikely(!bh))
 335                goto out;
 336
 337        offset = le16_to_cpu(sum->ss_bytes);
 338        for (;;) {
 339                unsigned long nblocks, ndatablk, nnodeblk;
 340                struct nilfs_finfo *finfo;
 341
 342                finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
 343                                                sizeof(*finfo));
 344                if (unlikely(!finfo))
 345                        goto out;
 346
 347                ino = le64_to_cpu(finfo->fi_ino);
 348                nblocks = le32_to_cpu(finfo->fi_nblocks);
 349                ndatablk = le32_to_cpu(finfo->fi_ndatablk);
 350                nnodeblk = nblocks - ndatablk;
 351
 352                while (ndatablk-- > 0) {
 353                        struct nilfs_recovery_block *rb;
 354                        struct nilfs_binfo_v *binfo;
 355
 356                        binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
 357                                                        sizeof(*binfo));
 358                        if (unlikely(!binfo))
 359                                goto out;
 360
 361                        rb = kmalloc(sizeof(*rb), GFP_NOFS);
 362                        if (unlikely(!rb)) {
 363                                err = -ENOMEM;
 364                                goto out;
 365                        }
 366                        rb->ino = ino;
 367                        rb->blocknr = blocknr++;
 368                        rb->vblocknr = le64_to_cpu(binfo->bi_vblocknr);
 369                        rb->blkoff = le64_to_cpu(binfo->bi_blkoff);
 370                        /* INIT_LIST_HEAD(&rb->list); */
 371                        list_add_tail(&rb->list, head);
 372                }
 373                if (--nfinfo == 0)
 374                        break;
 375                blocknr += nnodeblk; /* always 0 for data sync logs */
 376                nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),
 377                                        nnodeblk);
 378                if (unlikely(!bh))
 379                        goto out;
 380        }
 381        err = 0;
 382 out:
 383        brelse(bh);   /* brelse(NULL) is just ignored */
 384        return err;
 385}
 386
 387static void dispose_recovery_list(struct list_head *head)
 388{
 389        while (!list_empty(head)) {
 390                struct nilfs_recovery_block *rb;
 391
 392                rb = list_first_entry(head, struct nilfs_recovery_block, list);
 393                list_del(&rb->list);
 394                kfree(rb);
 395        }
 396}
 397
 398struct nilfs_segment_entry {
 399        struct list_head        list;
 400        __u64                   segnum;
 401};
 402
 403static int nilfs_segment_list_add(struct list_head *head, __u64 segnum)
 404{
 405        struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);
 406
 407        if (unlikely(!ent))
 408                return -ENOMEM;
 409
 410        ent->segnum = segnum;
 411        INIT_LIST_HEAD(&ent->list);
 412        list_add_tail(&ent->list, head);
 413        return 0;
 414}
 415
 416void nilfs_dispose_segment_list(struct list_head *head)
 417{
 418        while (!list_empty(head)) {
 419                struct nilfs_segment_entry *ent;
 420
 421                ent = list_first_entry(head, struct nilfs_segment_entry, list);
 422                list_del(&ent->list);
 423                kfree(ent);
 424        }
 425}
 426
 427static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
 428                                              struct super_block *sb,
 429                                              struct nilfs_recovery_info *ri)
 430{
 431        struct list_head *head = &ri->ri_used_segments;
 432        struct nilfs_segment_entry *ent, *n;
 433        struct inode *sufile = nilfs->ns_sufile;
 434        __u64 segnum[4];
 435        int err;
 436        int i;
 437
 438        segnum[0] = nilfs->ns_segnum;
 439        segnum[1] = nilfs->ns_nextnum;
 440        segnum[2] = ri->ri_segnum;
 441        segnum[3] = ri->ri_nextnum;
 442
 443        /*
 444         * Releasing the next segment of the latest super root.
 445         * The next segment is invalidated by this recovery.
 446         */
 447        err = nilfs_sufile_free(sufile, segnum[1]);
 448        if (unlikely(err))
 449                goto failed;
 450
 451        for (i = 1; i < 4; i++) {
 452                err = nilfs_segment_list_add(head, segnum[i]);
 453                if (unlikely(err))
 454                        goto failed;
 455        }
 456
 457        /*
 458         * Collecting segments written after the latest super root.
 459         * These are marked dirty to avoid being reallocated in the next write.
 460         */
 461        list_for_each_entry_safe(ent, n, head, list) {
 462                if (ent->segnum != segnum[0]) {
 463                        err = nilfs_sufile_scrap(sufile, ent->segnum);
 464                        if (unlikely(err))
 465                                goto failed;
 466                }
 467                list_del(&ent->list);
 468                kfree(ent);
 469        }
 470
 471        /* Allocate new segments for recovery */
 472        err = nilfs_sufile_alloc(sufile, &segnum[0]);
 473        if (unlikely(err))
 474                goto failed;
 475
 476        nilfs->ns_pseg_offset = 0;
 477        nilfs->ns_seg_seq = ri->ri_seq + 2;
 478        nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0];
 479
 480 failed:
 481        /* No need to recover sufile because it will be destroyed on error */
 482        return err;
 483}
 484
 485static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
 486                                     struct nilfs_recovery_block *rb,
 487                                     struct page *page)
 488{
 489        struct buffer_head *bh_org;
 490        void *kaddr;
 491
 492        bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);
 493        if (unlikely(!bh_org))
 494                return -EIO;
 495
 496        kaddr = kmap_atomic(page);
 497        memcpy(kaddr + bh_offset(bh_org), bh_org->b_data, bh_org->b_size);
 498        kunmap_atomic(kaddr);
 499        brelse(bh_org);
 500        return 0;
 501}
 502
 503static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
 504                                      struct super_block *sb,
 505                                      struct nilfs_root *root,
 506                                      struct list_head *head,
 507                                      unsigned long *nr_salvaged_blocks)
 508{
 509        struct inode *inode;
 510        struct nilfs_recovery_block *rb, *n;
 511        unsigned blocksize = nilfs->ns_blocksize;
 512        struct page *page;
 513        loff_t pos;
 514        int err = 0, err2 = 0;
 515
 516        list_for_each_entry_safe(rb, n, head, list) {
 517                inode = nilfs_iget(sb, root, rb->ino);
 518                if (IS_ERR(inode)) {
 519                        err = PTR_ERR(inode);
 520                        inode = NULL;
 521                        goto failed_inode;
 522                }
 523
 524                pos = rb->blkoff << inode->i_blkbits;
 525                err = block_write_begin(inode->i_mapping, pos, blocksize,
 526                                        0, &page, nilfs_get_block);
 527                if (unlikely(err)) {
 528                        loff_t isize = inode->i_size;
 529                        if (pos + blocksize > isize)
 530                                nilfs_write_failed(inode->i_mapping,
 531                                                        pos + blocksize);
 532                        goto failed_inode;
 533                }
 534
 535                err = nilfs_recovery_copy_block(nilfs, rb, page);
 536                if (unlikely(err))
 537                        goto failed_page;
 538
 539                err = nilfs_set_file_dirty(inode, 1);
 540                if (unlikely(err))
 541                        goto failed_page;
 542
 543                block_write_end(NULL, inode->i_mapping, pos, blocksize,
 544                                blocksize, page, NULL);
 545
 546                unlock_page(page);
 547                page_cache_release(page);
 548
 549                (*nr_salvaged_blocks)++;
 550                goto next;
 551
 552 failed_page:
 553                unlock_page(page);
 554                page_cache_release(page);
 555
 556 failed_inode:
 557                printk(KERN_WARNING
 558                       "NILFS warning: error recovering data block "
 559                       "(err=%d, ino=%lu, block-offset=%llu)\n",
 560                       err, (unsigned long)rb->ino,
 561                       (unsigned long long)rb->blkoff);
 562                if (!err2)
 563                        err2 = err;
 564 next:
 565                iput(inode); /* iput(NULL) is just ignored */
 566                list_del_init(&rb->list);
 567                kfree(rb);
 568        }
 569        return err2;
 570}
 571
 572/**
 573 * nilfs_do_roll_forward - salvage logical segments newer than the latest
 574 * checkpoint
 575 * @nilfs: nilfs object
 576 * @sb: super block instance
 577 * @ri: pointer to a nilfs_recovery_info
 578 */
 579static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
 580                                 struct super_block *sb,
 581                                 struct nilfs_root *root,
 582                                 struct nilfs_recovery_info *ri)
 583{
 584        struct buffer_head *bh_sum = NULL;
 585        struct nilfs_segment_summary *sum;
 586        sector_t pseg_start;
 587        sector_t seg_start, seg_end;  /* Starting/ending DBN of full segment */
 588        unsigned long nsalvaged_blocks = 0;
 589        unsigned int flags;
 590        u64 seg_seq;
 591        __u64 segnum, nextnum = 0;
 592        int empty_seg = 0;
 593        int err = 0, ret;
 594        LIST_HEAD(dsync_blocks);  /* list of data blocks to be recovered */
 595        enum {
 596                RF_INIT_ST,
 597                RF_DSYNC_ST,   /* scanning data-sync segments */
 598        };
 599        int state = RF_INIT_ST;
 600
 601        pseg_start = ri->ri_lsegs_start;
 602        seg_seq = ri->ri_lsegs_start_seq;
 603        segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);
 604        nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
 605
 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                }
 613
 614                ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
 615                if (ret) {
 616                        if (ret == NILFS_SEG_FAIL_IO) {
 617                                err = -EIO;
 618                                goto failed;
 619                        }
 620                        goto strayed;
 621                }
 622
 623                flags = le16_to_cpu(sum->ss_flags);
 624                if (flags & NILFS_SS_SR)
 625                        goto confused;
 626
 627                /* Found a valid partial segment; do recovery actions */
 628                nextnum = nilfs_get_segnum_of_block(nilfs,
 629                                                    le64_to_cpu(sum->ss_next));
 630                empty_seg = 0;
 631                nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
 632                if (!(flags & NILFS_SS_GC))
 633                        nilfs->ns_nongc_ctime = nilfs->ns_ctime;
 634
 635                switch (state) {
 636                case RF_INIT_ST:
 637                        if (!(flags & NILFS_SS_LOGBGN) ||
 638                            !(flags & NILFS_SS_SYNDT))
 639                                goto try_next_pseg;
 640                        state = RF_DSYNC_ST;
 641                        /* Fall through */
 642                case RF_DSYNC_ST:
 643                        if (!(flags & NILFS_SS_SYNDT))
 644                                goto confused;
 645
 646                        err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
 647                                                   &dsync_blocks);
 648                        if (unlikely(err))
 649                                goto failed;
 650                        if (flags & NILFS_SS_LOGEND) {
 651                                err = nilfs_recover_dsync_blocks(
 652                                        nilfs, sb, root, &dsync_blocks,
 653                                        &nsalvaged_blocks);
 654                                if (unlikely(err))
 655                                        goto failed;
 656                                state = RF_INIT_ST;
 657                        }
 658                        break; /* Fall through to try_next_pseg */
 659                }
 660
 661 try_next_pseg:
 662                if (pseg_start == ri->ri_lsegs_end)
 663                        break;
 664                pseg_start += le32_to_cpu(sum->ss_nblocks);
 665                if (pseg_start < seg_end)
 666                        continue;
 667                goto feed_segment;
 668
 669 strayed:
 670                if (pseg_start == ri->ri_lsegs_end)
 671                        break;
 672
 673 feed_segment:
 674                /* Looking to the next full segment */
 675                if (empty_seg++)
 676                        break;
 677                seg_seq++;
 678                segnum = nextnum;
 679                nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
 680                pseg_start = seg_start;
 681        }
 682
 683        if (nsalvaged_blocks) {
 684                printk(KERN_INFO "NILFS (device %s): salvaged %lu blocks\n",
 685                       sb->s_id, nsalvaged_blocks);
 686                ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
 687        }
 688 out:
 689        brelse(bh_sum);
 690        dispose_recovery_list(&dsync_blocks);
 691        return err;
 692
 693 confused:
 694        err = -EINVAL;
 695 failed:
 696        printk(KERN_ERR
 697               "NILFS (device %s): Error roll-forwarding "
 698               "(err=%d, pseg block=%llu). ",
 699               sb->s_id, err, (unsigned long long)pseg_start);
 700        goto out;
 701}
 702
 703static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
 704                                      struct nilfs_recovery_info *ri)
 705{
 706        struct buffer_head *bh;
 707        int err;
 708
 709        if (nilfs_get_segnum_of_block(nilfs, ri->ri_lsegs_start) !=
 710            nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))
 711                return;
 712
 713        bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);
 714        BUG_ON(!bh);
 715        memset(bh->b_data, 0, bh->b_size);
 716        set_buffer_dirty(bh);
 717        err = sync_dirty_buffer(bh);
 718        if (unlikely(err))
 719                printk(KERN_WARNING
 720                       "NILFS warning: buffer sync write failed during "
 721                       "post-cleaning of recovery.\n");
 722        brelse(bh);
 723}
 724
 725/**
 726 * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
 727 * @nilfs: nilfs object
 728 * @sb: super block instance
 729 * @ri: pointer to a nilfs_recovery_info struct to store search results.
 730 *
 731 * Return Value: On success, 0 is returned.  On error, one of the following
 732 * negative error code is returned.
 733 *
 734 * %-EINVAL - Inconsistent filesystem state.
 735 *
 736 * %-EIO - I/O error
 737 *
 738 * %-ENOSPC - No space left on device (only in a panic state).
 739 *
 740 * %-ERESTARTSYS - Interrupted.
 741 *
 742 * %-ENOMEM - Insufficient memory available.
 743 */
 744int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
 745                              struct super_block *sb,
 746                              struct nilfs_recovery_info *ri)
 747{
 748        struct nilfs_root *root;
 749        int err;
 750
 751        if (ri->ri_lsegs_start == 0 || ri->ri_lsegs_end == 0)
 752                return 0;
 753
 754        err = nilfs_attach_checkpoint(sb, ri->ri_cno, true, &root);
 755        if (unlikely(err)) {
 756                printk(KERN_ERR
 757                       "NILFS: error loading the latest checkpoint.\n");
 758                return err;
 759        }
 760
 761        err = nilfs_do_roll_forward(nilfs, sb, root, ri);
 762        if (unlikely(err))
 763                goto failed;
 764
 765        if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {
 766                err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);
 767                if (unlikely(err)) {
 768                        printk(KERN_ERR "NILFS: Error preparing segments for "
 769                               "recovery.\n");
 770                        goto failed;
 771                }
 772
 773                err = nilfs_attach_log_writer(sb, root);
 774                if (unlikely(err))
 775                        goto failed;
 776
 777                set_nilfs_discontinued(nilfs);
 778                err = nilfs_construct_segment(sb);
 779                nilfs_detach_log_writer(sb);
 780
 781                if (unlikely(err)) {
 782                        printk(KERN_ERR "NILFS: Oops! recovery failed. "
 783                               "(err=%d)\n", err);
 784                        goto failed;
 785                }
 786
 787                nilfs_finish_roll_forward(nilfs, ri);
 788        }
 789
 790 failed:
 791        nilfs_put_root(root);
 792        return err;
 793}
 794
 795/**
 796 * nilfs_search_super_root - search the latest valid super root
 797 * @nilfs: the_nilfs
 798 * @ri: pointer to a nilfs_recovery_info struct to store search results.
 799 *
 800 * nilfs_search_super_root() looks for the latest super-root from a partial
 801 * segment pointed by the superblock.  It sets up struct the_nilfs through
 802 * this search. It fills nilfs_recovery_info (ri) required for recovery.
 803 *
 804 * Return Value: On success, 0 is returned.  On error, one of the following
 805 * negative error code is returned.
 806 *
 807 * %-EINVAL - No valid segment found
 808 *
 809 * %-EIO - I/O error
 810 *
 811 * %-ENOMEM - Insufficient memory available.
 812 */
 813int nilfs_search_super_root(struct the_nilfs *nilfs,
 814                            struct nilfs_recovery_info *ri)
 815{
 816        struct buffer_head *bh_sum = NULL;
 817        struct nilfs_segment_summary *sum;
 818        sector_t pseg_start, pseg_end, sr_pseg_start = 0;
 819        sector_t seg_start, seg_end; /* range of full segment (block number) */
 820        sector_t b, end;
 821        unsigned long nblocks;
 822        unsigned int flags;
 823        u64 seg_seq;
 824        __u64 segnum, nextnum = 0;
 825        __u64 cno;
 826        LIST_HEAD(segments);
 827        int empty_seg = 0, scan_newer = 0;
 828        int ret;
 829
 830        pseg_start = nilfs->ns_last_pseg;
 831        seg_seq = nilfs->ns_last_seq;
 832        cno = nilfs->ns_last_cno;
 833        segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);
 834
 835        /* Calculate range of segment */
 836        nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
 837
 838        /* Read ahead segment */
 839        b = seg_start;
 840        while (b <= seg_end)
 841                __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
 842
 843        for (;;) {
 844                brelse(bh_sum);
 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);
 851                if (ret) {
 852                        if (ret == NILFS_SEG_FAIL_IO)
 853                                goto failed;
 854                        goto strayed;
 855                }
 856
 857                nblocks = le32_to_cpu(sum->ss_nblocks);
 858                pseg_end = pseg_start + nblocks - 1;
 859                if (unlikely(pseg_end > seg_end)) {
 860                        ret = NILFS_SEG_FAIL_CONSISTENCY;
 861                        goto strayed;
 862                }
 863
 864                /* A valid partial segment */
 865                ri->ri_pseg_start = pseg_start;
 866                ri->ri_seq = seg_seq;
 867                ri->ri_segnum = segnum;
 868                nextnum = nilfs_get_segnum_of_block(nilfs,
 869                                                    le64_to_cpu(sum->ss_next));
 870                ri->ri_nextnum = nextnum;
 871                empty_seg = 0;
 872
 873                flags = le16_to_cpu(sum->ss_flags);
 874                if (!(flags & NILFS_SS_SR) && !scan_newer) {
 875                        /* This will never happen because a superblock
 876                           (last_segment) always points to a pseg
 877                           having a super root. */
 878                        ret = NILFS_SEG_FAIL_CONSISTENCY;
 879                        goto failed;
 880                }
 881
 882                if (pseg_start == seg_start) {
 883                        nilfs_get_segment_range(nilfs, nextnum, &b, &end);
 884                        while (b <= end)
 885                                __breadahead(nilfs->ns_bdev, b++,
 886                                             nilfs->ns_blocksize);
 887                }
 888                if (!(flags & NILFS_SS_SR)) {
 889                        if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {
 890                                ri->ri_lsegs_start = pseg_start;
 891                                ri->ri_lsegs_start_seq = seg_seq;
 892                        }
 893                        if (flags & NILFS_SS_LOGEND)
 894                                ri->ri_lsegs_end = pseg_start;
 895                        goto try_next_pseg;
 896                }
 897
 898                /* A valid super root was found. */
 899                ri->ri_cno = cno++;
 900                ri->ri_super_root = pseg_end;
 901                ri->ri_lsegs_start = ri->ri_lsegs_end = 0;
 902
 903                nilfs_dispose_segment_list(&segments);
 904                sr_pseg_start = pseg_start;
 905                nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;
 906                nilfs->ns_seg_seq = seg_seq;
 907                nilfs->ns_segnum = segnum;
 908                nilfs->ns_cno = cno;  /* nilfs->ns_cno = ri->ri_cno + 1 */
 909                nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
 910                nilfs->ns_nextnum = nextnum;
 911
 912                if (scan_newer)
 913                        ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED;
 914                else {
 915                        if (nilfs->ns_mount_state & NILFS_VALID_FS)
 916                                goto super_root_found;
 917                        scan_newer = 1;
 918                }
 919
 920 try_next_pseg:
 921                /* Standing on a course, or met an inconsistent state */
 922                pseg_start += nblocks;
 923                if (pseg_start < seg_end)
 924                        continue;
 925                goto feed_segment;
 926
 927 strayed:
 928                /* Off the trail */
 929                if (!scan_newer)
 930                        /*
 931                         * This can happen if a checkpoint was written without
 932                         * barriers, or as a result of an I/O failure.
 933                         */
 934                        goto failed;
 935
 936 feed_segment:
 937                /* Looking to the next full segment */
 938                if (empty_seg++)
 939                        goto super_root_found; /* found a valid super root */
 940
 941                ret = nilfs_segment_list_add(&segments, segnum);
 942                if (unlikely(ret))
 943                        goto failed;
 944
 945                seg_seq++;
 946                segnum = nextnum;
 947                nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
 948                pseg_start = seg_start;
 949        }
 950
 951 super_root_found:
 952        /* Updating pointers relating to the latest checkpoint */
 953        brelse(bh_sum);
 954        list_splice_tail(&segments, &ri->ri_used_segments);
 955        nilfs->ns_last_pseg = sr_pseg_start;
 956        nilfs->ns_last_seq = nilfs->ns_seg_seq;
 957        nilfs->ns_last_cno = ri->ri_cno;
 958        return 0;
 959
 960 failed:
 961        brelse(bh_sum);
 962        nilfs_dispose_segment_list(&segments);
 963        return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
 964}
 965
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.