From patchwork Sat Jan 9 08:50:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fan Li X-Patchwork-Id: 7991971 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D1F5B9F3F6 for ; Sat, 9 Jan 2016 08:51:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C4D882024C for ; Sat, 9 Jan 2016 08:51:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1A30B20211 for ; Sat, 9 Jan 2016 08:51:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752164AbcAIIvJ (ORCPT ); Sat, 9 Jan 2016 03:51:09 -0500 Received: from mailout1.samsung.com ([203.254.224.24]:47477 "EHLO mailout1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751956AbcAIIvI (ORCPT ); Sat, 9 Jan 2016 03:51:08 -0500 Received: from epcpsbgm2new.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O0O02L7XGL29I50@mailout1.samsung.com> for linux-fsdevel@vger.kernel.org; Sat, 09 Jan 2016 17:51:05 +0900 (KST) X-AuditID: cbfee61b-f793c6d00000236c-3c-5690c9f99aad Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2new.samsung.com (EPCPMTA) with SMTP id 8D.C1.09068.9F9C0965; Sat, 9 Jan 2016 17:51:05 +0900 (KST) Received: from lifan ([109.123.105.144]) by mmp2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O0O00EIVGKAMA20@mmp2.samsung.com> for linux-fsdevel@vger.kernel.org; Sat, 09 Jan 2016 17:51:05 +0900 (KST) From: Fan Li To: linux-fsdevel@vger.kernel.org Subject: [PATCH] fs: fix bugs for __generic_block_fiemap() Date: Sat, 09 Jan 2016 16:50:34 +0800 Message-id: <001401d14aba$dfe6c370$9fb44a50$@samsung.com> MIME-version: 1.0 Content-type: text/plain; charset=us-ascii Content-transfer-encoding: 7bit X-Mailer: Microsoft Outlook 14.0 Thread-index: AdFKuoXTT1MyTc57SHm2ova/u2Ht0g== Content-language: en-us X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrNLMWRmVeSWpSXmKPExsVy+t9jQd2fJyeEGUztF7TYs/ckiwOjx+dN cgGMUVw2Kak5mWWpRfp2CVwZs9oOMBZs1a2YtWYCUwPjRMUuRg4OCQETiWXX+LoYOYFMMYkL 99azdTFycQgJzGKUuN31lwnC6WGS2H/mDhtIFZuAusSWmd1MIM0iAooSl987gYSFBawkPu04 yQRiswioSvxaPxesnFfAUuLnpZvsELagxI/J91hAbGYBLYn1O48zQdjyEpvXvGWGOEJBYsfZ 14wgtoiAnsTZKzfZIGrEJSY9eMg+gZF/FpJRs5CMmoVk1CwkLQsYWVYxSqQWJBcUJ6XnGuWl lusVJ+YWl+al6yXn525iBAfhM+kdjId3uR9iFOBgVOLhnSAwIUyINbGsuDL3EKMEB7OSCO/6 ZKAQb0piZVVqUX58UWlOavEhRmkOFiVx3n2XIsOEBNITS1KzU1MLUotgskwcnFINjDLPd87d 9vda+Ou32uFz2/4UdUYUsHa5+M3a+Ggux+cbQVv3agptzl+fPu9Exfo6hbUyT/ce2PMzfH60 myRLyfoLap3qj5c9zfu5O1nA98WJewH36mclN7PE/GV65HzuebTfP9t/rnEKTLXCU7O/X1DK slY5ody740PMsQPMX46uUd7q7n3JXFKJpTgj0VCLuag4EQBk+mHePgIAAA== Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Fix 3 bugs: 1. If there are more than two blocks of holes after the last extent of file, it would fail to add FIEMAP_EXTENT_LAST to the last extent. 2. len hasn't been updated correctly, if len > isize and start > 0. 3. If len is less than one block, it will be extended to one block. If start + len exceeds the boundary of the original block because of the extension, one extra block will be returned. And simplify the codes of __generic_block_fiemap() as well. Signed-off-by: Fan Li --- fs/ioctl.c | 116 +++++++++++++++--------------------------------------------- 1 file changed, 29 insertions(+), 87 deletions(-) diff --git a/fs/ioctl.c b/fs/ioctl.c index 41c352e..8e2b426 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -256,7 +256,6 @@ int __generic_block_fiemap(struct inode *inode, loff_t isize = i_size_read(inode); u64 logical = 0, phys = 0, size = 0; u32 flags = FIEMAP_EXTENT_MERGED; - bool past_eof = false, whole_file = false; int ret = 0; ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); @@ -268,28 +267,27 @@ int __generic_block_fiemap(struct inode *inode, * since we expect isize to not change at all through the duration of * this call. */ - if (len >= isize) { - whole_file = true; - len = isize; - } + if (start >= isize) + return 0; - /* - * Some filesystems can't deal with being asked to map less than - * blocksize, so make sure our len is at least block length. - */ - if (logical_to_blk(inode, len) == 0) - len = blk_to_logical(inode, 1); + if (start + len > isize) + len = isize - start; start_blk = logical_to_blk(inode, start); last_blk = logical_to_blk(inode, start + len - 1); do { + memset(&map_bh, 0, sizeof(struct buffer_head)); /* - * we set b_size to the total size we want so it will map as - * many contiguous blocks as possible at once + * Some filesystems would round down b_size to align + * with block size, if len isn't aligned already, the last + * block may not be returned. Let's round it up first. */ - memset(&map_bh, 0, sizeof(struct buffer_head)); - map_bh.b_size = len; + if (last_blk > start_blk) + map_bh.b_size = blk_to_logical(inode, + last_blk - start_blk + 1); + else + map_bh.b_size = blk_to_logical(inode, 1); ret = get_block(inode, start_blk, &map_bh, 0); if (ret) @@ -299,91 +297,35 @@ int __generic_block_fiemap(struct inode *inode, if (!buffer_mapped(&map_bh)) { start_blk++; - /* - * We want to handle the case where there is an - * allocated block at the front of the file, and then - * nothing but holes up to the end of the file properly, - * to make sure that extent at the front gets properly - * marked with FIEMAP_EXTENT_LAST - */ - if (!past_eof && - blk_to_logical(inode, start_blk) >= isize) - past_eof = 1; - + /* Skip holes unless it indicates the EOF */ + if (blk_to_logical(inode, start_blk) < isize) + goto next; /* * First hole after going past the EOF, this is our * last extent */ - if (past_eof && size) { - flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - } else if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - size = 0; - } - - /* if we have holes up to/past EOF then we're done */ - if (start_blk > last_blk || past_eof || ret) - break; - } else { - /* - * We have gone over the length of what we wanted to - * map, and it wasn't the entire file, so add the extent - * we got last time and exit. - * - * This is for the case where say we want to map all the - * way up to the second to the last block in a file, but - * the last block is a hole, making the second to last - * block FIEMAP_EXTENT_LAST. In this case we want to - * see if there is a hole after the second to last block - * so we can mark it properly. If we found data after - * we exceeded the length we were requesting, then we - * are good to go, just add the extent to the fieinfo - * and break - */ - if (start_blk > last_blk && !whole_file) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - break; - } + flags |= FIEMAP_EXTENT_LAST; + } - /* - * if size != 0 then we know we already have an extent - * to add, so add it. - */ - if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - if (ret) - break; - } + if (size) + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); - logical = blk_to_logical(inode, start_blk); - phys = blk_to_logical(inode, map_bh.b_blocknr); - size = map_bh.b_size; - flags = FIEMAP_EXTENT_MERGED; + if (start_blk > last_blk || ret) + break; - start_blk += logical_to_blk(inode, size); + logical = blk_to_logical(inode, start_blk); + phys = blk_to_logical(inode, map_bh.b_blocknr); + size = map_bh.b_size; + flags = FIEMAP_EXTENT_MERGED; - /* - * If we are past the EOF, then we need to make sure as - * soon as we find a hole that the last extent we found - * is marked with FIEMAP_EXTENT_LAST - */ - if (!past_eof && logical + size >= isize) - past_eof = true; - } + start_blk += logical_to_blk(inode, size); +next: cond_resched(); if (fatal_signal_pending(current)) { ret = -EINTR; break; } - } while (1); /* If ret is 1 then we just hit the end of the extent array */