Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp3345090ybi; Fri, 19 Jul 2019 01:42:50 -0700 (PDT) X-Google-Smtp-Source: APXvYqwXLr+049dbRx2zg205su0EqU56vG0QNXMVSlhhusiLFzrxfynHVafJt2v8nx5onSWU48kW X-Received: by 2002:a17:902:b582:: with SMTP id a2mr56432230pls.128.1563525769890; Fri, 19 Jul 2019 01:42:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1563525769; cv=none; d=google.com; s=arc-20160816; b=uaYI/sfZL1ve1rwWH/hKLCQICnmtTPs2DddMl+rliGlcte9PY7rR77UScVNisoLz4M mXLpH3lFd3buCNN8snKsBAJTd4kcYcNcO4Opb1j7eA76fS2C/f2UckiVOfGJvTa6OKau W0OW8RGC1JWXM7kBsmeMC94OI6cv6XI5o6jnZatL7tKaDgtuwl9VtKnKu8h13Dm4q2cB W7/YPtwSoVxjM9zEJIm4kNGprDOhERSYGtiyuLRwz5AxKynlcpp0YlZaqhvGJzVGkCle AwUcG9J9TZXT9pgijuKI2UcNYyv+jtZBUE6Lld8g074jSVExVRE1oNvugHljGkxnnEKh c3PQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=BLmdEkJk0olhN6GOLnuO3WYkHUkJUyMhowsr9IlrwSg=; b=VZBZWPeZwtsyjtlM3m+8c8AZf07GgTl9jRhWsJ70ThBGe9SJJ/QdEavA/vrC4uewxa /In5afthQA2J/B3Xs2PDCTsuuX5Ox2fs49cLR9lYNEzVcZ+hRiWqz6MsZYV5RXlCkVDG vqh+3Au/W3XrjJXr/mtUUQjGQqQlc4Wa1ep1FjGuqcfY1rNacCVxw0E1vHFAVK6yzcYN 3Sh5rVL04G/FzCUPntpfzxiXrjbEY6xB8Th+hQ4Z6hCqocDhSwJuJCJ1+y1FKrme7fnY LdXAz1z3cKQYZNVaoF9oVKO96CPodp9DsmGeC2E9W3Ko//wusi4rH5jlq7IEhck5QixL xjgA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n1si213098pgi.380.2019.07.19.01.42.33; Fri, 19 Jul 2019 01:42:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727389AbfGSIkF (ORCPT + 99 others); Fri, 19 Jul 2019 04:40:05 -0400 Received: from mx2.suse.de ([195.135.220.15]:35718 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726402AbfGSIj5 (ORCPT ); Fri, 19 Jul 2019 04:39:57 -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 D2771ACD1; Fri, 19 Jul 2019 08:39:55 +0000 (UTC) From: Nikolay Borisov To: linux-btrfs@vger.kernel.org Cc: paulmck@linux.ibm.com, andrea.parri@amarulasolutions.com, linux-kernel@vger.kernel.org, Nikolay Borisov Subject: [PATCH v2 1/2] btrfs: Implement DRW lock Date: Fri, 19 Jul 2019 11:39:48 +0300 Message-Id: <20190719083949.5351-2-nborisov@suse.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190719083949.5351-1-nborisov@suse.com> References: <20190719083949.5351-1-nborisov@suse.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org A (D)ouble (R)eader (W)riter lock is a locking primitive that allows to have multiple readers or multiple writers but not multiple readers and writers holding it concurrently. The code is factored out from the existing open-coded locking scheme used to exclude pending snapshots from nocow writers and vice-versa. Current implementation actually favors Readers (that is snapshot creaters) to writers (nocow writers of the filesystem). Signed-off-by: Nikolay Borisov --- fs/btrfs/ctree.h | 1 + fs/btrfs/locking.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/locking.h | 20 +++++++++++ 3 files changed, 109 insertions(+) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index da97ff10f421..b7c9359b24a0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -33,6 +33,7 @@ #include "extent_map.h" #include "async-thread.h" #include "block-rsv.h" +#include "locking.h" struct btrfs_trans_handle; struct btrfs_transaction; diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index 98fccce4208c..702c956ed028 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -354,3 +354,91 @@ void btrfs_tree_unlock(struct extent_buffer *eb) write_unlock(&eb->lock); } } + + +int btrfs_drw_lock_init(struct btrfs_drw_lock *lock) +{ + int ret; + + ret = percpu_counter_init(&lock->writers, 0, GFP_KERNEL); + if (ret) + return ret; + + atomic_set(&lock->readers, 0); + init_waitqueue_head(&lock->pending_readers); + init_waitqueue_head(&lock->pending_writers); + + return 0; +} +EXPORT_SYMBOL(btrfs_drw_lock_init); + +void btrfs_drw_lock_destroy(struct btrfs_drw_lock *lock) +{ + percpu_counter_destroy(&lock->writers); +} + +bool btrfs_drw_try_write_lock(struct btrfs_drw_lock *lock) +{ + if (atomic_read(&lock->readers)) + return false; + + percpu_counter_inc(&lock->writers); + + /* + * Ensure writers count is updated before we check for + * pending readers + */ + smp_mb(); + if (atomic_read(&lock->readers)) { + btrfs_drw_write_unlock(lock); + return false; + } + + return true; +} +EXPORT_SYMBOL(btrfs_drw_try_write_lock); + +void btrfs_drw_write_lock(struct btrfs_drw_lock *lock) +{ + while (true) { + if (btrfs_drw_try_write_lock(lock)) + return; + wait_event(lock->pending_writers, !atomic_read(&lock->readers)); + } +} +EXPORT_SYMBOL(btrfs_drw_write_lock); + +void btrfs_drw_write_unlock(struct btrfs_drw_lock *lock) +{ + percpu_counter_dec(&lock->writers); + cond_wake_up(&lock->pending_readers); +} +EXPORT_SYMBOL(btrfs_drw_write_unlock); + +void btrfs_drw_read_lock(struct btrfs_drw_lock *lock) +{ + atomic_inc(&lock->readers); + + /* + * Ensure the pending reader count is perceieved BEFORE this reader + * goes to sleep in case of active writers. This guarantees new writers + * won't be allowed and that the current reader will be woken up when + * the last active writer finishes its jobs. + */ + smp_mb__after_atomic(); + + wait_event(lock->pending_readers, + percpu_counter_sum(&lock->writers) == 0); +} +EXPORT_SYMBOL(btrfs_drw_read_lock); + +void btrfs_drw_read_unlock(struct btrfs_drw_lock *lock) +{ + /* + * Atomic RMW operations imply full barrier, so woken up writers + * are guaranteed to see the decrement + */ + if (atomic_dec_and_test(&lock->readers)) + wake_up(&lock->pending_writers); +} +EXPORT_SYMBOL(btrfs_drw_read_unlock); diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h index 595014f64830..44378c65f843 100644 --- a/fs/btrfs/locking.h +++ b/fs/btrfs/locking.h @@ -6,6 +6,10 @@ #ifndef BTRFS_LOCKING_H #define BTRFS_LOCKING_H +#include +#include +#include + #define BTRFS_WRITE_LOCK 1 #define BTRFS_READ_LOCK 2 #define BTRFS_WRITE_LOCK_BLOCKING 3 @@ -39,4 +43,20 @@ static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw) BUG(); } + +struct btrfs_drw_lock { + atomic_t readers; + struct percpu_counter writers; + wait_queue_head_t pending_writers; + wait_queue_head_t pending_readers; +}; + +int btrfs_drw_lock_init(struct btrfs_drw_lock *lock); +void btrfs_drw_lock_destroy(struct btrfs_drw_lock *lock); +void btrfs_drw_write_lock(struct btrfs_drw_lock *lock); +bool btrfs_drw_try_write_lock(struct btrfs_drw_lock *lock); +void btrfs_drw_write_unlock(struct btrfs_drw_lock *lock); +void btrfs_drw_read_lock(struct btrfs_drw_lock *lock); +void btrfs_drw_read_unlock(struct btrfs_drw_lock *lock); + #endif -- 2.17.1