Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp8110412ybi; Thu, 6 Jun 2019 06:55:48 -0700 (PDT) X-Google-Smtp-Source: APXvYqyNzSTtzKH5zdNBMzkAp3TLST/SwjzPJWNJCxGtPOK++BKzrnjBj/56wF9zP0r6ZXKPYYyb X-Received: by 2002:a63:fb01:: with SMTP id o1mr3530024pgh.410.1559829348132; Thu, 06 Jun 2019 06:55:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559829348; cv=none; d=google.com; s=arc-20160816; b=WK6TGJW+EzyGWKxc5smOp4owHeDmlXC5wR6El9HalVSloLqDT6y6/fbOaREDVVojOb 8+knwPpXwUmrXlbIovL1nQPP+1wJFS/9MQSpMlubgJX9OZLA0AggYG1sB+vTZ9Nz2BwG lz7BDzKgv6jRXJv8iJ3iWtRej2+uylynMB4Qg5QIE1t8fUHlggky+4IiMQ4gNawYVAUI 1Yiu8Gi2DTlGcaUM3LWAPtLXiy2SwhlkzHdp0GmotdgOHbNIDBI+2tYEtq75r+4Se/uH TABK+ZlMbBWGarunvTLVwpujmAf9i01a7pbkqIflKYi65ZvHRg/Cwy+sytJ5bMxVGvOQ hq5w== 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=FrJKgexWIsQWtZ2cstczlrtQgW4PegEFGkG3hDJPzw8=; b=lC8F7GX/+HOZk6uKl/qeGfq+iE3mvNWDwjnSCBiRyHPjgt+AkVlidocKNoLLW8HQPa KlPqT4fCQammbd2KcDfKgqG6gAPfKTufEgpqAR+wmMyjr8+dkEn48LB9dq90DhtR51Rp Jq5ujuzhWOkkiPP7it172QeEopLVnH33kZ5C/ojL9McV+SglshkHhhKPfVQzqecjAJpT jJB7weUEPqTtFIke8Hs35rMDaPdnb2kzPQREJmQABiepjc3kJqhU0BUBRnnW1S1PKbNr vOAAeMmnaCkoyJOXeyhSOJnBfB0knt0zQAYAg4a8fWjlo0ri3auilAyLuGxMgLERsNI4 b7Zg== 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 r142si2040422pfc.5.2019.06.06.06.55.31; Thu, 06 Jun 2019 06:55:48 -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 S1728669AbfFFNwc (ORCPT + 99 others); Thu, 6 Jun 2019 09:52:32 -0400 Received: from mx2.suse.de ([195.135.220.15]:40312 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728630AbfFFNwY (ORCPT ); Thu, 6 Jun 2019 09:52: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 44F29AF59; Thu, 6 Jun 2019 13:52:22 +0000 (UTC) From: Nikolay Borisov To: linux-btrfs@vger.kernel.org Cc: linux-kernel@vger.kernel.org, andrea.parri@amarulasolutions.com, peterz@infradead.org, paulmck@linux.ibm.com, Nikolay Borisov Subject: [PATCH 1/2] btrfs: Implement DRW lock Date: Thu, 6 Jun 2019 16:52:18 +0300 Message-Id: <20190606135219.1086-2-nborisov@suse.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190606135219.1086-1-nborisov@suse.com> References: <20190606135219.1086-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/Makefile | 2 +- fs/btrfs/drw_lock.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/drw_lock.h | 23 +++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 fs/btrfs/drw_lock.c create mode 100644 fs/btrfs/drw_lock.h diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index ca693dd554e9..dc60127791e6 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -10,7 +10,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ - uuid-tree.o props.o free-space-tree.o tree-checker.o + uuid-tree.o props.o free-space-tree.o tree-checker.o drw_lock.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o diff --git a/fs/btrfs/drw_lock.c b/fs/btrfs/drw_lock.c new file mode 100644 index 000000000000..9681bf7544be --- /dev/null +++ b/fs/btrfs/drw_lock.c @@ -0,0 +1,71 @@ +#include "drw_lock.h" +#include "ctree.h" + +void btrfs_drw_lock_init(struct btrfs_drw_lock *lock) +{ + atomic_set(&lock->readers, 0); + percpu_counter_init(&lock->writers, 0, GFP_KERNEL); + init_waitqueue_head(&lock->pending_readers); + init_waitqueue_head(&lock->pending_writers); +} + +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_read_unlock(lock); + return false; + } + + return true; +} + +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)); + } +} + +void btrfs_drw_write_unlock(struct btrfs_drw_lock *lock) +{ + percpu_counter_dec(&lock->writers); + cond_wake_up(&lock->pending_readers); +} + +void btrfs_drw_read_lock(struct btrfs_drw_lock *lock) +{ + atomic_inc(&lock->readers); + smp_mb__after_atomic(); + + wait_event(lock->pending_readers, + percpu_counter_sum(&lock->writers) == 0); +} + +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); +} + + diff --git a/fs/btrfs/drw_lock.h b/fs/btrfs/drw_lock.h new file mode 100644 index 000000000000..baff59561c06 --- /dev/null +++ b/fs/btrfs/drw_lock.h @@ -0,0 +1,23 @@ +#ifndef BTRFS_DRW_LOCK_H +#define BTRFS_DRW_LOCK_H + +#include +#include +#include + +struct btrfs_drw_lock { + atomic_t readers; + struct percpu_counter writers; + wait_queue_head_t pending_writers; + wait_queue_head_t pending_readers; +}; + +void 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