From patchwork Fri Sep 27 10:23:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolay Borisov X-Patchwork-Id: 11164275 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 30115112B for ; Fri, 27 Sep 2019 10:23:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 17EEA207E0 for ; Fri, 27 Sep 2019 10:23:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727243AbfI0KXY (ORCPT ); Fri, 27 Sep 2019 06:23:24 -0400 Received: from mx2.suse.de ([195.135.220.15]:33030 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726080AbfI0KXY (ORCPT ); Fri, 27 Sep 2019 06:23:24 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 7E8FBAFFE; Fri, 27 Sep 2019 10:23:22 +0000 (UTC) From: Nikolay Borisov To: linux-btrfs@vger.kernel.org Cc: Nikolay Borisov Subject: [PATCH v2 1/3] btrfs: Speed up btrfs_file_llseek Date: Fri, 27 Sep 2019 13:23:16 +0300 Message-Id: <20190927102318.12830-2-nborisov@suse.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190927102318.12830-1-nborisov@suse.com> References: <20190927102318.12830-1-nborisov@suse.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Modifying the file position is done on a per-file basis. This renders holding the inode lock for writing useless and makes the performance of concurrent llseek's abysmal. Fix this by holding the inode for read. This provides protection against concurrent truncates and find_desired_extent already includes proper extent locking for the range which ensures proper locking against concurrent writes. SEEK_CUR and SEEK_END can be done lockessly. The former is synchronized by file::f_lock spinlock. SEEK_END is not synchronized but atomic, but that's OK since there is not guarantee that SEEK_END will always be at the end of the file in the face of tail modifications. This change brings ~82% performance improvement when doing a lot of parallel fseeks. The workload essentially does: for (d=0; d --- fs/btrfs/file.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 12688ae6e6f2..000b7bd89bf0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3347,13 +3347,14 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct extent_map *em = NULL; struct extent_state *cached_state = NULL; + loff_t i_size = inode->i_size; u64 lockstart; u64 lockend; u64 start; u64 len; int ret = 0; - if (inode->i_size == 0) + if (i_size == 0 || *offset >= i_size) return -ENXIO; /* @@ -3363,8 +3364,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) start = max_t(loff_t, 0, *offset); lockstart = round_down(start, fs_info->sectorsize); - lockend = round_up(i_size_read(inode), - fs_info->sectorsize); + lockend = round_up(i_size, fs_info->sectorsize); if (lockend <= lockstart) lockend = lockstart + fs_info->sectorsize; lockend--; @@ -3373,7 +3373,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, &cached_state); - while (start < inode->i_size) { + while (start < i_size) { em = btrfs_get_extent_fiemap(BTRFS_I(inode), start, len); if (IS_ERR(em)) { ret = PTR_ERR(em); @@ -3397,10 +3397,10 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) } free_extent_map(em); if (!ret) { - if (whence == SEEK_DATA && start >= inode->i_size) + if (whence == SEEK_DATA && start >= i_size) ret = -ENXIO; else - *offset = min_t(loff_t, start, inode->i_size); + *offset = min_t(loff_t, start, i_size); } unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, &cached_state); @@ -3412,7 +3412,6 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) struct inode *inode = file->f_mapping->host; int ret; - inode_lock(inode); switch (whence) { case SEEK_END: case SEEK_CUR: @@ -3420,21 +3419,16 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) goto out; case SEEK_DATA: case SEEK_HOLE: - if (offset >= i_size_read(inode)) { - inode_unlock(inode); - return -ENXIO; - } - + inode_lock_shared(inode); ret = find_desired_extent(inode, &offset, whence); - if (ret) { - inode_unlock(inode); + inode_unlock_shared(inode); + + if (ret) return ret; - } } offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); out: - inode_unlock(inode); return offset; } From patchwork Fri Sep 27 10:23:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolay Borisov X-Patchwork-Id: 11164277 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D3D0876 for ; Fri, 27 Sep 2019 10:23:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BBF32217D7 for ; Fri, 27 Sep 2019 10:23:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727235AbfI0KXY (ORCPT ); Fri, 27 Sep 2019 06:23:24 -0400 Received: from mx2.suse.de ([195.135.220.15]:33042 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727213AbfI0KXX (ORCPT ); Fri, 27 Sep 2019 06:23:23 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id E3CFAB0B7; Fri, 27 Sep 2019 10:23:22 +0000 (UTC) From: Nikolay Borisov To: linux-btrfs@vger.kernel.org Cc: Nikolay Borisov Subject: [PATCH v2 2/3] btrfs: Simplify btrfs_file_llseek Date: Fri, 27 Sep 2019 13:23:17 +0300 Message-Id: <20190927102318.12830-3-nborisov@suse.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190927102318.12830-1-nborisov@suse.com> References: <20190927102318.12830-1-nborisov@suse.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Handle SEEK_END/SEEK_CUR in a single 'default' case by directly returning from generic_file_llseek. This makes the 'out' label redundant. Finally return directly the vale from vfs_setpos. No semantic changes. Signed-off-by: Nikolay Borisov Reviewed-by: Johannes Thumshirn --- fs/btrfs/file.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 000b7bd89bf0..cda1882f5cb5 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3413,10 +3413,8 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) int ret; switch (whence) { - case SEEK_END: - case SEEK_CUR: - offset = generic_file_llseek(file, offset, whence); - goto out; + default: + return generic_file_llseek(file, offset, whence); case SEEK_DATA: case SEEK_HOLE: inode_lock_shared(inode); @@ -3427,9 +3425,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) return ret; } - offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); -out: - return offset; + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); } static int btrfs_file_open(struct inode *inode, struct file *filp) From patchwork Fri Sep 27 10:23:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolay Borisov X-Patchwork-Id: 11164279 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D1181112B for ; Fri, 27 Sep 2019 10:23:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BA14F217D9 for ; Fri, 27 Sep 2019 10:23:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727247AbfI0KXZ (ORCPT ); Fri, 27 Sep 2019 06:23:25 -0400 Received: from mx2.suse.de ([195.135.220.15]:33056 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726033AbfI0KXZ (ORCPT ); Fri, 27 Sep 2019 06:23:25 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 4FDB6B052; Fri, 27 Sep 2019 10:23:23 +0000 (UTC) From: Nikolay Borisov To: linux-btrfs@vger.kernel.org Cc: Nikolay Borisov Subject: [PATCH v2 3/3] btrfs: Return offset from find_desired_extent Date: Fri, 27 Sep 2019 13:23:18 +0300 Message-Id: <20190927102318.12830-4-nborisov@suse.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190927102318.12830-1-nborisov@suse.com> References: <20190927102318.12830-1-nborisov@suse.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Instead of using an input pointer parameter as the return value and have an int as the return type of find_desired_extent, rework the function to directly return the found offset. Doing that the 'ret' variable in btrfs_llseek_file can be removed. Additional (subjective) benefit is that btrfs' llseek function now resemebles those of the other major filesystems. Signed-off-by: Nikolay Borisov Reviewed-by: Johannes Thumshirn --- fs/btrfs/file.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index cda1882f5cb5..cb6f7ac8cd15 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3342,7 +3342,8 @@ static long btrfs_fallocate(struct file *file, int mode, return ret; } -static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) +static loff_t find_desired_extent(struct inode *inode, loff_t offset, + int whence) { struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct extent_map *em = NULL; @@ -3354,14 +3355,14 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) u64 len; int ret = 0; - if (i_size == 0 || *offset >= i_size) + if (i_size == 0 || offset >= i_size) return -ENXIO; /* - * *offset can be negative, in this case we start finding DATA/HOLE from + * offset can be negative, in this case we start finding DATA/HOLE from * the very start of the file. */ - start = max_t(loff_t, 0, *offset); + start = max_t(loff_t, 0, offset); lockstart = round_down(start, fs_info->sectorsize); lockend = round_up(i_size, fs_info->sectorsize); @@ -3396,21 +3397,23 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) cond_resched(); } free_extent_map(em); - if (!ret) { + unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, + &cached_state); + if (ret) { + offset = ret; + } else { if (whence == SEEK_DATA && start >= i_size) - ret = -ENXIO; + offset = -ENXIO; else - *offset = min_t(loff_t, start, i_size); + offset = min_t(loff_t, start, i_size); } - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state); - return ret; + + return offset; } static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) { struct inode *inode = file->f_mapping->host; - int ret; switch (whence) { default: @@ -3418,13 +3421,14 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) case SEEK_DATA: case SEEK_HOLE: inode_lock_shared(inode); - ret = find_desired_extent(inode, &offset, whence); + offset = find_desired_extent(inode, offset, whence); inode_unlock_shared(inode); - - if (ret) - return ret; + break; } + if (offset < 0) + return offset; + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); }