recovery.c 9.4 KB
Newer Older
J
Jaegeuk Kim 已提交
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 * fs/f2fs/recovery.c
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 *             http://www.samsung.com/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include "f2fs.h"
#include "node.h"
#include "segment.h"

static struct kmem_cache *fsync_entry_slab;

bool space_for_roll_forward(struct f2fs_sb_info *sbi)
{
	if (sbi->last_valid_block_count + sbi->alloc_valid_block_count
			> sbi->user_block_count)
		return false;
	return true;
}

static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
								nid_t ino)
{
	struct list_head *this;
	struct fsync_inode_entry *entry;

	list_for_each(this, head) {
		entry = list_entry(this, struct fsync_inode_entry, list);
		if (entry->inode->i_ino == ino)
			return entry;
	}
	return NULL;
}

static int recover_dentry(struct page *ipage, struct inode *inode)
{
	struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage);
	struct f2fs_inode *raw_inode = &(raw_node->i);
45
	struct qstr name;
46 47 48 49 50 51 52 53 54 55
	struct f2fs_dir_entry *de;
	struct page *page;
	struct inode *dir;
	int err = 0;

	if (!is_dent_dnode(ipage))
		goto out;

	dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino));
	if (IS_ERR(dir)) {
56
		err = PTR_ERR(dir);
57 58 59
		goto out;
	}

60 61
	name.len = le32_to_cpu(raw_inode->i_namelen);
	name.name = raw_inode->i_name;
62

63
	de = f2fs_find_entry(dir, &name, &page);
64 65 66 67
	if (de) {
		kunmap(page);
		f2fs_put_page(page, 0);
	} else {
68
		err = __f2fs_add_link(dir, &name, inode);
69 70 71 72 73 74 75 76 77 78 79 80 81
	}
	iput(dir);
out:
	kunmap(ipage);
	return err;
}

static int recover_inode(struct inode *inode, struct page *node_page)
{
	void *kaddr = page_address(node_page);
	struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
	struct f2fs_inode *raw_inode = &(raw_node->i);

82
	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	i_size_write(inode, le64_to_cpu(raw_inode->i_size));
	inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime);
	inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime);
	inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime);
	inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
	inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec);
	inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);

	return recover_dentry(node_page, inode);
}

static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
{
	unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver);
	struct curseg_info *curseg;
	struct page *page;
	block_t blkaddr;
	int err = 0;

	/* get node pages in the current segment */
	curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
	blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff;

	/* read node page */
	page = alloc_page(GFP_F2FS_ZERO);
	if (IS_ERR(page))
		return PTR_ERR(page);
	lock_page(page);

	while (1) {
		struct fsync_inode_entry *entry;

115 116
		err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC);
		if (err)
117 118
			goto out;

119 120
		lock_page(page);

121
		if (cp_ver != cpver_of_node(page))
122
			goto unlock_out;
123 124 125 126 127 128 129 130 131 132 133

		if (!is_fsync_dnode(page))
			goto next;

		entry = get_fsync_inode(head, ino_of_node(page));
		if (entry) {
			if (IS_INODE(page) && is_dent_dnode(page))
				set_inode_flag(F2FS_I(entry->inode),
							FI_INC_LINK);
		} else {
			if (IS_INODE(page) && is_dent_dnode(page)) {
134 135
				err = recover_inode_page(sbi, page);
				if (err)
136
					goto unlock_out;
137 138 139 140 141 142
			}

			/* add this fsync inode to the list */
			entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS);
			if (!entry) {
				err = -ENOMEM;
143
				goto unlock_out;
144 145 146 147 148
			}

			entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
			if (IS_ERR(entry->inode)) {
				err = PTR_ERR(entry->inode);
149
				kmem_cache_free(fsync_entry_slab, entry);
150
				goto unlock_out;
151
			}
152
			list_add_tail(&entry->list, head);
153
		}
J
Jaegeuk Kim 已提交
154 155
		entry->blkaddr = blkaddr;

156 157
		if (IS_INODE(page)) {
			err = recover_inode(entry->inode, page);
158 159 160 161
			if (err == -ENOENT) {
				goto next;
			} else if (err) {
				err = -EINVAL;
162
				goto unlock_out;
163
			}
164 165 166 167 168
		}
next:
		/* check next segment */
		blkaddr = next_blkaddr_of_node(page);
	}
169
unlock_out:
170
	unlock_page(page);
171
out:
172 173 174 175 176 177 178
	__free_pages(page, 0);
	return err;
}

static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi,
					struct list_head *head)
{
179 180 181
	struct fsync_inode_entry *entry, *tmp;

	list_for_each_entry_safe(entry, tmp, head, list) {
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
		iput(entry->inode);
		list_del(&entry->list);
		kmem_cache_free(fsync_entry_slab, entry);
	}
}

static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
						block_t blkaddr)
{
	struct seg_entry *sentry;
	unsigned int segno = GET_SEGNO(sbi, blkaddr);
	unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) &
					(sbi->blocks_per_seg - 1);
	struct f2fs_summary sum;
	nid_t ino;
	void *kaddr;
	struct inode *inode;
	struct page *node_page;
	block_t bidx;
	int i;

	sentry = get_seg_entry(sbi, segno);
	if (!f2fs_test_bit(blkoff, sentry->cur_valid_map))
		return;

	/* Get the previous summary */
	for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) {
		struct curseg_info *curseg = CURSEG_I(sbi, i);
		if (curseg->segno == segno) {
			sum = curseg->sum_blk->entries[blkoff];
			break;
		}
	}
	if (i > CURSEG_COLD_DATA) {
		struct page *sum_page = get_sum_page(sbi, segno);
		struct f2fs_summary_block *sum_node;
		kaddr = page_address(sum_page);
		sum_node = (struct f2fs_summary_block *)kaddr;
		sum = sum_node->entries[blkoff];
		f2fs_put_page(sum_page, 1);
	}

	/* Get the node page */
	node_page = get_node_page(sbi, le32_to_cpu(sum.nid));
	bidx = start_bidx_of_node(ofs_of_node(node_page)) +
				le16_to_cpu(sum.ofs_in_node);
	ino = ino_of_node(node_page);
	f2fs_put_page(node_page, 1);

	/* Deallocate previous index in the node page */
