Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp10786921imu; Thu, 6 Dec 2018 06:49:27 -0800 (PST) X-Google-Smtp-Source: AFSGD/WvefnsI0y/L1fIPJrdjZOiu7zcxRsKRKvKfvZdI+4P1v6t5mHsV+8YyWmuYMX68a5COk+q X-Received: by 2002:a17:902:380c:: with SMTP id l12mr27775330plc.326.1544107767769; Thu, 06 Dec 2018 06:49:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544107767; cv=none; d=google.com; s=arc-20160816; b=ZCr+Xmj/b0wMcCb5BmIkmftfexiC7Bttq2uNj61qPfsldGT3+IRb+hxIRDJ3571NaS AfgpuPiXqq4yz2Pt/DubmxfRdWK9XZaXz1UFCdsqdyXtEsEkadNaexodhji9AvWX8YE7 ZL4f0e+aeNFYy338HY7fr+vO7l885J6aEOnvNzICUAqkCDjRe4SBSh4nTzqwkgxDC0TD pVzs2wh00wBiYZZSE7LMYJpjt4x9uLW/TlT1buwu91ppsVUDYbsXDHzFvK2IFU2LE1Ui X7RI2NW805l/yCJG2yfYzcPtEQoXvSxKY7khvd0chDdi4qCXGGnF0wPJ83HyxORvc0Hc G7Dg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=YDrGoweWvyd4djDNN1Ij1pJL2EY/E6DrN+Wi1rC5Gfc=; b=oc5kQHDiRVIpN8v/7vB1AsBva05CkalgpGyzIxadV7SbHebT/FBqX6/oVL5dN0fUZ6 Zeb6/xeqw8WgHD4at2ETn9oScHY35xEAEB7gqgx/+CWxYD3azuZDzpN2+sdnQdat3cSG TRjjODYDmNMuortrjTDbH322jVVhrJntwhLPOIoej+byc4DeJxM8nT2EvMIszY6tS3zZ a0FzQL8v7iceqcTAROyGdZyN1Hne2k6Bge1vNlqkR/0vkayj9rpxSF2M8qC5YOOdkZYf Kd2i/BF2Xk++G4hgzb2iOI8J6IlGoD11ObmmODU/pqLIjd+zcBya/2nbvICtMA98ANWh /fVg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Z8D2B36+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v21si373288plo.417.2018.12.06.06.49.11; Thu, 06 Dec 2018 06:49:27 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Z8D2B36+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731486AbeLFOrn (ORCPT + 99 others); Thu, 6 Dec 2018 09:47:43 -0500 Received: from mail.kernel.org ([198.145.29.99]:52750 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731476AbeLFOrl (ORCPT ); Thu, 6 Dec 2018 09:47:41 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 5B0AC20661; Thu, 6 Dec 2018 14:47:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1544107659; bh=XgwXtl0LqdCGh1fKT4jAoywiy6ItGx59N8Ue09RnVnE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z8D2B36+BoVryUW0hd/BIr0OxAAHcJWCgj3MMSERUDI6+i8T7l1qC/SwJsYa/YJgw vRYOQZOJKN2olnOf3VemxN+FG6cBze9XLnUshH5jQKf5itTSOEsqZgoX6vFIAnLsoG XhMS0EGrzXKEAooT5yqfkmO+2L1JO3snSKCoGAts= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Chao Yu , Jaegeuk Kim , Ben Hutchings Subject: [PATCH 4.9 091/101] f2fs: introduce and spread verify_blkaddr Date: Thu, 6 Dec 2018 15:39:30 +0100 Message-Id: <20181206143018.111333050@linuxfoundation.org> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181206143011.174892052@linuxfoundation.org> References: <20181206143011.174892052@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Chao Yu commit e1da7872f6eda977bd812346bf588c35e4495a1e upstream. This patch introduces verify_blkaddr to check meta/data block address with valid range to detect bug earlier. In addition, once we encounter an invalid blkaddr, notice user to run fsck to fix, and let the kernel panic. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim [bwh: Backported to 4.9: - I skipped an earlier renaming of is_valid_meta_blkaddr() to f2fs_is_valid_meta_blkaddr() - Adjust context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/checkpoint.c | 11 +++++++++-- fs/f2fs/data.c | 6 +++--- fs/f2fs/f2fs.h | 32 +++++++++++++++++++++++++++++--- fs/f2fs/file.c | 9 +++++---- fs/f2fs/inode.c | 7 ++++--- fs/f2fs/node.c | 4 ++-- fs/f2fs/recovery.c | 6 +++--- fs/f2fs/segment.c | 4 ++-- fs/f2fs/segment.h | 8 +++----- 9 files changed, 60 insertions(+), 27 deletions(-) --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -118,7 +118,8 @@ struct page *get_tmp_page(struct f2fs_sb return __get_meta_page(sbi, index, false); } -bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type) +bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type) { switch (type) { case META_NAT: @@ -138,10 +139,16 @@ bool is_valid_meta_blkaddr(struct f2fs_s return false; break; case META_POR: + case DATA_GENERIC: if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || blkaddr < MAIN_BLKADDR(sbi))) return false; break; + case META_GENERIC: + if (unlikely(blkaddr < SEG0_BLKADDR(sbi) || + blkaddr >= MAIN_BLKADDR(sbi))) + return false; + break; default: BUG(); } @@ -173,7 +180,7 @@ int ra_meta_pages(struct f2fs_sb_info *s blk_start_plug(&plug); for (; nrpages-- > 0; blkno++) { - if (!is_valid_meta_blkaddr(sbi, blkno, type)) + if (!f2fs_is_valid_blkaddr(sbi, blkno, type)) goto out; switch (type) { --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -267,7 +267,7 @@ void f2fs_submit_page_mbio(struct f2fs_i io = is_read ? &sbi->read_io : &sbi->write_io[btype]; - if (is_valid_blkaddr(fio->old_blkaddr)) + if (__is_valid_data_blkaddr(fio->old_blkaddr)) verify_block_addr(fio, fio->old_blkaddr); verify_block_addr(fio, fio->new_blkaddr); @@ -723,7 +723,7 @@ next_dnode: next_block: blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); - if (!is_valid_blkaddr(blkaddr)) { + if (!is_valid_data_blkaddr(sbi, blkaddr)) { if (create) { if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; @@ -1217,7 +1217,7 @@ retry_encrypt: * If current allocation needs SSR, * it had better in-place writes for updated data. */ - if (unlikely(is_valid_blkaddr(fio->old_blkaddr) && + if (unlikely(is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) && !is_cold_data(page) && !IS_ATOMIC_WRITTEN_PAGE(page) && need_inplace_update(inode))) { --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -145,7 +145,7 @@ struct cp_control { }; /* - * For CP/NAT/SIT/SSA readahead + * indicate meta/data type */ enum { META_CP, @@ -153,6 +153,8 @@ enum { META_SIT, META_SSA, META_POR, + DATA_GENERIC, + META_GENERIC, }; /* for the list of ino */ @@ -1930,13 +1932,36 @@ static inline void *f2fs_kvzalloc(size_t (pgofs - ADDRS_PER_INODE(inode) + ADDRS_PER_BLOCK) / \ ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(inode)) -static inline bool is_valid_blkaddr(block_t blkaddr) +bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type); +void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...); +static inline void verify_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type) +{ + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) { + f2fs_msg(sbi->sb, KERN_ERR, + "invalid blkaddr: %u, type: %d, run fsck to fix.", + blkaddr, type); + f2fs_bug_on(sbi, 1); + } +} + +static inline bool __is_valid_data_blkaddr(block_t blkaddr) { if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) return false; return true; } +static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr) +{ + if (!__is_valid_data_blkaddr(blkaddr)) + return false; + verify_blkaddr(sbi, blkaddr, DATA_GENERIC); + return true; +} + /* * file.c */ @@ -2122,7 +2147,8 @@ void f2fs_stop_checkpoint(struct f2fs_sb struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t); -bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type); +bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type); int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool); void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t); long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -310,13 +310,13 @@ static pgoff_t __get_first_dirty_index(s return pgofs; } -static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs, - int whence) +static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr, + pgoff_t dirty, pgoff_t pgofs, int whence) { switch (whence) { case SEEK_DATA: if ((blkaddr == NEW_ADDR && dirty == pgofs) || - is_valid_blkaddr(blkaddr)) + is_valid_data_blkaddr(sbi, blkaddr)) return true; break; case SEEK_HOLE: @@ -378,7 +378,8 @@ static loff_t f2fs_seek_block(struct fil block_t blkaddr; blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); - if (__found_offset(blkaddr, dirty, pgofs, whence)) { + if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty, + pgofs, whence)) { f2fs_put_dnode(&dn); goto found; } --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -59,11 +59,12 @@ static void __get_inode_rdev(struct inod } } -static bool __written_first_block(struct f2fs_inode *ri) +static bool __written_first_block(struct f2fs_sb_info *sbi, + struct f2fs_inode *ri) { block_t addr = le32_to_cpu(ri->i_addr[0]); - if (is_valid_blkaddr(addr)) + if (is_valid_data_blkaddr(sbi, addr)) return true; return false; } @@ -159,7 +160,7 @@ static int do_read_inode(struct inode *i /* get rdev by using inline_info */ __get_inode_rdev(inode, ri); - if (__written_first_block(ri)) + if (__written_first_block(sbi, ri)) set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); if (!need_inode_block_update(sbi, inode->i_ino)) --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -304,7 +304,7 @@ static void set_node_addr(struct f2fs_sb new_blkaddr == NULL_ADDR); f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR && new_blkaddr == NEW_ADDR); - f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) && + f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) && new_blkaddr == NEW_ADDR); /* increment version no as node is removed */ @@ -319,7 +319,7 @@ static void set_node_addr(struct f2fs_sb /* change address */ nat_set_blkaddr(e, new_blkaddr); - if (!is_valid_blkaddr(new_blkaddr)) + if (!is_valid_data_blkaddr(sbi, new_blkaddr)) set_nat_flag(e, IS_CHECKPOINTED, false); __set_nat_cache_dirty(nm_i, e); --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -236,7 +236,7 @@ static int find_fsync_dnodes(struct f2fs while (1) { struct fsync_inode_entry *entry; - if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR)) + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) return 0; page = get_tmp_page(sbi, blkaddr); @@ -468,7 +468,7 @@ retry_dn: } /* dest is valid block, try to recover from src to dest */ - if (is_valid_meta_blkaddr(sbi, dest, META_POR)) { + if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) { if (src == NULL_ADDR) { err = reserve_new_block(&dn); @@ -527,7 +527,7 @@ static int recover_data(struct f2fs_sb_i while (1) { struct fsync_inode_entry *entry; - if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR)) + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) break; ra_meta_pages_cond(sbi, blkaddr); --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -944,7 +944,7 @@ bool is_checkpointed_data(struct f2fs_sb struct seg_entry *se; bool is_cp = false; - if (!is_valid_blkaddr(blkaddr)) + if (!is_valid_data_blkaddr(sbi, blkaddr)) return true; mutex_lock(&sit_i->sentry_lock); @@ -1668,7 +1668,7 @@ void f2fs_wait_on_encrypted_page_writeba { struct page *cpage; - if (!is_valid_blkaddr(blkaddr)) + if (!is_valid_data_blkaddr(sbi, blkaddr)) return; cpage = find_lock_page(META_MAPPING(sbi), blkaddr); --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -81,7 +81,7 @@ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1)) #define GET_SEGNO(sbi, blk_addr) \ - ((!is_valid_blkaddr(blk_addr)) ? \ + ((!is_valid_data_blkaddr(sbi, blk_addr)) ? \ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ GET_SEGNO_FROM_SEG0(sbi, blk_addr))) #define GET_SECNO(sbi, segno) \ @@ -603,11 +603,9 @@ static inline void verify_block_addr(str if (PAGE_TYPE_OF_BIO(fio->type) == META && (!is_read_io(fio->op) || fio->is_meta)) - BUG_ON(blk_addr < SEG0_BLKADDR(sbi) || - blk_addr >= MAIN_BLKADDR(sbi)); + verify_blkaddr(sbi, blk_addr, META_GENERIC); else - BUG_ON(blk_addr < MAIN_BLKADDR(sbi) || - blk_addr >= MAX_BLKADDR(sbi)); + verify_blkaddr(sbi, blk_addr, DATA_GENERIC); } /*