brintos

brintos / linux-shallow public Read only

0
0
Text · 24.7 KiB · 21d8109 Raw
999 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS recovery logic4 *5 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Written by Ryusuke Konishi.8 */9 10#include <linux/buffer_head.h>11#include <linux/blkdev.h>12#include <linux/swap.h>13#include <linux/slab.h>14#include <linux/crc32.h>15#include "nilfs.h"16#include "segment.h"17#include "sufile.h"18#include "page.h"19#include "segbuf.h"20 21/*22 * Segment check result23 */24enum {25	NILFS_SEG_VALID,26	NILFS_SEG_NO_SUPER_ROOT,27	NILFS_SEG_FAIL_IO,28	NILFS_SEG_FAIL_MAGIC,29	NILFS_SEG_FAIL_SEQ,30	NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,31	NILFS_SEG_FAIL_CHECKSUM_FULL,32	NILFS_SEG_FAIL_CONSISTENCY,33};34 35/* work structure for recovery */36struct nilfs_recovery_block {37	ino_t ino;		/*38				 * Inode number of the file that this block39				 * belongs to40				 */41	sector_t blocknr;	/* block number */42	__u64 vblocknr;		/* virtual block number */43	unsigned long blkoff;	/* File offset of the data block (per block) */44	struct list_head list;45};46 47 48static int nilfs_warn_segment_error(struct super_block *sb, int err)49{50	const char *msg = NULL;51 52	switch (err) {53	case NILFS_SEG_FAIL_IO:54		nilfs_err(sb, "I/O error reading segment");55		return -EIO;56	case NILFS_SEG_FAIL_MAGIC:57		msg = "Magic number mismatch";58		break;59	case NILFS_SEG_FAIL_SEQ:60		msg = "Sequence number mismatch";61		break;62	case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:63		msg = "Checksum error in super root";64		break;65	case NILFS_SEG_FAIL_CHECKSUM_FULL:66		msg = "Checksum error in segment payload";67		break;68	case NILFS_SEG_FAIL_CONSISTENCY:69		msg = "Inconsistency found";70		break;71	case NILFS_SEG_NO_SUPER_ROOT:72		msg = "No super root in the last segment";73		break;74	default:75		nilfs_err(sb, "unrecognized segment error %d", err);76		return -EINVAL;77	}78	nilfs_warn(sb, "invalid segment: %s", msg);79	return -EINVAL;80}81 82/**83 * nilfs_compute_checksum - compute checksum of blocks continuously84 * @nilfs: nilfs object85 * @bhs: buffer head of start block86 * @sum: place to store result87 * @offset: offset bytes in the first block88 * @check_bytes: number of bytes to be checked89 * @start: DBN of start block90 * @nblock: number of blocks to be checked91 */92static int nilfs_compute_checksum(struct the_nilfs *nilfs,93				  struct buffer_head *bhs, u32 *sum,94				  unsigned long offset, u64 check_bytes,95				  sector_t start, unsigned long nblock)96{97	unsigned int blocksize = nilfs->ns_blocksize;98	unsigned long size;99	u32 crc;100 101	BUG_ON(offset >= blocksize);102	check_bytes -= offset;103	size = min_t(u64, check_bytes, blocksize - offset);104	crc = crc32_le(nilfs->ns_crc_seed,105		       (unsigned char *)bhs->b_data + offset, size);106	if (--nblock > 0) {107		do {108			struct buffer_head *bh;109 110			bh = __bread(nilfs->ns_bdev, ++start, blocksize);111			if (!bh)112				return -EIO;113			check_bytes -= size;114			size = min_t(u64, check_bytes, blocksize);115			crc = crc32_le(crc, bh->b_data, size);116			brelse(bh);117		} while (--nblock > 0);118	}119	*sum = crc;120	return 0;121}122 123/**124 * nilfs_read_super_root_block - read super root block125 * @nilfs: nilfs object126 * @sr_block: disk block number of the super root block127 * @pbh: address of a buffer_head pointer to return super root buffer128 * @check: CRC check flag129 */130int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,131				struct buffer_head **pbh, int check)132{133	struct buffer_head *bh_sr;134	struct nilfs_super_root *sr;135	u32 crc;136	int ret;137 138	*pbh = NULL;139	bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);140	if (unlikely(!bh_sr)) {141		ret = NILFS_SEG_FAIL_IO;142		goto failed;143	}144 145	sr = (struct nilfs_super_root *)bh_sr->b_data;146	if (check) {147		unsigned int bytes = le16_to_cpu(sr->sr_bytes);148 149		if (bytes == 0 || bytes > nilfs->ns_blocksize) {150			ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;151			goto failed_bh;152		}153		if (nilfs_compute_checksum(154			    nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,155			    sr_block, 1)) {156			ret = NILFS_SEG_FAIL_IO;157			goto failed_bh;158		}159		if (crc != le32_to_cpu(sr->sr_sum)) {160			ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;161			goto failed_bh;162		}163	}164	*pbh = bh_sr;165	return 0;166 167 failed_bh:168	brelse(bh_sr);169 170 failed:171	return nilfs_warn_segment_error(nilfs->ns_sb, ret);172}173 174/**175 * nilfs_read_log_header - read summary header of the specified log176 * @nilfs: nilfs object177 * @start_blocknr: start block number of the log178 * @sum: pointer to return segment summary structure179 */180static struct buffer_head *181nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,182		      struct nilfs_segment_summary **sum)183{184	struct buffer_head *bh_sum;185 186	bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);187	if (bh_sum)188		*sum = (struct nilfs_segment_summary *)bh_sum->b_data;189	return bh_sum;190}191 192/**193 * nilfs_validate_log - verify consistency of log194 * @nilfs: nilfs object195 * @seg_seq: sequence number of segment196 * @bh_sum: buffer head of summary block197 * @sum: segment summary struct198 */199static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,200			      struct buffer_head *bh_sum,201			      struct nilfs_segment_summary *sum)202{203	unsigned long nblock;204	u32 crc;205	int ret;206 207	ret = NILFS_SEG_FAIL_MAGIC;208	if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)209		goto out;210 211	ret = NILFS_SEG_FAIL_SEQ;212	if (le64_to_cpu(sum->ss_seq) != seg_seq)213		goto out;214 215	nblock = le32_to_cpu(sum->ss_nblocks);216	ret = NILFS_SEG_FAIL_CONSISTENCY;217	if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))218		/* This limits the number of blocks read in the CRC check */219		goto out;220 221	ret = NILFS_SEG_FAIL_IO;222	if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),223				   ((u64)nblock << nilfs->ns_blocksize_bits),224				   bh_sum->b_blocknr, nblock))225		goto out;226 227	ret = NILFS_SEG_FAIL_CHECKSUM_FULL;228	if (crc != le32_to_cpu(sum->ss_datasum))229		goto out;230	ret = 0;231out:232	return ret;233}234 235/**236 * nilfs_read_summary_info - read an item on summary blocks of a log237 * @nilfs: nilfs object238 * @pbh: the current buffer head on summary blocks [in, out]239 * @offset: the current byte offset on summary blocks [in, out]240 * @bytes: byte size of the item to be read241 */242static void *nilfs_read_summary_info(struct the_nilfs *nilfs,243				     struct buffer_head **pbh,244				     unsigned int *offset, unsigned int bytes)245{246	void *ptr;247	sector_t blocknr;248 249	BUG_ON((*pbh)->b_size < *offset);250	if (bytes > (*pbh)->b_size - *offset) {251		blocknr = (*pbh)->b_blocknr;252		brelse(*pbh);253		*pbh = __bread(nilfs->ns_bdev, blocknr + 1,254			       nilfs->ns_blocksize);255		if (unlikely(!*pbh))256			return NULL;257		*offset = 0;258	}259	ptr = (*pbh)->b_data + *offset;260	*offset += bytes;261	return ptr;262}263 264/**265 * nilfs_skip_summary_info - skip items on summary blocks of a log266 * @nilfs: nilfs object267 * @pbh: the current buffer head on summary blocks [in, out]268 * @offset: the current byte offset on summary blocks [in, out]269 * @bytes: byte size of the item to be skipped270 * @count: number of items to be skipped271 */272static void nilfs_skip_summary_info(struct the_nilfs *nilfs,273				    struct buffer_head **pbh,274				    unsigned int *offset, unsigned int bytes,275				    unsigned long count)276{277	unsigned int rest_item_in_current_block278		= ((*pbh)->b_size - *offset) / bytes;279 280	if (count <= rest_item_in_current_block) {281		*offset += bytes * count;282	} else {283		sector_t blocknr = (*pbh)->b_blocknr;284		unsigned int nitem_per_block = (*pbh)->b_size / bytes;285		unsigned int bcnt;286 287		count -= rest_item_in_current_block;288		bcnt = DIV_ROUND_UP(count, nitem_per_block);289		*offset = bytes * (count - (bcnt - 1) * nitem_per_block);290 291		brelse(*pbh);292		*pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,293			       nilfs->ns_blocksize);294	}295}296 297/**298 * nilfs_scan_dsync_log - get block information of a log written for data sync299 * @nilfs: nilfs object300 * @start_blocknr: start block number of the log301 * @sum: log summary information302 * @head: list head to add nilfs_recovery_block struct303 */304static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,305				struct nilfs_segment_summary *sum,306				struct list_head *head)307{308	struct buffer_head *bh;309	unsigned int offset;310	u32 nfinfo, sumbytes;311	sector_t blocknr;312	ino_t ino;313	int err = -EIO;314 315	nfinfo = le32_to_cpu(sum->ss_nfinfo);316	if (!nfinfo)317		return 0;318 319	sumbytes = le32_to_cpu(sum->ss_sumbytes);320	blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);321	bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);322	if (unlikely(!bh))323		goto out;324 325	offset = le16_to_cpu(sum->ss_bytes);326	for (;;) {327		unsigned long nblocks, ndatablk, nnodeblk;328		struct nilfs_finfo *finfo;329 330		finfo = nilfs_read_summary_info(nilfs, &bh, &offset,331						sizeof(*finfo));332		if (unlikely(!finfo))333			goto out;334 335		ino = le64_to_cpu(finfo->fi_ino);336		nblocks = le32_to_cpu(finfo->fi_nblocks);337		ndatablk = le32_to_cpu(finfo->fi_ndatablk);338		nnodeblk = nblocks - ndatablk;339 340		while (ndatablk-- > 0) {341			struct nilfs_recovery_block *rb;342			struct nilfs_binfo_v *binfo;343 344			binfo = nilfs_read_summary_info(nilfs, &bh, &offset,345							sizeof(*binfo));346			if (unlikely(!binfo))347				goto out;348 349			rb = kmalloc(sizeof(*rb), GFP_NOFS);350			if (unlikely(!rb)) {351				err = -ENOMEM;352				goto out;353			}354			rb->ino = ino;355			rb->blocknr = blocknr++;356			rb->vblocknr = le64_to_cpu(binfo->bi_vblocknr);357			rb->blkoff = le64_to_cpu(binfo->bi_blkoff);358			/* INIT_LIST_HEAD(&rb->list); */359			list_add_tail(&rb->list, head);360		}361		if (--nfinfo == 0)362			break;363		blocknr += nnodeblk; /* always 0 for data sync logs */364		nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),365					nnodeblk);366		if (unlikely(!bh))367			goto out;368	}369	err = 0;370 out:371	brelse(bh);   /* brelse(NULL) is just ignored */372	return err;373}374 375static void dispose_recovery_list(struct list_head *head)376{377	while (!list_empty(head)) {378		struct nilfs_recovery_block *rb;379 380		rb = list_first_entry(head, struct nilfs_recovery_block, list);381		list_del(&rb->list);382		kfree(rb);383	}384}385 386struct nilfs_segment_entry {387	struct list_head	list;388	__u64			segnum;389};390 391static int nilfs_segment_list_add(struct list_head *head, __u64 segnum)392{393	struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);394 395	if (unlikely(!ent))396		return -ENOMEM;397 398	ent->segnum = segnum;399	INIT_LIST_HEAD(&ent->list);400	list_add_tail(&ent->list, head);401	return 0;402}403 404void nilfs_dispose_segment_list(struct list_head *head)405{406	while (!list_empty(head)) {407		struct nilfs_segment_entry *ent;408 409		ent = list_first_entry(head, struct nilfs_segment_entry, list);410		list_del(&ent->list);411		kfree(ent);412	}413}414 415static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,416					      struct super_block *sb,417					      struct nilfs_recovery_info *ri)418{419	struct list_head *head = &ri->ri_used_segments;420	struct nilfs_segment_entry *ent, *n;421	struct inode *sufile = nilfs->ns_sufile;422	__u64 segnum[4];423	int err;424	int i;425 426	segnum[0] = nilfs->ns_segnum;427	segnum[1] = nilfs->ns_nextnum;428	segnum[2] = ri->ri_segnum;429	segnum[3] = ri->ri_nextnum;430 431	/*432	 * Releasing the next segment of the latest super root.433	 * The next segment is invalidated by this recovery.434	 */435	err = nilfs_sufile_free(sufile, segnum[1]);436	if (unlikely(err)) {437		if (err == -ENOENT) {438			nilfs_err(sb,439				  "checkpoint log inconsistency at block %llu (segment %llu): next segment %llu is unallocated",440				  (unsigned long long)nilfs->ns_last_pseg,441				  (unsigned long long)nilfs->ns_segnum,442				  (unsigned long long)segnum[1]);443			err = -EINVAL;444		}445		goto failed;446	}447 448	for (i = 1; i < 4; i++) {449		err = nilfs_segment_list_add(head, segnum[i]);450		if (unlikely(err))451			goto failed;452	}453 454	/*455	 * Collecting segments written after the latest super root.456	 * These are marked dirty to avoid being reallocated in the next write.457	 */458	list_for_each_entry_safe(ent, n, head, list) {459		if (ent->segnum != segnum[0]) {460			err = nilfs_sufile_scrap(sufile, ent->segnum);461			if (unlikely(err))462				goto failed;463		}464		list_del(&ent->list);465		kfree(ent);466	}467 468	/* Allocate new segments for recovery */469	err = nilfs_sufile_alloc(sufile, &segnum[0]);470	if (unlikely(err))471		goto failed;472 473	nilfs->ns_pseg_offset = 0;474	nilfs->ns_seg_seq = ri->ri_seq + 2;475	nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0];476 477 failed:478	/* No need to recover sufile because it will be destroyed on error */479	return err;480}481 482static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,483				     struct nilfs_recovery_block *rb,484				     loff_t pos, struct page *page)485{486	struct buffer_head *bh_org;487	size_t from = pos & ~PAGE_MASK;488	void *kaddr;489 490	bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);491	if (unlikely(!bh_org))492		return -EIO;493 494	kaddr = kmap_local_page(page);495	memcpy(kaddr + from, bh_org->b_data, bh_org->b_size);496	kunmap_local(kaddr);497	brelse(bh_org);498	return 0;499}500 501static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,502				      struct super_block *sb,503				      struct nilfs_root *root,504				      struct list_head *head,505				      unsigned long *nr_salvaged_blocks)506{507	struct inode *inode;508	struct nilfs_recovery_block *rb, *n;509	unsigned int blocksize = nilfs->ns_blocksize;510	struct folio *folio;511	loff_t pos;512	int err = 0, err2 = 0;513 514	list_for_each_entry_safe(rb, n, head, list) {515		inode = nilfs_iget(sb, root, rb->ino);516		if (IS_ERR(inode)) {517			err = PTR_ERR(inode);518			inode = NULL;519			goto failed_inode;520		}521 522		pos = rb->blkoff << inode->i_blkbits;523		err = block_write_begin(inode->i_mapping, pos, blocksize,524					&folio, nilfs_get_block);525		if (unlikely(err)) {526			loff_t isize = inode->i_size;527 528			if (pos + blocksize > isize)529				nilfs_write_failed(inode->i_mapping,530							pos + blocksize);531			goto failed_inode;532		}533 534		err = nilfs_recovery_copy_block(nilfs, rb, pos, &folio->page);535		if (unlikely(err))536			goto failed_page;537 538		err = nilfs_set_file_dirty(inode, 1);539		if (unlikely(err))540			goto failed_page;541 542		block_write_end(NULL, inode->i_mapping, pos, blocksize,543				blocksize, folio, NULL);544 545		folio_unlock(folio);546		folio_put(folio);547 548		(*nr_salvaged_blocks)++;549		goto next;550 551 failed_page:552		folio_unlock(folio);553		folio_put(folio);554 555 failed_inode:556		nilfs_warn(sb,557			   "error %d recovering data block (ino=%lu, block-offset=%llu)",558			   err, (unsigned long)rb->ino,559			   (unsigned long long)rb->blkoff);560		if (!err2)561			err2 = err;562 next:563		iput(inode); /* iput(NULL) is just ignored */564		list_del_init(&rb->list);565		kfree(rb);566	}567	return err2;568}569 570/**571 * nilfs_do_roll_forward - salvage logical segments newer than the latest572 * checkpoint573 * @nilfs: nilfs object574 * @sb: super block instance575 * @root: NILFS root instance576 * @ri: pointer to a nilfs_recovery_info577 */578static int nilfs_do_roll_forward(struct the_nilfs *nilfs,579				 struct super_block *sb,580				 struct nilfs_root *root,581				 struct nilfs_recovery_info *ri)582{583	struct buffer_head *bh_sum = NULL;584	struct nilfs_segment_summary *sum = NULL;585	sector_t pseg_start;586	sector_t seg_start, seg_end;  /* Starting/ending DBN of full segment */587	unsigned long nsalvaged_blocks = 0;588	unsigned int flags;589	u64 seg_seq;590	__u64 segnum, nextnum = 0;591	int empty_seg = 0;592	int err = 0, ret;593	LIST_HEAD(dsync_blocks);  /* list of data blocks to be recovered */594	enum {595		RF_INIT_ST,596		RF_DSYNC_ST,   /* scanning data-sync segments */597	};598	int state = RF_INIT_ST;599 600	pseg_start = ri->ri_lsegs_start;601	seg_seq = ri->ri_lsegs_start_seq;602	segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);603	nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);604 605	while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {606		brelse(bh_sum);607		bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);608		if (!bh_sum) {609			err = -EIO;610			goto failed;611		}612 613		ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);614		if (ret) {615			if (ret == NILFS_SEG_FAIL_IO) {616				err = -EIO;617				goto failed;618			}619			goto strayed;620		}621 622		flags = le16_to_cpu(sum->ss_flags);623		if (flags & NILFS_SS_SR)624			goto confused;625 626		/* Found a valid partial segment; do recovery actions */627		nextnum = nilfs_get_segnum_of_block(nilfs,628						    le64_to_cpu(sum->ss_next));629		empty_seg = 0;630		nilfs->ns_ctime = le64_to_cpu(sum->ss_create);631		if (!(flags & NILFS_SS_GC))632			nilfs->ns_nongc_ctime = nilfs->ns_ctime;633 634		switch (state) {635		case RF_INIT_ST:636			if (!(flags & NILFS_SS_LOGBGN) ||637			    !(flags & NILFS_SS_SYNDT))638				goto try_next_pseg;639			state = RF_DSYNC_ST;640			fallthrough;641		case RF_DSYNC_ST:642			if (!(flags & NILFS_SS_SYNDT))643				goto confused;644 645			err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,646						   &dsync_blocks);647			if (unlikely(err))648				goto failed;649			if (flags & NILFS_SS_LOGEND) {650				err = nilfs_recover_dsync_blocks(651					nilfs, sb, root, &dsync_blocks,652					&nsalvaged_blocks);653				if (unlikely(err))654					goto failed;655				state = RF_INIT_ST;656			}657			break; /* Fall through to try_next_pseg */658		}659 660 try_next_pseg:661		if (pseg_start == ri->ri_lsegs_end)662			break;663		pseg_start += le32_to_cpu(sum->ss_nblocks);664		if (pseg_start < seg_end)665			continue;666		goto feed_segment;667 668 strayed:669		if (pseg_start == ri->ri_lsegs_end)670			break;671 672 feed_segment:673		/* Looking to the next full segment */674		if (empty_seg++)675			break;676		seg_seq++;677		segnum = nextnum;678		nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);679		pseg_start = seg_start;680	}681 682	if (nsalvaged_blocks) {683		nilfs_info(sb, "salvaged %lu blocks", nsalvaged_blocks);684		ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;685	}686 out:687	brelse(bh_sum);688	dispose_recovery_list(&dsync_blocks);689	return err;690 691 confused:692	err = -EINVAL;693 failed:694	nilfs_err(sb,695		  "error %d roll-forwarding partial segment at blocknr = %llu",696		  err, (unsigned long long)pseg_start);697	goto out;698}699 700static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,701				      struct nilfs_recovery_info *ri)702{703	struct buffer_head *bh;704	int err;705 706	if (nilfs_get_segnum_of_block(nilfs, ri->ri_lsegs_start) !=707	    nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))708		return;709 710	bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);711	if (WARN_ON(!bh))712		return;  /* should never happen */713 714	lock_buffer(bh);715	memset(bh->b_data, 0, bh->b_size);716	set_buffer_uptodate(bh);717	set_buffer_dirty(bh);718	unlock_buffer(bh);719 720	err = sync_dirty_buffer(bh);721	if (unlikely(err))722		nilfs_warn(nilfs->ns_sb,723			   "buffer sync write failed during post-cleaning of recovery.");724	brelse(bh);725}726 727/**728 * nilfs_abort_roll_forward - cleaning up after a failed rollforward recovery729 * @nilfs: nilfs object730 */731static void nilfs_abort_roll_forward(struct the_nilfs *nilfs)732{733	struct nilfs_inode_info *ii, *n;734	LIST_HEAD(head);735 736	/* Abandon inodes that have read recovery data */737	spin_lock(&nilfs->ns_inode_lock);738	list_splice_init(&nilfs->ns_dirty_files, &head);739	spin_unlock(&nilfs->ns_inode_lock);740	if (list_empty(&head))741		return;742 743	set_nilfs_purging(nilfs);744	list_for_each_entry_safe(ii, n, &head, i_dirty) {745		spin_lock(&nilfs->ns_inode_lock);746		list_del_init(&ii->i_dirty);747		spin_unlock(&nilfs->ns_inode_lock);748 749		iput(&ii->vfs_inode);750	}751	clear_nilfs_purging(nilfs);752}753 754/**755 * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint756 * @nilfs: nilfs object757 * @sb: super block instance758 * @ri: pointer to a nilfs_recovery_info struct to store search results.759 *760 * Return Value: On success, 0 is returned.  On error, one of the following761 * negative error code is returned.762 *763 * %-EINVAL - Inconsistent filesystem state.764 *765 * %-EIO - I/O error766 *767 * %-ENOSPC - No space left on device (only in a panic state).768 *769 * %-ERESTARTSYS - Interrupted.770 *771 * %-ENOMEM - Insufficient memory available.772 */773int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,774			      struct super_block *sb,775			      struct nilfs_recovery_info *ri)776{777	struct nilfs_root *root;778	int err;779 780	if (ri->ri_lsegs_start == 0 || ri->ri_lsegs_end == 0)781		return 0;782 783	err = nilfs_attach_checkpoint(sb, ri->ri_cno, true, &root);784	if (unlikely(err)) {785		nilfs_err(sb, "error %d loading the latest checkpoint", err);786		return err;787	}788 789	err = nilfs_do_roll_forward(nilfs, sb, root, ri);790	if (unlikely(err))791		goto failed;792 793	if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {794		err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);795		if (unlikely(err)) {796			nilfs_err(sb, "error %d preparing segment for recovery",797				  err);798			goto failed;799		}800 801		err = nilfs_attach_log_writer(sb, root);802		if (unlikely(err))803			goto failed;804 805		set_nilfs_discontinued(nilfs);806		err = nilfs_construct_segment(sb);807		nilfs_detach_log_writer(sb);808 809		if (unlikely(err)) {810			nilfs_err(sb, "error %d writing segment for recovery",811				  err);812			goto put_root;813		}814 815		nilfs_finish_roll_forward(nilfs, ri);816	}817 818put_root:819	nilfs_put_root(root);820	return err;821 822failed:823	nilfs_abort_roll_forward(nilfs);824	goto put_root;825}826 827/**828 * nilfs_search_super_root - search the latest valid super root829 * @nilfs: the_nilfs830 * @ri: pointer to a nilfs_recovery_info struct to store search results.831 *832 * nilfs_search_super_root() looks for the latest super-root from a partial833 * segment pointed by the superblock.  It sets up struct the_nilfs through834 * this search. It fills nilfs_recovery_info (ri) required for recovery.835 *836 * Return Value: On success, 0 is returned.  On error, one of the following837 * negative error code is returned.838 *839 * %-EINVAL - No valid segment found840 *841 * %-EIO - I/O error842 *843 * %-ENOMEM - Insufficient memory available.844 */845int nilfs_search_super_root(struct the_nilfs *nilfs,846			    struct nilfs_recovery_info *ri)847{848	struct buffer_head *bh_sum = NULL;849	struct nilfs_segment_summary *sum = NULL;850	sector_t pseg_start, pseg_end, sr_pseg_start = 0;851	sector_t seg_start, seg_end; /* range of full segment (block number) */852	sector_t b, end;853	unsigned long nblocks;854	unsigned int flags;855	u64 seg_seq;856	__u64 segnum, nextnum = 0;857	__u64 cno;858	LIST_HEAD(segments);859	int empty_seg = 0, scan_newer = 0;860	int ret;861 862	pseg_start = nilfs->ns_last_pseg;863	seg_seq = nilfs->ns_last_seq;864	cno = nilfs->ns_last_cno;865	segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);866 867	/* Calculate range of segment */868	nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);869 870	/* Read ahead segment */871	b = seg_start;872	while (b <= seg_end)873		__breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);874 875	for (;;) {876		brelse(bh_sum);877		ret = NILFS_SEG_FAIL_IO;878		bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);879		if (!bh_sum)880			goto failed;881 882		ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);883		if (ret) {884			if (ret == NILFS_SEG_FAIL_IO)885				goto failed;886			goto strayed;887		}888 889		nblocks = le32_to_cpu(sum->ss_nblocks);890		pseg_end = pseg_start + nblocks - 1;891		if (unlikely(pseg_end > seg_end)) {892			ret = NILFS_SEG_FAIL_CONSISTENCY;893			goto strayed;894		}895 896		/* A valid partial segment */897		ri->ri_pseg_start = pseg_start;898		ri->ri_seq = seg_seq;899		ri->ri_segnum = segnum;900		nextnum = nilfs_get_segnum_of_block(nilfs,901						    le64_to_cpu(sum->ss_next));902		ri->ri_nextnum = nextnum;903		empty_seg = 0;904 905		flags = le16_to_cpu(sum->ss_flags);906		if (!(flags & NILFS_SS_SR) && !scan_newer) {907			/*908			 * This will never happen because a superblock909			 * (last_segment) always points to a pseg with910			 * a super root.911			 */912			ret = NILFS_SEG_FAIL_CONSISTENCY;913			goto failed;914		}915 916		if (pseg_start == seg_start) {917			nilfs_get_segment_range(nilfs, nextnum, &b, &end);918			while (b <= end)919				__breadahead(nilfs->ns_bdev, b++,920					     nilfs->ns_blocksize);921		}922		if (!(flags & NILFS_SS_SR)) {923			if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {924				ri->ri_lsegs_start = pseg_start;925				ri->ri_lsegs_start_seq = seg_seq;926			}927			if (flags & NILFS_SS_LOGEND)928				ri->ri_lsegs_end = pseg_start;929			goto try_next_pseg;930		}931 932		/* A valid super root was found. */933		ri->ri_cno = cno++;934		ri->ri_super_root = pseg_end;935		ri->ri_lsegs_start = ri->ri_lsegs_end = 0;936 937		nilfs_dispose_segment_list(&segments);938		sr_pseg_start = pseg_start;939		nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;940		nilfs->ns_seg_seq = seg_seq;941		nilfs->ns_segnum = segnum;942		nilfs->ns_cno = cno;  /* nilfs->ns_cno = ri->ri_cno + 1 */943		nilfs->ns_ctime = le64_to_cpu(sum->ss_create);944		nilfs->ns_nextnum = nextnum;945 946		if (scan_newer)947			ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED;948		else {949			if (nilfs->ns_mount_state & NILFS_VALID_FS)950				goto super_root_found;951			scan_newer = 1;952		}953 954 try_next_pseg:955		/* Standing on a course, or met an inconsistent state */956		pseg_start += nblocks;957		if (pseg_start < seg_end)958			continue;959		goto feed_segment;960 961 strayed:962		/* Off the trail */963		if (!scan_newer)964			/*965			 * This can happen if a checkpoint was written without966			 * barriers, or as a result of an I/O failure.967			 */968			goto failed;969 970 feed_segment:971		/* Looking to the next full segment */972		if (empty_seg++)973			goto super_root_found; /* found a valid super root */974 975		ret = nilfs_segment_list_add(&segments, segnum);976		if (unlikely(ret))977			goto failed;978 979		seg_seq++;980		segnum = nextnum;981		nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);982		pseg_start = seg_start;983	}984 985 super_root_found:986	/* Updating pointers relating to the latest checkpoint */987	brelse(bh_sum);988	list_splice_tail(&segments, &ri->ri_used_segments);989	nilfs->ns_last_pseg = sr_pseg_start;990	nilfs->ns_last_seq = nilfs->ns_seg_seq;991	nilfs->ns_last_cno = ri->ri_cno;992	return 0;993 994 failed:995	brelse(bh_sum);996	nilfs_dispose_segment_list(&segments);997	return ret < 0 ? ret : nilfs_warn_segment_error(nilfs->ns_sb, ret);998}999