232
	inode = f2fs_iget(sbi->sb, ino);
233 234 235
	if (IS_ERR(inode))
		return;

236 237 238 239
	truncate_hole(inode, bidx, bidx + 1);
	iput(inode);
}

240
static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
241 242 243 244 245 246
					struct page *page, block_t blkaddr)
{
	unsigned int start, end;
	struct dnode_of_data dn;
	struct f2fs_summary sum;
	struct node_info ni;
247
	int err = 0;
248
	int ilock;
249 250 251 252 253 254 255

	start = start_bidx_of_node(ofs_of_node(page));
	if (IS_INODE(page))
		end = start + ADDRS_PER_INODE;
	else
		end = start + ADDRS_PER_BLOCK;

256
	ilock = mutex_lock_op(sbi);
257
	set_new_dnode(&dn, inode, NULL, NULL, 0);
258

259
	err = get_dnode_of_data(&dn, start, ALLOC_NODE);
260 261
	if (err) {
		mutex_unlock_op(sbi, ilock);
262
		return err;
263
	}
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

	wait_on_page_writeback(dn.node_page);

	get_node_info(sbi, dn.nid, &ni);
	BUG_ON(ni.ino != ino_of_node(page));
	BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page));

	for (; start < end; start++) {
		block_t src, dest;

		src = datablock_addr(dn.node_page, dn.ofs_in_node);
		dest = datablock_addr(page, dn.ofs_in_node);

		if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) {
			if (src == NULL_ADDR) {
				int err = reserve_new_block(&dn);
				/* We should not get -ENOSPC */
				BUG_ON(err);
			}

			/* Check the previous node page having this index */
			check_index_in_prev_nodes(sbi, dest);

			set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);

			/* write dummy data page */
			recover_data_page(sbi, NULL, &sum, src, dest);
			update_extent_cache(dest, &dn);
		}
		dn.ofs_in_node++;
	}

	/* write node page in place */
	set_summary(&sum, dn.nid, 0, 0);
	if (IS_INODE(dn.node_page))
		sync_inode_page(&dn);

	copy_node_footer(dn.node_page, page);
	fill_node_footer(dn.node_page, dn.nid, ni.ino,
					ofs_of_node(page), false);
	set_page_dirty(dn.node_page);

	recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
	f2fs_put_dnode(&dn);
308
	mutex_unlock_op(sbi, ilock);
309
	return 0;
310 311
}

312
static int recover_data(struct f2fs_sb_info *sbi,
313 314 315 316 317
				struct list_head *head, int type)
{
	unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver);
	struct curseg_info *curseg;
	struct page *page;
318
	int err = 0;
319 320 321 322 323 324 325 326 327
	block_t blkaddr;

	/* get node pages in the current segment */
	curseg = CURSEG_I(sbi, type);
	blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);

	/* read node page */
	page = alloc_page(GFP_NOFS | __GFP_ZERO);
	if (IS_ERR(page))
328 329
		return -ENOMEM;

330 331 332 333 334
	lock_page(page);

	while (1) {
		struct fsync_inode_entry *entry;

335 336
		err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC);
		if (err)
337 338
			goto out;

339 340
		lock_page(page);

341
		if (cp_ver != cpver_of_node(page))
342
			goto unlock_out;
343 344 345 346 347

		entry = get_fsync_inode(head, ino_of_node(page));
		if (!entry)
			goto next;

348 349 350
		err = do_recover_data(sbi, entry->inode, page, blkaddr);
		if (err)
			goto out;
351 352 353 354 355 356 357 358 359 360

		if (entry->blkaddr == blkaddr) {
			iput(entry->inode);
			list_del(&entry->list);
			kmem_cache_free(fsync_entry_slab, entry);
		}
next:
		/* check next segment */
		blkaddr = next_blkaddr_of_node(page);
	}
361
unlock_out:
362
	unlock_page(page);
363
out:
364 365
	__free_pages(page, 0);

366 367 368
	if (!err)
		allocate_new_segments(sbi);
	return err;
369 370
}

371
int recover_fsync_data(struct f2fs_sb_info *sbi)
372 373
{
	struct list_head inode_list;
374
	int err;
375 376 377 378

	fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
			sizeof(struct fsync_inode_entry), NULL);
	if (unlikely(!fsync_entry_slab))
379
		return -ENOMEM;
380 381 382 383

	INIT_LIST_HEAD(&inode_list);

	/* step #1: find fsynced inode numbers */
384 385
	err = find_fsync_dnodes(sbi, &inode_list);
	if (err)
386 387 388 389 390 391 392
		goto out;

	if (list_empty(&inode_list))
		goto out;

	/* step #2: recover data */
	sbi->por_doing = 1;
393
	err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
394 395 396 397 398
	sbi->por_doing = 0;
	BUG_ON(!list_empty(&inode_list));
out:
	destroy_fsync_dnodes(sbi, &inode_list);
	kmem_cache_destroy(fsync_entry_slab);
399
	write_checkpoint(sbi, false);
400
	return err;
401
}