diff options
Diffstat (limited to 'fs/f2fs/checkpoint.c')
-rw-r--r-- | fs/f2fs/checkpoint.c | 99 |
1 files changed, 76 insertions, 23 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index b1de01da1a40..66a6b85a51d8 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -357,8 +357,8 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, | |||
357 | unsigned long blk_size = sbi->blocksize; | 357 | unsigned long blk_size = sbi->blocksize; |
358 | struct f2fs_checkpoint *cp_block; | 358 | struct f2fs_checkpoint *cp_block; |
359 | unsigned long long cur_version = 0, pre_version = 0; | 359 | unsigned long long cur_version = 0, pre_version = 0; |
360 | unsigned int crc = 0; | ||
361 | size_t crc_offset; | 360 | size_t crc_offset; |
361 | __u32 crc = 0; | ||
362 | 362 | ||
363 | /* Read the 1st cp block in this CP pack */ | 363 | /* Read the 1st cp block in this CP pack */ |
364 | cp_page_1 = get_meta_page(sbi, cp_addr); | 364 | cp_page_1 = get_meta_page(sbi, cp_addr); |
@@ -369,7 +369,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, | |||
369 | if (crc_offset >= blk_size) | 369 | if (crc_offset >= blk_size) |
370 | goto invalid_cp1; | 370 | goto invalid_cp1; |
371 | 371 | ||
372 | crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); | 372 | crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset))); |
373 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) | 373 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) |
374 | goto invalid_cp1; | 374 | goto invalid_cp1; |
375 | 375 | ||
@@ -384,7 +384,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, | |||
384 | if (crc_offset >= blk_size) | 384 | if (crc_offset >= blk_size) |
385 | goto invalid_cp2; | 385 | goto invalid_cp2; |
386 | 386 | ||
387 | crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); | 387 | crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset))); |
388 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) | 388 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) |
389 | goto invalid_cp2; | 389 | goto invalid_cp2; |
390 | 390 | ||
@@ -450,13 +450,30 @@ fail_no_cp: | |||
450 | return -EINVAL; | 450 | return -EINVAL; |
451 | } | 451 | } |
452 | 452 | ||
453 | void set_dirty_dir_page(struct inode *inode, struct page *page) | 453 | static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) |
454 | { | 454 | { |
455 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | 455 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); |
456 | struct list_head *head = &sbi->dir_inode_list; | 456 | struct list_head *head = &sbi->dir_inode_list; |
457 | struct dir_inode_entry *new; | ||
458 | struct list_head *this; | 457 | struct list_head *this; |
459 | 458 | ||
459 | list_for_each(this, head) { | ||
460 | struct dir_inode_entry *entry; | ||
461 | entry = list_entry(this, struct dir_inode_entry, list); | ||
462 | if (entry->inode == inode) | ||
463 | return -EEXIST; | ||
464 | } | ||
465 | list_add_tail(&new->list, head); | ||
466 | #ifdef CONFIG_F2FS_STAT_FS | ||
467 | sbi->n_dirty_dirs++; | ||
468 | #endif | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | void set_dirty_dir_page(struct inode *inode, struct page *page) | ||
473 | { | ||
474 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | ||
475 | struct dir_inode_entry *new; | ||
476 | |||
460 | if (!S_ISDIR(inode->i_mode)) | 477 | if (!S_ISDIR(inode->i_mode)) |
461 | return; | 478 | return; |
462 | retry: | 479 | retry: |
@@ -469,23 +486,31 @@ retry: | |||
469 | INIT_LIST_HEAD(&new->list); | 486 | INIT_LIST_HEAD(&new->list); |
470 | 487 | ||
471 | spin_lock(&sbi->dir_inode_lock); | 488 | spin_lock(&sbi->dir_inode_lock); |
472 | list_for_each(this, head) { | 489 | if (__add_dirty_inode(inode, new)) |
473 | struct dir_inode_entry *entry; | 490 | kmem_cache_free(inode_entry_slab, new); |
474 | entry = list_entry(this, struct dir_inode_entry, list); | ||
475 | if (entry->inode == inode) { | ||
476 | kmem_cache_free(inode_entry_slab, new); | ||
477 | goto out; | ||
478 | } | ||
479 | } | ||
480 | list_add_tail(&new->list, head); | ||
481 | sbi->n_dirty_dirs++; | ||
482 | 491 | ||
483 | BUG_ON(!S_ISDIR(inode->i_mode)); | ||
484 | out: | ||
485 | inc_page_count(sbi, F2FS_DIRTY_DENTS); | 492 | inc_page_count(sbi, F2FS_DIRTY_DENTS); |
486 | inode_inc_dirty_dents(inode); | 493 | inode_inc_dirty_dents(inode); |
487 | SetPagePrivate(page); | 494 | SetPagePrivate(page); |
495 | spin_unlock(&sbi->dir_inode_lock); | ||
496 | } | ||
488 | 497 | ||
498 | void add_dirty_dir_inode(struct inode *inode) | ||
499 | { | ||
500 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | ||
501 | struct dir_inode_entry *new; | ||
502 | retry: | ||
503 | new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS); | ||
504 | if (!new) { | ||
505 | cond_resched(); | ||
506 | goto retry; | ||
507 | } | ||
508 | new->inode = inode; | ||
509 | INIT_LIST_HEAD(&new->list); | ||
510 | |||
511 | spin_lock(&sbi->dir_inode_lock); | ||
512 | if (__add_dirty_inode(inode, new)) | ||
513 | kmem_cache_free(inode_entry_slab, new); | ||
489 | spin_unlock(&sbi->dir_inode_lock); | 514 | spin_unlock(&sbi->dir_inode_lock); |
490 | } | 515 | } |
491 | 516 | ||
@@ -499,8 +524,10 @@ void remove_dirty_dir_inode(struct inode *inode) | |||
499 | return; | 524 | return; |
500 | 525 | ||
501 | spin_lock(&sbi->dir_inode_lock); | 526 | spin_lock(&sbi->dir_inode_lock); |
502 | if (atomic_read(&F2FS_I(inode)->dirty_dents)) | 527 | if (atomic_read(&F2FS_I(inode)->dirty_dents)) { |
503 | goto out; | 528 | spin_unlock(&sbi->dir_inode_lock); |
529 | return; | ||
530 | } | ||
504 | 531 | ||
505 | list_for_each(this, head) { | 532 | list_for_each(this, head) { |
506 | struct dir_inode_entry *entry; | 533 | struct dir_inode_entry *entry; |
@@ -508,12 +535,38 @@ void remove_dirty_dir_inode(struct inode *inode) | |||
508 | if (entry->inode == inode) { | 535 | if (entry->inode == inode) { |
509 | list_del(&entry->list); | 536 | list_del(&entry->list); |
510 | kmem_cache_free(inode_entry_slab, entry); | 537 | kmem_cache_free(inode_entry_slab, entry); |
538 | #ifdef CONFIG_F2FS_STAT_FS | ||
511 | sbi->n_dirty_dirs--; | 539 | sbi->n_dirty_dirs--; |
540 | #endif | ||
541 | break; | ||
542 | } | ||
543 | } | ||
544 | spin_unlock(&sbi->dir_inode_lock); | ||
545 | |||
546 | /* Only from the recovery routine */ | ||
547 | if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { | ||
548 | clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); | ||
549 | iput(inode); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino) | ||
554 | { | ||
555 | struct list_head *head = &sbi->dir_inode_list; | ||
556 | struct list_head *this; | ||
557 | struct inode *inode = NULL; | ||
558 | |||
559 | spin_lock(&sbi->dir_inode_lock); | ||
560 | list_for_each(this, head) { | ||
561 | struct dir_inode_entry *entry; | ||
562 | entry = list_entry(this, struct dir_inode_entry, list); | ||
563 | if (entry->inode->i_ino == ino) { | ||
564 | inode = entry->inode; | ||
512 | break; | 565 | break; |
513 | } | 566 | } |
514 | } | 567 | } |
515 | out: | ||
516 | spin_unlock(&sbi->dir_inode_lock); | 568 | spin_unlock(&sbi->dir_inode_lock); |
569 | return inode; | ||
517 | } | 570 | } |
518 | 571 | ||
519 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) | 572 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) |
@@ -595,7 +648,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) | |||
595 | block_t start_blk; | 648 | block_t start_blk; |
596 | struct page *cp_page; | 649 | struct page *cp_page; |
597 | unsigned int data_sum_blocks, orphan_blocks; | 650 | unsigned int data_sum_blocks, orphan_blocks; |
598 | unsigned int crc32 = 0; | 651 | __u32 crc32 = 0; |
599 | void *kaddr; | 652 | void *kaddr; |
600 | int i; | 653 | int i; |
601 | 654 | ||
@@ -664,8 +717,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) | |||
664 | get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); | 717 | get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); |
665 | 718 | ||
666 | crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); | 719 | crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); |
667 | *(__le32 *)((unsigned char *)ckpt + | 720 | *((__le32 *)((unsigned char *)ckpt + |
668 | le32_to_cpu(ckpt->checksum_offset)) | 721 | le32_to_cpu(ckpt->checksum_offset))) |
669 | = cpu_to_le32(crc32); | 722 | = cpu_to_le32(crc32); |
670 | 723 | ||
671 | start_blk = __start_cp_addr(sbi); | 724 | start_blk = __start_cp_addr(sbi); |