Merge tag 'f2fs-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 Apr 2016 20:00:39 +0000 (13:00 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 Apr 2016 20:00:39 +0000 (13:00 -0700)
Pull f2fs fixes from Jaegeuk Kim.

* tag 'f2fs-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: retrieve IO write stat from the right place
  f2fs crypto: fix corrupted symlink in encrypted case
  f2fs: cover large section in sanity check of super

1  2 
fs/f2fs/namei.c
fs/f2fs/super.c

diff --combined fs/f2fs/namei.c
index c1d9e9d2cb37735576dd58c08703f504666c34c1,6214d9ec89f2cd76f11cb9225400b9afc05d1f6d..013e57932d615fec6dcc8ce1f2246cd0a0a36c0e
@@@ -1027,12 -1027,6 +1027,6 @@@ static const char *f2fs_encrypted_get_l
                goto errout;
        }
  
-       /* this is broken symlink case */
-       if (unlikely(cstr.name[0] == 0)) {
-               res = -ENOENT;
-               goto errout;
-       }
        if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
                /* Symlink data on the disk is corrupted */
                res = -EIO;
        if (res < 0)
                goto errout;
  
+       /* this is broken symlink case */
+       if (unlikely(pstr.name[0] == 0)) {
+               res = -ENOENT;
+               goto errout;
+       }
        paddr = pstr.name;
  
        /* Null-terminate the name */
        paddr[res] = '\0';
  
 -      page_cache_release(cpage);
 +      put_page(cpage);
        set_delayed_call(done, kfree_link, paddr);
        return paddr;
  errout:
        fscrypt_fname_free_buffer(&pstr);
 -      page_cache_release(cpage);
 +      put_page(cpage);
        return ERR_PTR(res);
  }
  
diff --combined fs/f2fs/super.c
index 53b766cdabf2bed903ca3af7bdd67b59664a14b2,c1b1e993adb1487b660c25ebab8f6d7f434d443b..006f87d69921da05e071f41dc023a5d812116779
@@@ -984,9 -984,25 +984,25 @@@ static loff_t max_file_blocks(void
        return result;
  }
  
+ static int __f2fs_commit_super(struct buffer_head *bh,
+                       struct f2fs_super_block *super)
+ {
+       lock_buffer(bh);
+       if (super)
+               memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
+       set_buffer_uptodate(bh);
+       set_buffer_dirty(bh);
+       unlock_buffer(bh);
+       /* it's rare case, we can do fua all the time */
+       return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
+ }
  static inline bool sanity_check_area_boundary(struct super_block *sb,
-                                       struct f2fs_super_block *raw_super)
+                                       struct buffer_head *bh)
  {
+       struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
+                                       (bh->b_data + F2FS_SUPER_OFFSET);
        u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
        u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
        u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
        u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
        u32 segment_count = le32_to_cpu(raw_super->segment_count);
        u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+       u64 main_end_blkaddr = main_blkaddr +
+                               (segment_count_main << log_blocks_per_seg);
+       u64 seg_end_blkaddr = segment0_blkaddr +
+                               (segment_count << log_blocks_per_seg);
  
        if (segment0_blkaddr != cp_blkaddr) {
                f2fs_msg(sb, KERN_INFO,
                return true;
        }
  
-       if (main_blkaddr + (segment_count_main << log_blocks_per_seg) !=
-               segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
+       if (main_end_blkaddr > seg_end_blkaddr) {
                f2fs_msg(sb, KERN_INFO,
-                       "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)",
+                       "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
                        main_blkaddr,
-                       segment0_blkaddr + (segment_count << log_blocks_per_seg),
+                       segment0_blkaddr +
+                               (segment_count << log_blocks_per_seg),
                        segment_count_main << log_blocks_per_seg);
                return true;
+       } else if (main_end_blkaddr < seg_end_blkaddr) {
+               int err = 0;
+               char *res;
+               /* fix in-memory information all the time */
+               raw_super->segment_count = cpu_to_le32((main_end_blkaddr -
+                               segment0_blkaddr) >> log_blocks_per_seg);
+               if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) {
+                       res = "internally";
+               } else {
+                       err = __f2fs_commit_super(bh, NULL);
+                       res = err ? "failed" : "done";
+               }
+               f2fs_msg(sb, KERN_INFO,
+                       "Fix alignment : %s, start(%u) end(%u) block(%u)",
+                       res, main_blkaddr,
+                       segment0_blkaddr +
+                               (segment_count << log_blocks_per_seg),
+                       segment_count_main << log_blocks_per_seg);
+               if (err)
+                       return true;
        }
        return false;
  }
  
  static int sanity_check_raw_super(struct super_block *sb,
-                       struct f2fs_super_block *raw_super)
+                               struct buffer_head *bh)
  {
+       struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
+                                       (bh->b_data + F2FS_SUPER_OFFSET);
        unsigned int blocksize;
  
        if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
        }
  
        /* Currently, support only 4KB page cache size */
 -      if (F2FS_BLKSIZE != PAGE_CACHE_SIZE) {
 +      if (F2FS_BLKSIZE != PAGE_SIZE) {
                f2fs_msg(sb, KERN_INFO,
                        "Invalid page_cache_size (%lu), supports only 4KB\n",
 -                      PAGE_CACHE_SIZE);
 +                      PAGE_SIZE);
                return 1;
        }
  
        }
  
        /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
