Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1260353 > unrolled thread
| Started by | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| First post | 2015-11-02 05:40 +0100 |
| Last post | 2015-11-02 05:40 +0100 |
| Articles | 7 on this page of 27 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH v3 00/15] block, dax updates for 4.4 Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
[PATCH v3 12/15] block: enable dax for raw block devices Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
[PATCH v3 04/15] libnvdimm, pmem: move request_queue allocation earlier in probe Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
Re: [PATCH v3 04/15] libnvdimm, pmem: move request_queue allocation earlier in probe Ross Zwisler <ross.zwisler@linux.intel.com> - 2015-11-03 20:20 +0100
[PATCH v3 07/15] kvm: rename pfn_t to kvm_pfn_t Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
[PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
Re: [PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dave Chinner <david@fromorbit.com> - 2015-11-03 01:40 +0100
Re: [PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dan Williams <dan.j.williams@intel.com> - 2015-11-03 08:40 +0100
Re: [PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dave Chinner <david@fromorbit.com> - 2015-11-03 21:30 +0100
Re: [PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dan Williams <dan.j.williams@intel.com> - 2015-11-04 00:10 +0100
Re: [PATCH v3 13/15] block, dax: make dax mappings opt-in by default Dan Williams <dan.j.williams@intel.com> - 2015-11-04 20:30 +0100
[PATCH v3 05/15] libnvdimm, pmem: fix size trim in pmem_direct_access() Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
Re: [PATCH v3 05/15] libnvdimm, pmem: fix size trim in pmem_direct_access() Ross Zwisler <ross.zwisler@linux.intel.com> - 2015-11-03 20:40 +0100
Re: [PATCH v3 05/15] libnvdimm, pmem: fix size trim in pmem_direct_access() Dan Williams <dan.j.williams@intel.com> - 2015-11-03 22:40 +0100
[PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dave Chinner <david@fromorbit.com> - 2015-11-03 02:20 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-03 06:10 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dave Chinner <david@fromorbit.com> - 2015-11-03 06:50 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-03 08:30 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dave Chinner <david@fromorbit.com> - 2015-11-03 22:00 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-03 22:20 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Ross Zwisler <ross.zwisler@linux.intel.com> - 2015-11-03 22:40 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-03 22:50 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Ross Zwisler <ross.zwisler@linux.intel.com> - 2015-11-03 22:20 +0100
Re: [PATCH v3 14/15] dax: dirty extent notification Dan Williams <dan.j.williams@intel.com> - 2015-11-03 22:40 +0100
[PATCH v3 10/15] dax, pmem: introduce zone_device_revoke() and devm_memunmap_pages() Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
[PATCH v3 06/15] um: kill pfn_t Dan Williams <dan.j.williams@intel.com> - 2015-11-02 05:40 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2015-11-03 22:20 +0100 |
| Subject | Re: [PATCH v3 14/15] dax: dirty extent notification |
| Message-ID | <qqR9L-87W-5@gated-at.bofh.it> |
| In reply to | #1261889 |
On Tue, Nov 3, 2015 at 12:51 PM, Dave Chinner <david@fromorbit.com> wrote: > On Mon, Nov 02, 2015 at 11:20:49PM -0800, Dan Williams wrote: >> On Mon, Nov 2, 2015 at 9:40 PM, Dave Chinner <david@fromorbit.com> wrote: >> > On Mon, Nov 02, 2015 at 08:56:24PM -0800, Dan Williams wrote: >> >> No, we definitely can't do that. I think your mental model of the >> >> cache flushing is similar to the disk model where a small buffer is >> >> flushed after a large streaming write. Both Ross' patches and my >> >> approach suffer from the same horror that the cache flushing is O(N) >> >> currently, so we don't want to make it responsible for more data >> >> ranges areas than is strictly necessary. >> > >> > I didn't see anything that was O(N) in Ross's patches. What part of >> > the fsync algorithm that Ross proposed are you refering to here? >> >> We have to issue clflush per touched virtual address rather than a >> constant number of physical ways, or a flush-all instruction. > ..... >> > So don't tell me that tracking dirty pages in the radix tree too >> > slow for DAX and that DAX should not be used for POSIX IO based >> > applications - it should be as fast as buffered IO, if not faster, >> > and if it isn't then we've screwed up real bad. And right now, we're >> > screwing up real bad. >> >> Again, it's not the dirty tracking in the radix I'm worried about it's >> looping through all the virtual addresses within those pages.. > > So, let me summarise what I think you've just said. You are > > 1. fine with looping through the virtual addresses doing cache flushes > synchronously when doing IO despite it having significant > latency and performance costs. No, like I said in the blkdev_issue_zeroout thread we need to replace looping flushes with non-temporal stores and delayed wmb_pmem() wherever possible. > 2. Happy to hack a method into DAX to bypass the filesystems by > pushing information to the block device for it to track regions that > need cache flushes, then add infrastructure to the block device to > track those dirty regions and then walk those addresses and issue > cache flushes when the filesystem issues a REQ_FLUSH IO regardless > of whether the filesystem actually needs those cachelines flushed > for that specific IO? I'm happier with a temporary driver level hack than a temporary core kernel change. This requirement to flush by virtual address is something that, in my opinion, must be addressed by the platform with a reliable global flush or by walking a small constant number of physical-cache-ways. I think we're getting ahead of ourselves jumping to solving this in the core kernel while the question of how to do efficient large flushes is still pending. > 3. Not happy to use the generic mm/vfs level infrastructure > architectected specifically to provide the exact asynchronous > cache flushing/writeback semantics we require because it will > cause too many cache flushes, even though the number of cache > flushes will be, at worst, the same as in 2). Correct, because if/when a platform solution arrives the need to track dirty pfns evaporates. > 1) will work, but as we can see it is *slow*. 3) is what Ross is > implementing - it's a tried and tested architecture that all mm/fs > developers understand, and his explanation of why it will work for > pmem is pretty solid and completely platform/hardware architecture > independent. > > Which leaves this question: How does 2) save us anything in terms of > avoiding iterating virtual addresses and issuing cache flushes > over 3)? And is it sufficient to justify hacking a bypass into DAX > and the additional driver level complexity of having to add dirty > region tracking, flushing and cleaning to REQ_FLUSH operations? > Given what we are talking about amounts to a hardware workaround I think that kind of logic belongs in a driver. If the cache flushing gets fixed and we stop needing to track individual cachelines the flush implementation will look and feel much more like existing storage drivers. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ross Zwisler <ross.zwisler@linux.intel.com> |
|---|---|
| Date | 2015-11-03 22:40 +0100 |
| Subject | Re: [PATCH v3 14/15] dax: dirty extent notification |
| Message-ID | <qqRt8-8fd-17@gated-at.bofh.it> |
| In reply to | #1261889 |
On Wed, Nov 04, 2015 at 07:51:31AM +1100, Dave Chinner wrote: > On Mon, Nov 02, 2015 at 11:20:49PM -0800, Dan Williams wrote: > > On Mon, Nov 2, 2015 at 9:40 PM, Dave Chinner <david@fromorbit.com> wrote: > > > On Mon, Nov 02, 2015 at 08:56:24PM -0800, Dan Williams wrote: > > >> No, we definitely can't do that. I think your mental model of the > > >> cache flushing is similar to the disk model where a small buffer is > > >> flushed after a large streaming write. Both Ross' patches and my > > >> approach suffer from the same horror that the cache flushing is O(N) > > >> currently, so we don't want to make it responsible for more data > > >> ranges areas than is strictly necessary. > > > > > > I didn't see anything that was O(N) in Ross's patches. What part of > > > the fsync algorithm that Ross proposed are you refering to here? > > > > We have to issue clflush per touched virtual address rather than a > > constant number of physical ways, or a flush-all instruction. > ..... > > > So don't tell me that tracking dirty pages in the radix tree too > > > slow for DAX and that DAX should not be used for POSIX IO based > > > applications - it should be as fast as buffered IO, if not faster, > > > and if it isn't then we've screwed up real bad. And right now, we're > > > screwing up real bad. > > > > Again, it's not the dirty tracking in the radix I'm worried about it's > > looping through all the virtual addresses within those pages.. > > So, let me summarise what I think you've just said. You are > > 1. fine with looping through the virtual addresses doing cache flushes > synchronously when doing IO despite it having significant > latency and performance costs. > > 2. Happy to hack a method into DAX to bypass the filesystems by > pushing information to the block device for it to track regions that > need cache flushes, then add infrastructure to the block device to > track those dirty regions and then walk those addresses and issue > cache flushes when the filesystem issues a REQ_FLUSH IO regardless > of whether the filesystem actually needs those cachelines flushed > for that specific IO? > > 3. Not happy to use the generic mm/vfs level infrastructure > architectected specifically to provide the exact asynchronous > cache flushing/writeback semantics we require because it will > cause too many cache flushes, even though the number of cache > flushes will be, at worst, the same as in 2). > > > 1) will work, but as we can see it is *slow*. 3) is what Ross is > implementing - it's a tried and tested architecture that all mm/fs > developers understand, and his explanation of why it will work for > pmem is pretty solid and completely platform/hardware architecture > independent. > > Which leaves this question: How does 2) save us anything in terms of > avoiding iterating virtual addresses and issuing cache flushes > over 3)? And is it sufficient to justify hacking a bypass into DAX > and the additional driver level complexity of having to add dirty > region tracking, flushing and cleaning to REQ_FLUSH operations? I also don't see a benefit of pushing this into the driver. The generic writeback infrastructure that is already in place seems to fit perfectly with what we are trying to do. I feel like putting the flushing infrastructure into the driver, as with my first failed attempt at msync support, ends up solving one aspect of the problem in a non-generic way that is ultimately fatally flawed. The driver inherently doesn't have enough information to solve this problem - we really do need to involve the filesystem and mm layers. For example: 1) The driver can't easily mark regions as clean once they have been flushed, meaning that every time you dirty data you add to an ever increasing list of things that will be flushed on the next REQ_FLUSH. 2) The driver doesn't know how inodes map to blocks, so when you get a REQ_FLUSH for an fsync you end up flushing the dirty regions for *the entire block device*, not just the one inode. 3) The driver doesn't understand how mmap ranges map to block regions, so if someone msyncs a single page (causing a REQ_FLUSH) on a single mmap you will once again flush every region that has ever been dirtied on the entire block device. Each of these cases is handled by the existing writeback infrastructure. I'm strongly in favor of waiting and solving this issue with the radix tree patches. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2015-11-03 22:50 +0100 |
| Subject | Re: [PATCH v3 14/15] dax: dirty extent notification |
| Message-ID | <qqRCO-8it-5@gated-at.bofh.it> |
| In reply to | #1261910 |
On Tue, Nov 3, 2015 at 1:37 PM, Ross Zwisler <ross.zwisler@linux.intel.com> wrote: > On Wed, Nov 04, 2015 at 07:51:31AM +1100, Dave Chinner wrote: >> On Mon, Nov 02, 2015 at 11:20:49PM -0800, Dan Williams wrote: >> > On Mon, Nov 2, 2015 at 9:40 PM, Dave Chinner <david@fromorbit.com> wrote: >> > > On Mon, Nov 02, 2015 at 08:56:24PM -0800, Dan Williams wrote: >> > >> No, we definitely can't do that. I think your mental model of the >> > >> cache flushing is similar to the disk model where a small buffer is >> > >> flushed after a large streaming write. Both Ross' patches and my >> > >> approach suffer from the same horror that the cache flushing is O(N) >> > >> currently, so we don't want to make it responsible for more data >> > >> ranges areas than is strictly necessary. >> > > >> > > I didn't see anything that was O(N) in Ross's patches. What part of >> > > the fsync algorithm that Ross proposed are you refering to here? >> > >> > We have to issue clflush per touched virtual address rather than a >> > constant number of physical ways, or a flush-all instruction. >> ..... >> > > So don't tell me that tracking dirty pages in the radix tree too >> > > slow for DAX and that DAX should not be used for POSIX IO based >> > > applications - it should be as fast as buffered IO, if not faster, >> > > and if it isn't then we've screwed up real bad. And right now, we're >> > > screwing up real bad. >> > >> > Again, it's not the dirty tracking in the radix I'm worried about it's >> > looping through all the virtual addresses within those pages.. >> >> So, let me summarise what I think you've just said. You are >> >> 1. fine with looping through the virtual addresses doing cache flushes >> synchronously when doing IO despite it having significant >> latency and performance costs. >> >> 2. Happy to hack a method into DAX to bypass the filesystems by >> pushing information to the block device for it to track regions that >> need cache flushes, then add infrastructure to the block device to >> track those dirty regions and then walk those addresses and issue >> cache flushes when the filesystem issues a REQ_FLUSH IO regardless >> of whether the filesystem actually needs those cachelines flushed >> for that specific IO? >> >> 3. Not happy to use the generic mm/vfs level infrastructure >> architectected specifically to provide the exact asynchronous >> cache flushing/writeback semantics we require because it will >> cause too many cache flushes, even though the number of cache >> flushes will be, at worst, the same as in 2). >> >> >> 1) will work, but as we can see it is *slow*. 3) is what Ross is >> implementing - it's a tried and tested architecture that all mm/fs >> developers understand, and his explanation of why it will work for >> pmem is pretty solid and completely platform/hardware architecture >> independent. >> >> Which leaves this question: How does 2) save us anything in terms of >> avoiding iterating virtual addresses and issuing cache flushes >> over 3)? And is it sufficient to justify hacking a bypass into DAX >> and the additional driver level complexity of having to add dirty >> region tracking, flushing and cleaning to REQ_FLUSH operations? > > I also don't see a benefit of pushing this into the driver. The generic > writeback infrastructure that is already in place seems to fit perfectly with > what we are trying to do. I feel like putting the flushing infrastructure > into the driver, as with my first failed attempt at msync support, ends up > solving one aspect of the problem in a non-generic way that is ultimately > fatally flawed. > > The driver inherently doesn't have enough information to solve this problem - > we really do need to involve the filesystem and mm layers. For example: > > 1) The driver can't easily mark regions as clean once they have been flushed, > meaning that every time you dirty data you add to an ever increasing list of > things that will be flushed on the next REQ_FLUSH. > > 2) The driver doesn't know how inodes map to blocks, so when you get a > REQ_FLUSH for an fsync you end up flushing the dirty regions for *the entire > block device*, not just the one inode. > > 3) The driver doesn't understand how mmap ranges map to block regions, so if > someone msyncs a single page (causing a REQ_FLUSH) on a single mmap you will > once again flush every region that has ever been dirtied on the entire block > device. > > Each of these cases is handled by the existing writeback infrastructure. I'm > strongly in favor of waiting and solving this issue with the radix tree > patches. Again, all of these holes are mitigated by turning off DAX or fixing the app. The radix solution does nothing to address the worst case flushing and will spin, single-threaded flushing the world. So I remain strongly against the core change, but that's ultimately not my call. Looks like we're leaving this broken for 4.4... -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ross Zwisler <ross.zwisler@linux.intel.com> |
|---|---|
| Date | 2015-11-03 22:20 +0100 |
| Subject | Re: [PATCH v3 14/15] dax: dirty extent notification |
| Message-ID | <qqR9M-87W-21@gated-at.bofh.it> |
| In reply to | #1261198 |
On Mon, Nov 02, 2015 at 08:56:24PM -0800, Dan Williams wrote: > On Mon, Nov 2, 2015 at 5:16 PM, Dave Chinner <david@fromorbit.com> wrote: > > On Sun, Nov 01, 2015 at 11:30:58PM -0500, Dan Williams wrote: <> > > Yes, that's a basic feature of Ross's patches. Hence I think this > > special case DAX<->bdev interface is the wrong direction to be > > taking. > > So here's my problem with the "track dirty mappings" in the core > mm/vfs approach, it's harder to unwind and delete when it turns out no > application actually needs it, or the platform gives us an O(1) flush > method that is independent of dirty pte tracking. I don't think that we'll ever be able to "unwind and delete" the dirty page tracking. Even if *some* platform gives us an 0(1) flush method independent of PTE tracking, that will be an optimized path that will need to live along side the path that we'll need to keep for other architectures (like all the ones that exist today). -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2015-11-03 22:40 +0100 |
| Subject | Re: [PATCH v3 14/15] dax: dirty extent notification |
| Message-ID | <qqRt9-8fd-29@gated-at.bofh.it> |
| In reply to | #1261902 |
On Tue, Nov 3, 2015 at 1:18 PM, Ross Zwisler <ross.zwisler@linux.intel.com> wrote: > On Mon, Nov 02, 2015 at 08:56:24PM -0800, Dan Williams wrote: >> On Mon, Nov 2, 2015 at 5:16 PM, Dave Chinner <david@fromorbit.com> wrote: >> > On Sun, Nov 01, 2015 at 11:30:58PM -0500, Dan Williams wrote: > <> >> > Yes, that's a basic feature of Ross's patches. Hence I think this >> > special case DAX<->bdev interface is the wrong direction to be >> > taking. >> >> So here's my problem with the "track dirty mappings" in the core >> mm/vfs approach, it's harder to unwind and delete when it turns out no >> application actually needs it, or the platform gives us an O(1) flush >> method that is independent of dirty pte tracking. > > I don't think that we'll ever be able to "unwind and delete" the dirty page > tracking. Even if *some* platform gives us an 0(1) flush method independent > of PTE tracking, that will be an optimized path that will need to live along > side the path that we'll need to keep for other architectures (like all the > ones that exist today). Other architectures are in worse shape when we start talking about virtually tagged caches. If an architecture can't support DAX efficiently I don't know why we would jump through hoops in the core to allow it to use DAX. In the interim to make forward progress we have a safe workaround in the driver, and when the reports come in about fsync taking too much time the response is "switch from fsync to NVML" or "turn off DAX (ideally at the inode)". What's broken about those mitigation options? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2015-11-02 05:40 +0100 |
| Subject | [PATCH v3 10/15] dax, pmem: introduce zone_device_revoke() and devm_memunmap_pages() |
| Message-ID | <qqf4u-Og-29@gated-at.bofh.it> |
| In reply to | #1260353 |
Before we allow ZONE_DEVICE pages to be put into active use outside of
the pmem driver, we need a mechanism to revoke access and assert they
are idle when the driver is shutdown. devm_memunmap_pages() checks that
the reference count passed in at devm_memremap_pages() time is dead, and
then uses zone_device_revoke() to unmap any active inode mappings.
For pmem, it is using the q_usage_counter percpu_ref from its
request_queue as the reference count for devm_memremap_pages().
Cc: Jan Kara <jack@suse.com>
Cc: Dave Hansen <dave@sr71.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: Matthew Wilcox <willy@linux.intel.com>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
drivers/nvdimm/pmem.c | 50 +++++++++++++++++++++----
fs/dax.c | 20 ++++++++++
include/linux/io.h | 17 ---------
include/linux/mm.h | 25 +++++++++++++
kernel/memremap.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 182 insertions(+), 28 deletions(-)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 09093372e5f0..aa2f1292120a 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -24,12 +24,15 @@
#include <linux/memory_hotplug.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
+#include <linux/async.h>
#include <linux/slab.h>
#include <linux/pmem.h>
#include <linux/nd.h>
#include "pfn.h"
#include "nd.h"
+static ASYNC_DOMAIN_EXCLUSIVE(async_pmem);
+
struct pmem_device {
struct request_queue *pmem_queue;
struct gendisk *pmem_disk;
@@ -147,7 +150,8 @@ static struct pmem_device *pmem_alloc(struct device *dev,
pmem->pfn_flags = PFN_DEV;
if (pmem_should_map_pages(dev)) {
- pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res);
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res,
+ &q->q_usage_counter);
pmem->pfn_flags |= PFN_MAP;
} else
pmem->virt_addr = (void __pmem *) devm_memremap(dev,
@@ -163,14 +167,43 @@ static struct pmem_device *pmem_alloc(struct device *dev,
return pmem;
}
-static void pmem_detach_disk(struct pmem_device *pmem)
+
+static void async_blk_cleanup_queue(void *data, async_cookie_t cookie)
{
+ struct pmem_device *pmem = data;
+
+ blk_cleanup_queue(pmem->pmem_queue);
+}
+
+static void pmem_detach_disk(struct device *dev)
+{
+ struct pmem_device *pmem = dev_get_drvdata(dev);
+ struct request_queue *q = pmem->pmem_queue;
+
if (!pmem->pmem_disk)
return;
del_gendisk(pmem->pmem_disk);
put_disk(pmem->pmem_disk);
- blk_cleanup_queue(pmem->pmem_queue);
+ async_schedule_domain(async_blk_cleanup_queue, pmem, &async_pmem);
+
+ if (pmem_should_map_pages(dev)) {
+ /*
+ * Wait for queue to go dead so that we know no new
+ * references will be taken against the pages allocated
+ * by devm_memremap_pages().
+ */
+ blk_wait_queue_dead(q);
+
+ /*
+ * Manually release the page mapping so that
+ * blk_cleanup_queue() can complete queue draining.
+ */
+ devm_memunmap_pages(dev, (void __force *) pmem->virt_addr);
+ }
+
+ /* Wait for blk_cleanup_queue() to finish */
+ async_synchronize_full_domain(&async_pmem);
}
static int pmem_attach_disk(struct device *dev,
@@ -299,11 +332,9 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
static int nvdimm_namespace_detach_pfn(struct nd_namespace_common *ndns)
{
struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
- struct pmem_device *pmem;
/* free pmem disk */
- pmem = dev_get_drvdata(&nd_pfn->dev);
- pmem_detach_disk(pmem);
+ pmem_detach_disk(&nd_pfn->dev);
/* release nd_pfn resources */
kfree(nd_pfn->pfn_sb);
@@ -321,6 +352,7 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
struct nd_region *nd_region;
struct nd_pfn_sb *pfn_sb;
struct pmem_device *pmem;
+ struct request_queue *q;
phys_addr_t offset;
int rc;
@@ -357,8 +389,10 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
/* establish pfn range for lookup, and switch to direct map */
pmem = dev_get_drvdata(dev);
+ q = pmem->pmem_queue;
devm_memunmap(dev, (void __force *) pmem->virt_addr);
- pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res);
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res,
+ &q->q_usage_counter);
pmem->pfn_flags |= PFN_MAP;
if (IS_ERR(pmem->virt_addr)) {
rc = PTR_ERR(pmem->virt_addr);
@@ -428,7 +462,7 @@ static int nd_pmem_remove(struct device *dev)
else if (is_nd_pfn(dev))
nvdimm_namespace_detach_pfn(pmem->ndns);
else
- pmem_detach_disk(pmem);
+ pmem_detach_disk(dev);
return 0;
}
diff --git a/fs/dax.c b/fs/dax.c
index 4d6861f022d9..ac8992e86779 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -327,6 +327,23 @@ static int copy_user_bh(struct page *to, struct inode *inode,
return 0;
}
+/* must be called within a dax_map_atomic / dax_unmap_atomic section */
+static void dax_account_mapping(struct block_device *bdev, pfn_t pfn,
+ struct address_space *mapping)
+{
+ /*
+ * If we are establishing a mapping for a page mapped pfn, take an
+ * extra reference against the request_queue. See zone_device_revoke
+ * for the paired decrement.
+ */
+ if (pfn_t_has_page(pfn)) {
+ struct page *page = pfn_t_to_page(pfn);
+
+ page->mapping = mapping;
+ percpu_ref_get(&bdev->bd_queue->q_usage_counter);
+ }
+}
+
static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -364,6 +381,8 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
clear_pmem(addr, PAGE_SIZE);
wmb_pmem();
}
+
+ dax_account_mapping(bdev, pfn, mapping);
dax_unmap_atomic(bdev, addr);
error = vm_insert_mixed(vma, vaddr, pfn_t_to_pfn(pfn));
@@ -677,6 +696,7 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
result |= VM_FAULT_MAJOR;
}
+ dax_account_mapping(bdev, pfn, mapping);
dax_unmap_atomic(bdev, kaddr);
result |= vmf_insert_pfn_pmd(vma, address, pmd,
diff --git a/include/linux/io.h b/include/linux/io.h
index de64c1e53612..2f2f8859abd9 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -87,23 +87,6 @@ void *devm_memremap(struct device *dev, resource_size_t offset,
size_t size, unsigned long flags);
void devm_memunmap(struct device *dev, void *addr);
-void *__devm_memremap_pages(struct device *dev, struct resource *res);
-
-#ifdef CONFIG_ZONE_DEVICE
-void *devm_memremap_pages(struct device *dev, struct resource *res);
-#else
-static inline void *devm_memremap_pages(struct device *dev, struct resource *res)
-{
- /*
- * Fail attempts to call devm_memremap_pages() without
- * ZONE_DEVICE support enabled, this requires callers to fall
- * back to plain devm_memremap() based on config
- */
- WARN_ON_ONCE(1);
- return ERR_PTR(-ENXIO);
-}
-#endif
-
/*
* Some systems do not have legacy ISA devices.
* /dev/port is not a valid interface on these systems.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b8a90c481ae4..f6225140b5d7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -717,6 +717,31 @@ static inline enum zone_type page_zonenum(const struct page *page)
return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
}
+struct percpu_ref;
+struct resource;
+struct device;
+#ifdef CONFIG_ZONE_DEVICE
+void devm_memunmap_pages(struct device *dev, void *addr);
+void *devm_memremap_pages(struct device *dev, struct resource *res,
+ struct percpu_ref *ref);
+#else
+static inline void devm_memunmap_pages(struct device *dev, void *addr)
+{
+}
+
+static inline void *devm_memremap_pages(struct device *dev,
+ struct resource *res, struct percpu_ref *ref)
+{
+ /*
+ * Fail attempts to call devm_memremap_pages() without
+ * ZONE_DEVICE support enabled, this requires callers to fall
+ * back to plain devm_memremap() based on config
+ */
+ WARN_ON_ONCE(1);
+ return ERR_PTR(-ENXIO);
+}
+#endif
+
#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
#define SECTION_IN_PAGE_FLAGS
#endif
diff --git a/kernel/memremap.c b/kernel/memremap.c
index 3218e8b1fc28..a73e18d8a120 100644
--- a/kernel/memremap.c
+++ b/kernel/memremap.c
@@ -12,9 +12,11 @@
*/
#include <linux/device.h>
#include <linux/types.h>
+#include <linux/fs.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/memory_hotplug.h>
+#include <linux/percpu-refcount.h>
#ifndef ioremap_cache
/* temporary while we convert existing ioremap_cache users to memremap */
@@ -140,17 +142,88 @@ EXPORT_SYMBOL(devm_memunmap);
#ifdef CONFIG_ZONE_DEVICE
struct page_map {
struct resource res;
+ struct percpu_ref *ref;
};
-static void devm_memremap_pages_release(struct device *dev, void *res)
+static unsigned long pfn_first(struct page_map *page_map)
{
- struct page_map *page_map = res;
+ const struct resource *res = &page_map->res;
+
+ return res->start >> PAGE_SHIFT;
+}
+
+static unsigned long pfn_end(struct page_map *page_map)
+{
+ const struct resource *res = &page_map->res;
+
+ return (res->start + resource_size(res)) >> PAGE_SHIFT;
+}
+
+#define for_each_device_pfn(pfn, map) \
+ for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++)
+
+static void zone_device_revoke(struct device *dev, struct page_map *page_map)
+{
+ unsigned long pfn;
+ int retry = 3;
+ struct percpu_ref *ref = page_map->ref;
+ struct address_space *mapping_prev;
+
+ if (percpu_ref_tryget_live(ref)) {
+ dev_WARN(dev, "%s: page mapping is still live!\n", __func__);
+ percpu_ref_put(ref);
+ }
+
+ retry:
+ mapping_prev = NULL;
+ for_each_device_pfn(pfn, page_map) {
+ struct page *page = pfn_to_page(pfn);
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = mapping ? mapping->host : NULL;
+
+ dev_WARN_ONCE(dev, atomic_read(&page->_count) < 1,
+ "%s: ZONE_DEVICE page was freed!\n", __func__);
+
+ /* See dax_account_mapping */
+ if (mapping) {
+ percpu_ref_put(ref);
+ page->mapping = NULL;
+ }
+
+ if (!mapping || !inode || mapping == mapping_prev) {
+ dev_WARN_ONCE(dev, atomic_read(&page->_count) > 1,
+ "%s: unexpected elevated page count pfn: %lx\n",
+ __func__, pfn);
+ continue;
+ }
+
+ unmap_mapping_range(mapping, 0, 0, 1);
+ mapping_prev = mapping;
+ }
+
+ /*
+ * Straggling mappings may have been established immediately
+ * after the percpu_ref was killed.
+ */
+ if (!percpu_ref_is_zero(ref) && retry--)
+ goto retry;
+
+ if (!percpu_ref_is_zero(ref))
+ dev_warn(dev, "%s: not all references released\n", __func__);
+}
+
+static void devm_memremap_pages_release(struct device *dev, void *data)
+{
+ struct page_map *page_map = data;
+
+ zone_device_revoke(dev, page_map);
/* pages are dead and unused, undo the arch mapping */
arch_remove_memory(page_map->res.start, resource_size(&page_map->res));
}
-void *devm_memremap_pages(struct device *dev, struct resource *res)
+void *devm_memremap_pages(struct device *dev, struct resource *res,
+ struct percpu_ref *ref)
{
int is_ram = region_intersects(res->start, resource_size(res),
"System RAM");
@@ -172,6 +245,7 @@ void *devm_memremap_pages(struct device *dev, struct resource *res)
return ERR_PTR(-ENOMEM);
memcpy(&page_map->res, res, sizeof(*res));
+ page_map->ref = ref;
nid = dev_to_node(dev);
if (nid < 0)
@@ -187,4 +261,22 @@ void *devm_memremap_pages(struct device *dev, struct resource *res)
return __va(res->start);
}
EXPORT_SYMBOL(devm_memremap_pages);
+
+static int page_map_match(struct device *dev, void *res, void *match_data)
+{
+ struct page_map *page_map = res;
+ resource_size_t phys = *(resource_size_t *) match_data;
+
+ return page_map->res.start == phys;
+}
+
+void devm_memunmap_pages(struct device *dev, void *addr)
+{
+ resource_size_t start = __pa(addr);
+
+ if (devres_release(dev, devm_memremap_pages_release, page_map_match,
+ &start) != 0)
+ dev_WARN(dev, "failed to find page map to release\n");
+}
+EXPORT_SYMBOL(devm_memunmap_pages);
#endif /* CONFIG_ZONE_DEVICE */
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2015-11-02 05:40 +0100 |
| Subject | [PATCH v3 06/15] um: kill pfn_t |
| Message-ID | <qqf4u-Og-31@gated-at.bofh.it> |
| In reply to | #1260353 |
The core has developed a need for a "pfn_t" type [1]. Convert the usage
of pfn_t by usermode-linux to an unsigned long, and update pfn_to_phys()
to drop its expectation of a typed pfn.
[1]: https://lists.01.org/pipermail/linux-nvdimm/2015-September/002199.html
Cc: Dave Hansen <dave@sr71.net>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
arch/um/include/asm/page.h | 6 +++---
arch/um/include/asm/pgtable-3level.h | 4 ++--
arch/um/include/asm/pgtable.h | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h
index 71c5d132062a..fe26a5e06268 100644
--- a/arch/um/include/asm/page.h
+++ b/arch/um/include/asm/page.h
@@ -18,6 +18,7 @@
struct page;
+#include <linux/pfn.h>
#include <linux/types.h>
#include <asm/vm-flags.h>
@@ -76,7 +77,6 @@ typedef struct { unsigned long pmd; } pmd_t;
#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE))
#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot))
-typedef unsigned long pfn_t;
typedef unsigned long phys_t;
#endif
@@ -109,8 +109,8 @@ extern unsigned long uml_physmem;
#define __pa(virt) to_phys((void *) (unsigned long) (virt))
#define __va(phys) to_virt((unsigned long) (phys))
-#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT))
-#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT))
+#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
+#define pfn_to_phys(pfn) PFN_PHYS(pfn)
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h
index 2b4274e7c095..bae8523a162f 100644
--- a/arch/um/include/asm/pgtable-3level.h
+++ b/arch/um/include/asm/pgtable-3level.h
@@ -98,7 +98,7 @@ static inline unsigned long pte_pfn(pte_t pte)
return phys_to_pfn(pte_val(pte));
}
-static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
+static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
pte_t pte;
phys_t phys = pfn_to_phys(page_nr);
@@ -107,7 +107,7 @@ static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
return pte;
}
-static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot)
+static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
{
return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
}
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 18eb9924dda3..7485398d0737 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -271,7 +271,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys))
#define __virt_to_page(virt) phys_to_page(__pa(virt))
-#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page))
+#define page_to_phys(page) pfn_to_phys(page_to_pfn(page))
#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
#define mk_pte(page, pgprot) \
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web