From patchwork Fri Oct 5 00:46:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 10627233 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DC19C15A6 for ; Fri, 5 Oct 2018 00:46:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C9B6528F4F for ; Fri, 5 Oct 2018 00:46:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BD1E128F83; Fri, 5 Oct 2018 00:46:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from userp2120.oracle.com (userp2120.oracle.com [156.151.31.85]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4CEAB28F4F for ; Fri, 5 Oct 2018 00:46:28 +0000 (UTC) Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w950j5hs000998; Fri, 5 Oct 2018 00:46:13 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : date : message-id : in-reply-to : references : mime-version : cc : subject : list-id : list-unsubscribe : list-archive : list-post : list-help : list-subscribe : content-type : content-transfer-encoding : sender; s=corp-2018-07-02; bh=O53SDKr0MuQR8hy7ItDJN1GwfEYcFYlt31arNGVo90M=; b=QkAOPi6oGbAAxwtaIyfjALLtOUDRVMu3hfg13H2262LllBxDH0BjdwHBYNmDA9qWBV0W W25iy+QKE1/fZ2DEyBfXAHEPYGXA+2KUHUe9vWzVtJChIfM9qS50T5+Dxdha1E5fGdKN BTD5oows5nA3F0WMrfhgJd3A08qmo1YLrbETtlGwx9KUtLMgpT81NCuAtUj+gNBSDukM VBx+htFGBvqiwqduG1EokRmjRUIcj450PMl0f8Oqi3zc3HO4j2iGjoBhVx+OrYxkUXRK DcMFt4j9FQB2UvvadASfiQHiWT8Narrob7cwzZ18Xigec5rTMZ+hcB8wra4ivE8+EVAp 3Q== Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by userp2120.oracle.com with ESMTP id 2mt21rfk21-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 05 Oct 2018 00:46:13 +0000 Received: from oss.oracle.com (oss-old-reserved.oracle.com [137.254.22.2]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w950kCuQ023118 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 5 Oct 2018 00:46:13 GMT Received: from localhost ([127.0.0.1] helo=lb-oss.oracle.com) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1g8EFw-0004wD-JC; Thu, 04 Oct 2018 17:46:12 -0700 Received: from aserv0022.oracle.com ([141.146.126.234]) by oss.oracle.com with esmtp (Exim 4.63) (envelope-from ) id 1g8EFt-0004w0-B6 for ocfs2-devel@oss.oracle.com; Thu, 04 Oct 2018 17:46:09 -0700 Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w950k9di007744 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 5 Oct 2018 00:46:09 GMT Received: from abhmp0020.oracle.com (abhmp0020.oracle.com [141.146.116.26]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id w950k9Va014954; Fri, 5 Oct 2018 00:46:09 GMT Received: from localhost (/10.159.229.198) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 05 Oct 2018 00:46:08 +0000 From: "Darrick J. Wong" To: david@fromorbit.com, darrick.wong@oracle.com Date: Thu, 04 Oct 2018 17:46:01 -0700 Message-ID: <153870036143.29072.11970142092673351715.stgit@magnolia> In-Reply-To: <153870027422.29072.7433543674436957232.stgit@magnolia> References: <153870027422.29072.7433543674436957232.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Cc: linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, ocfs2-devel@oss.oracle.com, linux-btrfs@vger.kernel.org, sandeen@redhat.com Subject: [Ocfs2-devel] [PATCH 12/15] vfs: implement opportunistic short dedupe X-BeenThere: ocfs2-devel@oss.oracle.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ocfs2-devel-bounces@oss.oracle.com Errors-To: ocfs2-devel-bounces@oss.oracle.com X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=9036 signatures=668706 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1807170000 definitions=main-1810050006 X-Virus-Scanned: ClamAV using ClamSMTP From: Darrick J. Wong For a given dedupe request, the bytes_deduped field in the control structure tells userspace if we managed to deduplicate some, but not all of, the requested regions starting from the file offsets supplied. However, due to sloppy coding, the current dedupe code returns FILE_DEDUPE_RANGE_DIFFERS if any part of the range is different. Fix this so that we can actually support partial request completion. Signed-off-by: Darrick J. Wong --- fs/read_write.c | 44 +++++++++++++++++++++++++++++++++++--------- include/linux/fs.h | 2 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index 292d68c2f47c..9be9f261edd2 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1781,13 +1781,11 @@ int vfs_clone_file_prep(struct file *file_in, loff_t pos_in, * Check that the extents are the same. */ if (is_dedupe) { - bool is_same = false; - ret = vfs_dedupe_file_range_compare(inode_in, pos_in, - inode_out, pos_out, *len, &is_same); + inode_out, pos_out, len); if (ret) return ret; - if (!is_same) + if (*len == 0) return -EBADE; } @@ -1872,13 +1870,30 @@ static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset) return page; } +static unsigned int vfs_dedupe_memcmp(const char *s1, const char *s2, + unsigned int cmp_len) +{ + const char *orig_s1 = s1; + const char *e1 = s1 + cmp_len; + const char *e2 = s2 + cmp_len; + + while (s1 < e1 && s2 < e2) { + if (*s1 != *s2) + break; + s1++; + s2++; + } + + return s1 - orig_s1; +} + /* * Compare extents of two files to see if they are the same. * Caller must have locked both inodes to prevent write races. */ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, struct inode *dest, loff_t destoff, - loff_t len, bool *is_same) + loff_t *req_len) { loff_t src_poff; loff_t dest_poff; @@ -1886,8 +1901,11 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, void *dest_addr; struct page *src_page; struct page *dest_page; - loff_t cmp_len; + loff_t len = *req_len; + loff_t same_len = 0; bool same; + unsigned int cmp_len; + unsigned int cmp_same; int error; error = -EINVAL; @@ -1897,7 +1915,7 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, dest_poff = destoff & (PAGE_SIZE - 1); cmp_len = min(PAGE_SIZE - src_poff, PAGE_SIZE - dest_poff); - cmp_len = min(cmp_len, len); + cmp_len = min_t(loff_t, cmp_len, len); if (cmp_len <= 0) goto out_error; @@ -1919,7 +1937,10 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, flush_dcache_page(src_page); flush_dcache_page(dest_page); - if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len)) + cmp_same = vfs_dedupe_memcmp(src_addr + src_poff, + dest_addr + dest_poff, cmp_len); + same_len += cmp_same; + if (cmp_same != cmp_len) same = false; kunmap_atomic(dest_addr); @@ -1937,7 +1958,12 @@ int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, len -= cmp_len; } - *is_same = same; + /* + * If less than the whole range matched, we have to back down to the + * nearest block boundary. + */ + if (*req_len != same_len) + *req_len = ALIGN_DOWN(same_len, dest->i_sb->s_blocksize); return 0; out_error: diff --git a/include/linux/fs.h b/include/linux/fs.h index eb35363478e5..490128b84d10 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1840,7 +1840,7 @@ extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, u64 len); extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff, struct inode *dest, loff_t destoff, - loff_t len, bool *is_same); + loff_t *len); extern int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same); extern s64 vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,