The following series implements the updated api for wait/wound mutex locks.
The documentation and api should be complete, the implementation may not be
final. There is no support for -rt yet, and TASK_DEADLOCK handling is missing
too. However I believe that this is an implementation detail, and that the
interface for users of the api will not behave differently.
ww_acquire_ctx has been added, and a whole lot of api abuses are now correctly
detected because of the extra state carried in ww_acquire_ctx if debugging is
enabled.
---
Maarten Lankhorst (3):
arch: make __mutex_fastpath_lock_retval return whether fastpath succeeded or not.
mutex: add support for wound/wait style locks, v3
mutex: Add ww tests to lib/locking-selftest.c. v3
Documentation/ww-mutex-design.txt | 322 +++++++++++++++++++++++++
arch/ia64/include/asm/mutex.h | 10 -
arch/powerpc/include/asm/mutex.h | 10 -
arch/sh/include/asm/mutex-llsc.h | 4
arch/x86/include/asm/mutex_32.h | 11 -
arch/x86/include/asm/mutex_64.h | 11 -
include/asm-generic/mutex-dec.h | 10 -
include/asm-generic/mutex-null.h | 2
include/asm-generic/mutex-xchg.h | 10 -
include/linux/mutex-debug.h | 1
include/linux/mutex.h | 257 ++++++++++++++++++++
kernel/mutex.c | 473 ++++++++++++++++++++++++++++++++++---
lib/debug_locks.c | 2
lib/locking-selftest.c | 439 +++++++++++++++++++++++++++++++++-
14 files changed, 1469 insertions(+), 93 deletions(-)
create mode 100644 Documentation/ww-mutex-design.txt
--
Signature
Hello,
Contiguous Memory Allocator is very sensitive about migration failures
of the individual pages. A single page, which causes permanent migration
failure can break large conitguous allocations and cause the failure of
a multimedia device driver.
One of the known issues with migration of CMA pages are the problems of
migrating the anonymous user pages, for which the others called
get_user_pages(). This takes a reference to the given user pages to let
kernel to operate directly on the page content. This is usually used for
preventing swaping out the page contents and doing direct DMA to/from
userspace.
To solving this issue requires preventing locking of the pages, which
are placed in CMA regions, for a long time. Our idea is to migrate
anonymous page content before locking the page in get_user_pages(). This
cannot be done automatically, as get_user_pages() interface is used very
often for various operations, which usually last for a short period of
time (like for example exec syscall). We have added a new flag
indicating that the given get_user_space() call will grab pages for a
long time, thus it is suitable to use the migration workaround in such
cases.
The proposed extensions is used by V4L2/VideoBuf2
(drivers/media/v4l2-core/videobuf2-dma-contig.c), but that is not the
only place which might benefit from it, like any driver which use DMA to
userspace with get_user_pages(). This one is provided to demonstrate the
use case.
I would like to hear some comments on the presented approach. What do
you think about it? Is there a chance to get such workaround merged at
some point to mainline?
Best regards
Marek Szyprowski
Samsung Poland R&D Center
Patch summary:
Marek Szyprowski (5):
mm: introduce migrate_replace_page() for migrating page to the given
target
mm: get_user_pages: use static inline
mm: get_user_pages: use NON-MOVABLE pages when FOLL_DURABLE flag is
set
mm: get_user_pages: migrate out CMA pages when FOLL_DURABLE flag is
set
media: vb2: use FOLL_DURABLE and __get_user_pages() to avoid CMA
migration issues
drivers/media/v4l2-core/videobuf2-dma-contig.c | 8 +-
include/linux/highmem.h | 12 ++-
include/linux/migrate.h | 5 +
include/linux/mm.h | 76 ++++++++++++-
mm/internal.h | 12 +++
mm/memory.c | 136 +++++++++++-------------
mm/migrate.c | 59 ++++++++++
7 files changed, 225 insertions(+), 83 deletions(-)
--
1.7.9.5
Hi all,
I've been looking at a better way to do custom dma allocation algorithms
in a similar style to Ion heaps. Most drivers/clients have come up with
a series of semi-standard ways to get memory (CMA, memblock_reserve,
discontiguous pages etc.) . As these allocation schemes get more and
more complex, there needs to be a since place where all clients (Ion
based driver vs. DRM driver vs. ???) can independently take advantage
of any optimizations and call a single API for the backing allocations.
The dma_map_ops take care of almost everything needed for abstraction
but the question is where should new allocation algorithms be located?
Most of the work has been added to either arm/mm/dma-mapping.c or
dma-contiguous.c . My current thought:
1) split out the dma_map_ops currently in dma-mapping.c into separate
files (dma-mapping-common.c, dma-mapping-iommu.c)
2) Extend dma-contiguous.c to support memblock_reserve memory
3) Place additional algorithms in either arch/arm/mm or
drivers/base/dma-alloc/ as appropriate to the code. This is the part
where I'm most unsure about the direction.
I don't have anything written yet but I plan to draft some patches
assuming the proposed approach sounds reasonable and no one else has
started on something similar already.
Thoughts? Opinions?
Thanks,
Laura
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
Hello,
This is an update for my proposal for device tree integration for
Contiguous Memory Allocator. The code is quite straightforward, but
expect again that the device tree bindings will trigger some discussion.
Just a few words for those who see this code for the first time:
The proposed bindings allows to define contiguous memory regions of
specified base address and size. Then, the defined regions can be
assigned to the given device(s) by adding a property with a phanle to
the defined contiguous memory region. From the device tree perspective
that's all. Once the bindings are added, all the memory allocations from
dma-mapping subsystem will be served from the defined contiguous memory
regions.
Contiguous Memory Allocator is a framework, which lets to provide a
large contiguous memory buffers for (usually a multimedia) devices. The
contiguous memory is reserved during early boot and then shared with
kernel, which is allowed to allocate it for movable pages. Then, when
device driver requests a contigouous buffer, the framework migrates
movable pages out of contiguous region and gives it to the driver. When
device driver frees the buffer, it is added to kernel memory pool again.
For more information, please refer to commit c64be2bb1c6eb43c838b2c6d57
("drivers: add Contiguous Memory Allocator") and d484864dd96e1830e76895
(CMA merge commit).
Why we need device tree bindings for CMA at all?
Older ARM kernels used so called board-based initialization. Those board
files contained a definition of all hardware blocks available on the
target system and particular kernel and driver software configuration
selected by the board maintainer.
In the new approach the board files will be removed completely and
Device Tree approach is used to describe all hardware blocks available
on the target system. By definition, the bindings should be software
independent, so at least in theory it should be possible to use those
bindings with other operating systems than Linux kernel.
However we also need to pass somehow the information about kernel and
device driver software-only configuration data, which were earlier
encoded in the board file. For such data I propose to use /chosen node,
where kernel command line has been already stored. Future bootloaders
will allow to modify or replace particular nodes and one will be able to
use custom /chosen node to configure his system. The proposed patches
introduce /chosen/contiguous-memory node and related bindings, to avoid
complicated encoding of CMA related configuration to kernel command
line.
Best regards
Marek Szyprowski
Samsung Poland R&D Center
Changelog:
v2:
- moved contiguous-memory bindings from /memory to /chosen/contiguous-memory/
node to avoid spreading Linux specific parameters over the whole device
tree definitions
- added support for autoconfigured regions (use zero base)
- fixes minor bugs
v1: http://thread.gmane.org/gmane.linux.drivers.devicetree/30111/
- initial proposal
Patch summary:
Marek Szyprowski (2):
drivers: dma-contiguous: clean source code and prepare for device
tree
drivers: dma-contiguous: add initialization from device tree
Documentation/devicetree/bindings/memory.txt | 101 ++++++++++
arch/arm/boot/dts/skeleton.dtsi | 7 +-
drivers/base/dma-contiguous.c | 278 +++++++++++++++++++-------
include/asm-generic/dma-contiguous.h | 4 +-
include/linux/dma-contiguous.h | 32 ++-
5 files changed, 338 insertions(+), 84 deletions(-)
create mode 100644 Documentation/devicetree/bindings/memory.txt
--
1.7.9.5
This will allow me to call functions that have multiple arguments if fastpath fails.
This is required to support ticket mutexes, because they need to be able to pass an
extra argument to the fail function.
Originally I duplicated the functions, by adding __mutex_fastpath_lock_retval_arg.
This ended up being just a duplication of the existing function, so a way to test
if fastpath was called ended up being better.
This also cleaned up the reservation mutex patch some by being able to call an
atomic_set instead of atomic_xchg, and making it easier to detect if the wrong
unlock function was previously used.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst(a)canonical.com>
---
arch/ia64/include/asm/mutex.h | 10 ++++------
arch/powerpc/include/asm/mutex.h | 10 ++++------
arch/sh/include/asm/mutex-llsc.h | 4 ++--
arch/x86/include/asm/mutex_32.h | 11 ++++-------
arch/x86/include/asm/mutex_64.h | 11 ++++-------
include/asm-generic/mutex-dec.h | 10 ++++------
include/asm-generic/mutex-null.h | 2 +-
include/asm-generic/mutex-xchg.h | 10 ++++------
kernel/mutex.c | 32 ++++++++++++++------------------
9 files changed, 41 insertions(+), 59 deletions(-)
diff --git a/arch/ia64/include/asm/mutex.h b/arch/ia64/include/asm/mutex.h
index bed73a6..f41e66d 100644
--- a/arch/ia64/include/asm/mutex.h
+++ b/arch/ia64/include/asm/mutex.h
@@ -29,17 +29,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
*/
static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(ia64_fetchadd4_acq(count, -1) != 1))
- return fail_fn(count);
+ return -1;
return 0;
}
diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h
index 5399f7e..127ab23 100644
--- a/arch/powerpc/include/asm/mutex.h
+++ b/arch/powerpc/include/asm/mutex.h
@@ -82,17 +82,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
*/
static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(__mutex_dec_return_lock(count) < 0))
- return fail_fn(count);
+ return -1;
return 0;
}
diff --git a/arch/sh/include/asm/mutex-llsc.h b/arch/sh/include/asm/mutex-llsc.h
index 090358a..dad29b6 100644
--- a/arch/sh/include/asm/mutex-llsc.h
+++ b/arch/sh/include/asm/mutex-llsc.h
@@ -37,7 +37,7 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
}
static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
{
int __done, __res;
@@ -51,7 +51,7 @@ __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
: "t");
if (unlikely(!__done || __res != 0))
- __res = fail_fn(count);
+ __res = -1;
return __res;
}
diff --git a/arch/x86/include/asm/mutex_32.h b/arch/x86/include/asm/mutex_32.h
index 03f90c8..b7f6b34 100644
--- a/arch/x86/include/asm/mutex_32.h
+++ b/arch/x86/include/asm/mutex_32.h
@@ -42,17 +42,14 @@ do { \
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if it
- * wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or 1 otherwise.
*/
-static inline int __mutex_fastpath_lock_retval(atomic_t *count,
- int (*fail_fn)(atomic_t *))
+static inline int __mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(atomic_dec_return(count) < 0))
- return fail_fn(count);
+ return -1;
else
return 0;
}
diff --git a/arch/x86/include/asm/mutex_64.h b/arch/x86/include/asm/mutex_64.h
index 68a87b0..2c543ff 100644
--- a/arch/x86/include/asm/mutex_64.h
+++ b/arch/x86/include/asm/mutex_64.h
@@ -37,17 +37,14 @@ do { \
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
*/
-static inline int __mutex_fastpath_lock_retval(atomic_t *count,
- int (*fail_fn)(atomic_t *))
+static inline int __mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(atomic_dec_return(count) < 0))
- return fail_fn(count);
+ return -1;
else
return 0;
}
diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h
index f104af7..d4f9fb4 100644
--- a/include/asm-generic/mutex-dec.h
+++ b/include/asm-generic/mutex-dec.h
@@ -28,17 +28,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
*/
static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(atomic_dec_return(count) < 0))
- return fail_fn(count);
+ return -1;
return 0;
}
diff --git a/include/asm-generic/mutex-null.h b/include/asm-generic/mutex-null.h
index e1bbbc7..efd6206 100644
--- a/include/asm-generic/mutex-null.h
+++ b/include/asm-generic/mutex-null.h
@@ -11,7 +11,7 @@
#define _ASM_GENERIC_MUTEX_NULL_H
#define __mutex_fastpath_lock(count, fail_fn) fail_fn(count)
-#define __mutex_fastpath_lock_retval(count, fail_fn) fail_fn(count)
+#define __mutex_fastpath_lock_retval(count, fail_fn) (-1)
#define __mutex_fastpath_unlock(count, fail_fn) fail_fn(count)
#define __mutex_fastpath_trylock(count, fail_fn) fail_fn(count)
#define __mutex_slowpath_needs_to_unlock() 1
diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h
index c04e0db..f169ec0 100644
--- a/include/asm-generic/mutex-xchg.h
+++ b/include/asm-generic/mutex-xchg.h
@@ -39,18 +39,16 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
* __mutex_fastpath_lock_retval - try to take the lock by moving the count
* from 1 to a 0 value
* @count: pointer of type atomic_t
- * @fail_fn: function to call if the original value was not 1
*
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if it
- * wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
*/
static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
{
if (unlikely(atomic_xchg(count, 0) != 1))
if (likely(atomic_xchg(count, -1) != 1))
- return fail_fn(count);
+ return -1;
return 0;
}
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 52f2301..84a5f07 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -351,10 +351,10 @@ __mutex_unlock_slowpath(atomic_t *lock_count)
* mutex_lock_interruptible() and mutex_trylock().
*/
static noinline int __sched
-__mutex_lock_killable_slowpath(atomic_t *lock_count);
+__mutex_lock_killable_slowpath(struct mutex *lock);
static noinline int __sched
-__mutex_lock_interruptible_slowpath(atomic_t *lock_count);
+__mutex_lock_interruptible_slowpath(struct mutex *lock);
/**
* mutex_lock_interruptible - acquire the mutex, interruptible
@@ -372,12 +372,12 @@ int __sched mutex_lock_interruptible(struct mutex *lock)
int ret;
might_sleep();
- ret = __mutex_fastpath_lock_retval
- (&lock->count, __mutex_lock_interruptible_slowpath);
- if (!ret)
+ ret = __mutex_fastpath_lock_retval(&lock->count);
+ if (likely(!ret)) {
mutex_set_owner(lock);
-
- return ret;
+ return 0;
+ } else
+ return __mutex_lock_interruptible_slowpath(lock);
}
EXPORT_SYMBOL(mutex_lock_interruptible);
@@ -387,12 +387,12 @@ int __sched mutex_lock_killable(struct mutex *lock)
int ret;
might_sleep();
- ret = __mutex_fastpath_lock_retval
- (&lock->count, __mutex_lock_killable_slowpath);
- if (!ret)
+ ret = __mutex_fastpath_lock_retval(&lock->count);
+ if (likely(!ret)) {
mutex_set_owner(lock);
-
- return ret;
+ return 0;
+ } else
+ return __mutex_lock_killable_slowpath(lock);
}
EXPORT_SYMBOL(mutex_lock_killable);
@@ -405,18 +405,14 @@ __mutex_lock_slowpath(atomic_t *lock_count)
}
static noinline int __sched
-__mutex_lock_killable_slowpath(atomic_t *lock_count)
+__mutex_lock_killable_slowpath(struct mutex *lock)
{
- struct mutex *lock = container_of(lock_count, struct mutex, count);
-
return __mutex_lock_common(lock, TASK_KILLABLE, 0, NULL, _RET_IP_);
}
static noinline int __sched
-__mutex_lock_interruptible_slowpath(atomic_t *lock_count)
+__mutex_lock_interruptible_slowpath(struct mutex *lock)
{
- struct mutex *lock = container_of(lock_count, struct mutex, count);
-
return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, NULL, _RET_IP_);
}
#endif
We unlock here when we failed to take the lock.
Signed-off-by: Dan Carpenter <dan.carpenter(a)oracle.com>
---
This is in linux-next, and I think the debugfs code is only in Sumit's
tree.
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 466476f..174cd2c 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -593,7 +593,7 @@ static int dma_buf_describe(struct seq_file *s)
if (ret) {
seq_printf(s,
"\tERROR locking buffer object: skipping\n");
- goto skip_buffer;
+ continue;
}
seq_printf(s, "\t");
@@ -618,7 +618,6 @@ static int dma_buf_describe(struct seq_file *s)
count++;
size += buf_obj->size;
-skip_buffer:
mutex_unlock(&buf_obj->lock);
}
Hi Tom,
On Tuesday 09 April 2013 12:21:08 Tom Cooksey wrote:
> Hi All,
>
> Last year Laurent posted an RFC patch[i] to add support for exporting an
> fbdev framebuffer through dma_buf. Looking through the mailing list
> archives, it doesn't appear to have progressed beyond an RFC? What would be
> needed to get this merged? It would be useful for our Mali T6xx driver
> (which supports importing dma_buf buffers) to allow the GPU to draw
> directly into the framebuffer on platforms which lack a DRM/KMS driver.
The patch was pretty simple, I don't think it would take lots of efforts to
get it to mainline. On the other hand, fbdev is a dying API, so I'm not sure
how much energy we want to spend on upgrading it. I suppose all that would be
needed is a developer with enough interest in the topic to fix the patch
according to the comments.
> [i] Subject: "[RFC/PATCH] fb: Add dma-buf support", sent 20/06/2012.
--
Regards,
Laurent Pinchart
Hi All,
Last year Laurent posted an RFC patch[i] to add support for exporting an fbdev framebuffer through
dma_buf. Looking through the mailing list archives, it doesn't appear to have progressed beyond an
RFC? What would be needed to get this merged? It would be useful for our Mali T6xx driver (which
supports importing dma_buf buffers) to allow the GPU to draw directly into the framebuffer on
platforms which lack a DRM/KMS driver.
[i] Subject: "[RFC/PATCH] fb: Add dma-buf support", sent 20/06/2012.
Cheers,
Tom
The patch series adds a much-missed support for debugfs to dma-buf framework.
Based on the feedback received on v1 of this patch series, support is also
added to allow exporters to provide name-strings that will prove useful
while debugging.
Some more magic can be added for more advanced debugging, but we'll leave that
for the time being.
Best regards,
~Sumit.
---
changes since v2: (based on review comments from Laurent Pinchart)
- reordered functions to avoid forward declaration
- added __exitcall for dma_buf_deinit()
changes since v1:
- added patch to replace dma_buf_export() with dma_buf_export_named(), per
suggestion from Daniel Vetter.
- fixes on init and warnings as reported and corrected by Dave Airlie.
- added locking while walking attachment list - reported by Daniel Vetter.
Sumit Semwal (2):
dma-buf: replace dma_buf_export() with dma_buf_export_named()
dma-buf: Add debugfs support
Documentation/dma-buf-sharing.txt | 13 ++-
drivers/base/dma-buf.c | 170 ++++++++++++++++++++++++++++++++++++-
include/linux/dma-buf.h | 16 +++-
3 files changed, 190 insertions(+), 9 deletions(-)
--
1.7.10.4