From patchwork Fri Oct 6 22:36:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 9990665 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B398460244 for ; Fri, 6 Oct 2017 22:42:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A4A1628E14 for ; Fri, 6 Oct 2017 22:42:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9994B28E4A; Fri, 6 Oct 2017 22:42:29 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DA01928E14 for ; Fri, 6 Oct 2017 22:42:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752953AbdJFWm1 (ORCPT ); Fri, 6 Oct 2017 18:42:27 -0400 Received: from mga01.intel.com ([192.55.52.88]:58926 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752944AbdJFWm0 (ORCPT ); Fri, 6 Oct 2017 18:42:26 -0400 Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Oct 2017 15:42:25 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,486,1500966000"; d="scan'208";a="160377029" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.125]) by fmsmga006.fm.intel.com with ESMTP; 06 Oct 2017 15:42:25 -0700 Subject: [PATCH v7 08/12] fs, mapdirect: introduce ->lease_direct() From: Dan Williams To: linux-nvdimm@lists.01.org Cc: linux-xfs@vger.kernel.org, Jan Kara , "Darrick J. Wong" , linux-rdma@vger.kernel.org, linux-api@vger.kernel.org, Dave Chinner , Christoph Hellwig , "J. Bruce Fields" , linux-mm@kvack.org, Jeff Moyer , linux-fsdevel@vger.kernel.org, Jeff Layton , Ross Zwisler Date: Fri, 06 Oct 2017 15:36:00 -0700 Message-ID: <150732936063.22363.4533598271967882402.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <150732931273.22363.8436792888326501071.stgit@dwillia2-desk3.amr.corp.intel.com> References: <150732931273.22363.8436792888326501071.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.17.1-9-g687f MIME-Version: 1.0 Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Provide a vma operation that registers a lease that is broken by break_layout(). This is motivated by a need to stop in-progress RDMA when the block-map of a DAX-file changes. I.e. since DAX gives direct-access to filesystem blocks we can not allow those blocks to move or change state while they are under active RDMA. So, if the filesystem determines it needs to move blocks it can revoke device access before proceeding. Cc: Jan Kara Cc: Jeff Moyer Cc: Christoph Hellwig Cc: Dave Chinner Cc: "Darrick J. Wong" Cc: Ross Zwisler Cc: Jeff Layton Cc: "J. Bruce Fields" Signed-off-by: Dan Williams --- fs/mapdirect.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mapdirect.h | 23 +++++++++ include/linux/mm.h | 6 ++ 3 files changed, 146 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/mapdirect.c b/fs/mapdirect.c index 9ac7c1d946a2..338cbe055fc7 100644 --- a/fs/mapdirect.c +++ b/fs/mapdirect.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -32,12 +33,26 @@ struct map_direct_state { struct vm_area_struct *mds_vma; }; +struct lease_direct_state { + void *lds_owner; + struct file *lds_file; + unsigned long lds_state; + void (*lds_break_fn)(void *lds_owner); + struct work_struct lds_work; +}; + bool is_map_direct_valid(struct map_direct_state *mds) { return test_bit(MAPDIRECT_VALID, &mds->mds_state); } EXPORT_SYMBOL_GPL(is_map_direct_valid); +bool is_map_direct_broken(struct map_direct_state *mds) +{ + return test_bit(MAPDIRECT_BREAK, &mds->mds_state); +} +EXPORT_SYMBOL_GPL(is_map_direct_broken); + static void put_map_direct(struct map_direct_state *mds) { if (!atomic_dec_and_test(&mds->mds_ref)) @@ -162,6 +177,108 @@ static const struct lock_manager_operations map_direct_lm_ops = { .lm_setup = map_direct_lm_setup, }; +static void lease_direct_invalidate(struct work_struct *work) +{ + struct lease_direct_state *lds; + void *owner; + + lds = container_of(work, typeof(*lds), lds_work); + owner = lds; + lds->lds_break_fn(lds->lds_owner); + vfs_setlease(lds->lds_file, F_UNLCK, NULL, &owner); +} + +static bool lease_direct_lm_break(struct file_lock *fl) +{ + struct lease_direct_state *lds = fl->fl_owner; + + if (!test_and_set_bit(MAPDIRECT_BREAK, &lds->lds_state)) + schedule_work(&lds->lds_work); + return false; +} + +static int lease_direct_lm_change(struct file_lock *fl, int arg, + struct list_head *dispose) +{ + WARN_ON(!(arg & F_UNLCK)); + return lease_modify(fl, arg, dispose); +} + +static const struct lock_manager_operations lease_direct_lm_ops = { + .lm_break = lease_direct_lm_break, + .lm_change = lease_direct_lm_change, +}; + +struct lease_direct *map_direct_lease(struct vm_area_struct *vma, + void (*lds_break_fn)(void *), void *lds_owner) +{ + struct file *file = vma->vm_file; + struct lease_direct_state *lds; + struct lease_direct *ld; + struct file_lock *fl; + int rc = -ENOMEM; + void *owner; + + ld = kzalloc(sizeof(*ld) + sizeof(*lds), GFP_KERNEL); + if (!ld) + return ERR_PTR(-ENOMEM); + INIT_LIST_HEAD(&ld->list); + lds = (struct lease_direct_state *)(ld + 1); + owner = lds; + ld->lds = lds; + lds->lds_break_fn = lds_break_fn; + lds->lds_owner = lds_owner; + INIT_WORK(&lds->lds_work, lease_direct_invalidate); + lds->lds_file = get_file(file); + + fl = locks_alloc_lock(); + if (!fl) + goto err_lock_alloc; + + locks_init_lock(fl); + fl->fl_lmops = &lease_direct_lm_ops; + fl->fl_flags = FL_LAYOUT; + fl->fl_type = F_RDLCK; + fl->fl_end = OFFSET_MAX; + fl->fl_owner = lds; + fl->fl_pid = current->tgid; + fl->fl_file = file; + + rc = vfs_setlease(file, fl->fl_type, &fl, &owner); + if (rc) + goto err_setlease; + if (fl) { + WARN_ON(1); + owner = lds; + vfs_setlease(file, F_UNLCK, NULL, &owner); + owner = NULL; + rc = -ENXIO; + goto err_setlease; + } + + return ld; +err_setlease: + locks_free_lock(fl); +err_lock_alloc: + kfree(lds); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(map_direct_lease); + +void map_direct_lease_destroy(struct lease_direct *ld) +{ + struct lease_direct_state *lds = ld->lds; + struct file *file = lds->lds_file; + void *owner = lds; + + vfs_setlease(file, F_UNLCK, NULL, &owner); + flush_work(&lds->lds_work); + fput(file); + WARN_ON(!list_empty(&ld->list)); + kfree(ld); +} +EXPORT_SYMBOL_GPL(map_direct_lease_destroy); + struct map_direct_state *map_direct_register(int fd, struct vm_area_struct *vma) { struct map_direct_state *mds = kzalloc(sizeof(*mds), GFP_KERNEL); diff --git a/include/linux/mapdirect.h b/include/linux/mapdirect.h index 724e27d8615e..dc4d4ba677d0 100644 --- a/include/linux/mapdirect.h +++ b/include/linux/mapdirect.h @@ -13,17 +13,28 @@ #ifndef __MAPDIRECT_H__ #define __MAPDIRECT_H__ #include +#include struct inode; struct work_struct; struct vm_area_struct; struct map_direct_state; +struct list_direct_state; + +struct lease_direct { + struct list_head list; + struct lease_direct_state *lds; +}; #if IS_ENABLED(CONFIG_FS_DAX) struct map_direct_state *map_direct_register(int fd, struct vm_area_struct *vma); int put_map_direct_vma(struct map_direct_state *mds); void get_map_direct_vma(struct map_direct_state *mds); bool is_map_direct_valid(struct map_direct_state *mds); +bool is_map_direct_broken(struct map_direct_state *mds); +struct lease_direct *map_direct_lease(struct vm_area_struct *vma, + void (*ld_break_fn)(void *), void *ld_owner); +void map_direct_lease_destroy(struct lease_direct *ld); #else static inline struct map_direct_state *map_direct_register(int fd, struct vm_area_struct *vma) @@ -41,5 +52,17 @@ bool is_map_direct_valid(struct map_direct_state *mds) { return false; } +bool is_map_direct_broken(struct map_direct_state *mds) +{ + return false; +} +struct lease_direct *map_direct_lease(struct vm_area_struct *vma, + void (*ld_break_fn)(void *), void *ld_owner) +{ + return ERR_PTR(-EOPNOTSUPP); +} +void map_direct_lease_destroy(struct lease_direct *ld) +{ +} #endif #endif /* __MAPDIRECT_H__ */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 0afa19feb755..d03953f91ce8 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -420,6 +420,12 @@ struct vm_operations_struct { */ struct page *(*find_special_page)(struct vm_area_struct *vma, unsigned long addr); + /* + * Called by rdma memory registration to subscribe for "break" + * events that require any ongoing rdma accesses to quiesce. + */ + struct lease_direct *(*lease_direct)(struct vm_area_struct *vma, + void (*break_fn)(void *), void *owner); }; struct mmu_gather;