From patchwork Tue Feb 4 17:37:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 3578301 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 99B299F2F5 for ; Tue, 4 Feb 2014 17:38:08 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9156520166 for ; Tue, 4 Feb 2014 17:38:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5BA832016C for ; Tue, 4 Feb 2014 17:38:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754748AbaBDRh7 (ORCPT ); Tue, 4 Feb 2014 12:37:59 -0500 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:19027 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751958AbaBDRhz (ORCPT ); Tue, 4 Feb 2014 12:37:55 -0500 Received: from pps.filterd (m0044010 [127.0.0.1]) by mx0a-00082601.pphosted.com (8.14.5/8.14.5) with SMTP id s14HOdW8023300 for ; Tue, 4 Feb 2014 09:37:55 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=fb.com; h=from : to : subject : date : message-id : mime-version : content-type; s=facebook; bh=8lOoNDOGE3atob2KhyDAgyrLV84ocd4zY15EFrJbCZw=; b=KVnh10EamneRrGmZ9wOlQiX2DOFNRkMlu62i3wgSxfmS2Bh7czqbdCJqc1xiDXCpODR/ VPqSQlmiLZ/qeYc32GhdU0lLtrSxoP3B8WuP5WiW4m9UiBBxyEJVGRdD/ZLUzToSk3yp aWFTvOrie9RYGuJZJb/TKX60HUr/64j9rLU= Received: from mail.thefacebook.com (mailwest.thefacebook.com [173.252.71.148]) by mx0a-00082601.pphosted.com with ESMTP id 1hu04ds02q-1 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=OK) for ; Tue, 04 Feb 2014 09:37:54 -0800 Received: from localhost (192.168.57.29) by mail.thefacebook.com (192.168.16.12) with Microsoft SMTP Server (TLS) id 14.3.174.1; Tue, 4 Feb 2014 09:37:53 -0800 From: Josef Bacik To: Subject: [PATCH] Btrfs: introduce commit_root_sem to protect commit roots Date: Tue, 4 Feb 2014 12:37:51 -0500 Message-ID: <1391535471-12289-1-git-send-email-jbacik@fb.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [192.168.57.29] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:5.11.87, 1.0.14, 0.0.0000 definitions=2014-02-04_05:2014-02-04, 2014-02-04, 1970-01-01 signatures=0 X-Proofpoint-Spam-Details: rule=fb_default_notspam policy=fb_default score=0 kscore.is_bulkscore=5.71736372884102e-06 kscore.compositescore=0 circleOfTrustscore=502.112 compositescore=0.999776574422466 urlsuspect_oldscore=0.999776574422466 suspectscore=1 recipient_domain_to_sender_totalscore=0 phishscore=0 bulkscore=0 kscore.is_spamscore=0 recipient_to_sender_totalscore=0 recipient_domain_to_sender_domain_totalscore=62764 rbsscore=0.999776574422466 spamscore=0 recipient_to_sender_domain_totalscore=0 urlsuspectscore=0.9 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=7.0.1-1305240000 definitions=main-1402040084 X-FB-Internal: deliver Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,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 Btrfs send uses the commit roots to avoid locking and such when sending snapshots. The problem with this it doesn't lock anything to make sure the commit roots don't get swapped out from underneath it. This can cause issues if you are trying to send a snapshot and then snapshot that snapshot which will cause us to cow the root and screw everything up. So add commit_root_sem and hold it when we're swapping everything out during the commit. This will make sure we don't have to hold a transaction open while doing a send and we can still use our commit roots. This fixes Wang's reproducer that he turned into an xfstest. Thanks, Reported-by: Wang Shilong Signed-off-by: Josef Bacik --- fs/btrfs/backref.c | 14 ++++++++++---- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 1 + fs/btrfs/send.c | 8 ++++++-- fs/btrfs/transaction.c | 5 +++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index aded3ef..e70f181 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1588,18 +1588,24 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, struct btrfs_key found_key; int search_commit_root = path->search_commit_root; + if (search_commit_root) + down_read(&fs_info->commit_root_sem); ret = extent_from_logical(fs_info, logical, path, &found_key, &flags); btrfs_release_path(path); if (ret < 0) - return ret; - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) - return -EINVAL; + goto out; + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + ret = -EINVAL; + goto out; + } extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(fs_info, found_key.objectid, extent_item_pos, search_commit_root, iterate, ctx); - +out: + if (search_commit_root) + up_read(&fs_info->commit_root_sem); return ret; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 84d4c05..5d927e6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1440,7 +1440,7 @@ struct btrfs_fs_info { struct mutex ordered_extent_flush_mutex; struct rw_semaphore extent_commit_sem; - + struct rw_semaphore commit_root_sem; struct rw_semaphore cleanup_work_sem; struct rw_semaphore subvol_sem; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7619147..ceb2c2d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2279,6 +2279,7 @@ int open_ctree(struct super_block *sb, mutex_init(&fs_info->volume_mutex); init_rwsem(&fs_info->extent_commit_sem); init_rwsem(&fs_info->cleanup_work_sem); + init_rwsem(&fs_info->commit_root_sem); init_rwsem(&fs_info->subvol_sem); sema_init(&fs_info->uuid_tree_rescan_sem, 1); fs_info->dev_replace.lock_owner = 0; diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 04c07ed..1995e6b 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1249,13 +1249,17 @@ static int find_extent_clone(struct send_ctx *sctx, } logical = disk_byte + btrfs_file_extent_offset(eb, fi); + down_read(&sctx->send_root->fs_info->commit_root_sem); ret = extent_from_logical(sctx->send_root->fs_info, disk_byte, tmp_path, &found_key, &flags); btrfs_release_path(tmp_path); - if (ret < 0) + if (ret < 0) { + up_read(&sctx->send_root->fs_info->commit_root_sem); goto out; + } if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + up_read(&sctx->send_root->fs_info->commit_root_sem); ret = -EIO; goto out; } @@ -1297,7 +1301,7 @@ static int find_extent_clone(struct send_ctx *sctx, ret = iterate_extent_inodes(sctx->send_root->fs_info, found_key.objectid, extent_item_pos, 1, __iterate_backrefs, backref_ctx); - + up_read(&sctx->send_root->fs_info->commit_root_sem); if (ret < 0) goto out; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 34cd831..d888f26 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1819,8 +1819,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, */ mutex_lock(&root->fs_info->tree_log_mutex); + down_write(&root->fs_info->commit_root_sem); ret = commit_fs_roots(trans, root); if (ret) { + up_write(&root->fs_info->commit_root_sem); mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); goto cleanup_transaction; @@ -1842,6 +1844,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ret = commit_cowonly_roots(trans, root); if (ret) { + up_write(&root->fs_info->commit_root_sem); mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); goto cleanup_transaction; @@ -1853,6 +1856,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, */ if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { ret = cur_trans->aborted; + up_write(&root->fs_info->commit_root_sem); mutex_unlock(&root->fs_info->tree_log_mutex); mutex_unlock(&root->fs_info->reloc_mutex); goto cleanup_transaction; @@ -1870,6 +1874,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, root->fs_info->chunk_root->node); switch_commit_root(root->fs_info->chunk_root); + up_write(&root->fs_info->commit_root_sem); assert_qgroups_uptodate(trans); update_super_roots(root);