-       if (sanity_check_area_boundary(sb, raw_super))
+       if (sanity_check_area_boundary(sb, bh))
                return 1;
  
        return 0;
@@@ -1202,7 -1245,7 +1245,7 @@@ static int read_raw_super_block(struct 
  {
        int block;
        struct buffer_head *bh;
-       struct f2fs_super_block *super, *buf;
+       struct f2fs_super_block *super;
        int err = 0;
  
        super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
                        continue;
                }
  
-               buf = (struct f2fs_super_block *)
-                               (bh->b_data + F2FS_SUPER_OFFSET);
                /* sanity checking of raw super */
-               if (sanity_check_raw_super(sb, buf)) {
+               if (sanity_check_raw_super(sb, bh)) {
                        f2fs_msg(sb, KERN_ERR,
                                "Can't find valid F2FS filesystem in %dth superblock",
                                block + 1);
                }
  
                if (!*raw_super) {
-                       memcpy(super, buf, sizeof(*super));
+                       memcpy(super, bh->b_data + F2FS_SUPER_OFFSET,
+                                                       sizeof(*super));
                        *valid_super_block = block;
                        *raw_super = super;
                }
        return err;
  }
  
static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block)
int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
  {
-       struct f2fs_super_block *super = F2FS_RAW_SUPER(sbi);
        struct buffer_head *bh;
        int err;
  
-       bh = sb_getblk(sbi->sb, block);
+       /* write back-up superblock first */
+       bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1);
        if (!bh)
                return -EIO;
-       lock_buffer(bh);
-       memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
-       set_buffer_uptodate(bh);
-       set_buffer_dirty(bh);
-       unlock_buffer(bh);
-       /* it's rare case, we can do fua all the time */
-       err = __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
+       err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
        brelse(bh);
  
-       return err;
- }
- int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
- {
-       int err;
-       /* write back-up superblock first */
-       err = __f2fs_commit_super(sbi, sbi->valid_super_block ? 0 : 1);
        /* if we are in recovery path, skip writing valid superblock */
        if (recover || err)
                return err;
  
        /* write current valid superblock */
-       return __f2fs_commit_super(sbi, sbi->valid_super_block);
+       bh = sb_getblk(sbi->sb, sbi->valid_super_block);
+       if (!bh)
+               return -EIO;
+       err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
+       brelse(bh);
+       return err;
  }
  
  static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
@@@ -1442,7 -1470,7 +1470,7 @@@ try_onemore
        seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
        if (__exist_node_summaries(sbi))
                sbi->kbytes_written =
-                       le64_to_cpu(seg_i->sum_blk->journal.info.kbytes_written);
+                       le64_to_cpu(seg_i->journal->info.kbytes_written);
  
        build_gc_manager(sbi);