From patchwork Mon Jan 26 18:05:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Robinson X-Patchwork-Id: 5711971 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 894EBC058D for ; Mon, 26 Jan 2015 18:33:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 909982013D for ; Mon, 26 Jan 2015 18:33:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8B5162010F for ; Mon, 26 Jan 2015 18:33:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753493AbbAZSd0 (ORCPT ); Mon, 26 Jan 2015 13:33:26 -0500 Received: from shinra.asoshared.com ([65.99.237.192]:30393 "EHLO shinra.asoshared.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752869AbbAZSdZ (ORCPT ); Mon, 26 Jan 2015 13:33:25 -0500 X-Greylist: delayed 1358 seconds by postgrey-1.27 at vger.kernel.org; Mon, 26 Jan 2015 13:33:25 EST DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nerdoftheherd.com; s=default; h=Message-Id:Date:Subject:Cc:To:From; bh=Fg7XvsMseWf7FxpCAnE7siJ6VoTekhWdJBbs9UBlMbI=; b=mEgmH3e2cBt8uPLS2Z7lvTa6pHziUGfxFAaP3bdkknO1x+EC8fBG2HTlHvsIeR6W46bNjiDMmKJ40VG5c+8Vi5t1W9zQNTjPrEwABm42aclh2vqI7BaBW/iOG1wwn5p2OzT/dSeXidwKwTxBX7dU8yF/BAiDy5NY7eInBuaKT6Y=; Received: from mattyribbons.plus.com ([212.159.103.184]:52362 helo=localhost.localdomain) by shinra.asoshared.com with esmtpsa (TLSv1.2:AES128-SHA256:128) (Exim 4.84) (envelope-from ) id 1YFo7Z-0001mH-LZ; Mon, 26 Jan 2015 13:10:45 -0500 From: Matt Robinson To: Chris Mason , Josef Bacik , David Sterba Cc: Mark Fasheh , linux-btrfs@vger.kernel.org, Matt Robinson Subject: [PATCH 1/1] btrfs: Align EOF length to block in extent_same Date: Mon, 26 Jan 2015 18:05:51 +0000 Message-Id: <1422295551-25402-1-git-send-email-git@nerdoftheherd.com> X-Mailer: git-send-email 2.1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - shinra.asoshared.com X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - nerdoftheherd.com X-Get-Message-Sender-Via: shinra.asoshared.com: authenticated_id: matt@nerdoftheherd.com X-Source: X-Source-Args: X-Source-Dir: Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham 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 It is not currently possible to deduplicate the last block of files whose size is not a multiple of the block size, as the btrfs_extent_same ioctl returns -EINVAL if offset + size is greater than the file size or is not aligned to the fs block size. This prevents btrfs from freeing up the last extent in the file, causing gains from deduplication to be smaller than expected. To resolve this, allow unaligned offset + length values to be passed to btrfs_ioctl_file_extent_same if offset + length = file size for both src and dest. This is implemented in the same way as in btrfs_ioctl_clone. Signed-off-by: Matt Robinson --- fs/btrfs/ioctl.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d49fe8a..a407d8a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2871,14 +2871,16 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst, return ret; } -static int extent_same_check_offsets(struct inode *inode, u64 off, u64 len) +static int extent_same_check_offsets(struct inode *inode, u64 off, u64 len, + u64 len_aligned) { u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize; if (off + len > inode->i_size || off + len < off) return -EINVAL; + /* Check that we are block aligned - btrfs_clone() requires this */ - if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs)) + if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len_aligned, bs)) return -EINVAL; return 0; @@ -2888,6 +2890,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len, struct inode *dst, u64 dst_loff) { int ret; + u64 len_aligned = len; + u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; /* * btrfs_clone() can't handle extents in the same file @@ -2899,11 +2903,15 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len, btrfs_double_lock(src, loff, dst, dst_loff, len); - ret = extent_same_check_offsets(src, loff, len); + /* if we extend to both eofs, continue to block boundaries */ + if (loff + len == src->i_size && dst_loff + len == dst->i_size) + len_aligned = ALIGN(src->i_size, bs) - loff; + + ret = extent_same_check_offsets(src, loff, len, len_aligned); if (ret) goto out_unlock; - ret = extent_same_check_offsets(dst, dst_loff, len); + ret = extent_same_check_offsets(dst, dst_loff, len, len_aligned); if (ret) goto out_unlock; @@ -2916,7 +2924,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 len, ret = btrfs_cmp_data(src, loff, dst, dst_loff, len); if (ret == 0) - ret = btrfs_clone(src, dst, loff, len, len, dst_loff); + ret = btrfs_clone(src, dst, loff, len, len_aligned, dst_loff); out_unlock: btrfs_double_unlock(src, loff, dst, dst_loff, len); @@ -3162,8 +3170,7 @@ static void clone_update_extent_map(struct inode *inode, * @inode: Inode to clone to * @off: Offset within source to start clone from * @olen: Original length, passed by user, of range to clone - * @olen_aligned: Block-aligned value of olen, extent_same uses - * identical values here + * @olen_aligned: Block-aligned value of olen * @destoff: Offset within @inode to start clone */ static int btrfs_clone(struct inode *src, struct inode *inode,