Re: [Intel-gfx] [PATCH 27/38] drm/i915: Introduce the i915_user_extension_method

2019-01-22 Thread Tvrtko Ursulin


On 22/01/2019 10:47, Chris Wilson wrote:

Quoting Tvrtko Ursulin (2019-01-22 09:31:31)


On 18/01/2019 14:00, Chris Wilson wrote:

+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+
+#include "i915_user_extensions.h"
+
+int i915_user_extensions(struct i915_user_extension __user *ext,
+  const i915_user_extension_fn *tbl,
+  unsigned long count,


I would be tempted to limit the count to unsigned int. 4 billion
extensions should be enough for everyone. :)


I just picked the natural type, thinking having it the same width as
ARRAY_SIZE might save a few questions from semantic analysers.


+{
+ while (ext) {
+ int err;
+ u64 x;
+
+ cond_resched();
+ if (signal_pending(current))
+ return -EINTR;


What was your thinking behind this? It feels like, since here we are not
doing any explicit wait/sleeps, that at this level the code shouldn't
bother with it.


This ties into the discussion vvv


+ if (get_user(x, >name))
+ return -EFAULT;
+
+ err = -EINVAL;
+ if (x < count && tbl[x])
+ err = tbl[x](ext, data);
+ if (err)
+ return err;


We talked about providing unwind on failure ie. option for destructor
call backs. You gave up on that?


The patch is simply called 'merde'. Yes, unwind on failure does not lend
itself to a simple tail call implementation :) And it doesn't lend
itself nicely to writing the stacked cleanup handlers either. (So I
stuck with the solution of just doing a single cleanup on failure, safe
in the knowledge that the most complicated case in this series is
trivial.)

Thinking about the issues with providing a stack for unwind, leads to
the nasty question of how big a stack exactly do we want to provide.
Limiting the chain is required for defense against misuse, but what
depth? For the chained parameter setup of a single shot context create,
we could easily be into the dozens of parameters and extensions blocks.
The extreme I've been contemplating is a multi-batch execbuf setup (with
all the fancy extensions for e.g. semi-privileged fancy register setup),
for that I've been thinking about how this interface would extend to
supporting many chained chunks. What makes a good upper bound for stack
depth? 32? 64? 512? Pick a number, it won't be enough for someone. (Now,
really passing that much information through an ioctl means our design
is broken ;)

So... The break on interrupt there was for the silly protection against
recursion, if it doesn't result in an invalid command.

Another reason the patch was called merde.

I think the chained API extension is very powerful. Being able to do
arbitrary things like a single-shot context creation ioctl and still be
able to redefine/extend the interface as needs demands, is compelling.


I did not think about unwind implementation details. :)

We could make the ABI double linked list? But the feeling is bad..

Or have some reasonable stack size and if overflows fall back to a very 
inefficient lookup from root to walk backwards. Sounds okay for this use 
case since we would never overflow even a small stack, and even the 
inefficient walk on unwind would be a) fast and b) rare.


But since you mention stack sizes like 512 I wonder I did not quite 
grasp how much you'd want to use extensions in the future. :)



+/*
+ * i915_user_extension: Base class for defining a chain of extensions
+ *
+ * Many interfaces need to grow over time. In most cases we can simply
+ * extend the struct and have userspace pass in more data. Another option,
+ * as demonstrated by Vulkan's approach to providing extensions for forward
+ * and backward compatibility, is to use a list of optional structs to
+ * provide those extra details.
+ *
+ * The key advantage to using an extension chain is that it allows us to
+ * redefine the interface more easily than an ever growing struct of
+ * increasing complexity, and for large parts of that interface to be
+ * entirely optional. The downside is more pointer chasing; chasing across
+ * the __user boundary with pointers encapsulated inside u64.
+ */
+struct i915_user_extension {
+ __u64 next_extension;
+ __u64 name;


s/name/id/ ?


I think name is common parlance for extensions/parameters? At least I've
been using it like it was :) And I was trying to retrospectively restrict
'id' for handles tracked by an idr! :)


I don't know if it is common, it is completely new to me. Maybe it is.. 
Or how about type?


Regards,

Tvrtko
___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx


Re: [Intel-gfx] [PATCH 27/38] drm/i915: Introduce the i915_user_extension_method

2019-01-22 Thread Chris Wilson
Quoting Tvrtko Ursulin (2019-01-22 09:31:31)
> 
> On 18/01/2019 14:00, Chris Wilson wrote:
> > +/*
> > + * SPDX-License-Identifier: MIT
> > + *
> > + * Copyright © 2018 Intel Corporation
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#include "i915_user_extensions.h"
> > +
> > +int i915_user_extensions(struct i915_user_extension __user *ext,
> > +  const i915_user_extension_fn *tbl,
> > +  unsigned long count,
> 
> I would be tempted to limit the count to unsigned int. 4 billion 
> extensions should be enough for everyone. :)

I just picked the natural type, thinking having it the same width as
ARRAY_SIZE might save a few questions from semantic analysers.

> > +{
> > + while (ext) {
> > + int err;
> > + u64 x;
> > +
> > + cond_resched();
> > + if (signal_pending(current))
> > + return -EINTR;
> 
> What was your thinking behind this? It feels like, since here we are not 
> doing any explicit wait/sleeps, that at this level the code shouldn't 
> bother with it.

This ties into the discussion vvv

> > + if (get_user(x, >name))
> > + return -EFAULT;
> > +
> > + err = -EINVAL;
> > + if (x < count && tbl[x])
> > + err = tbl[x](ext, data);
> > + if (err)
> > + return err;
> 
> We talked about providing unwind on failure ie. option for destructor 
> call backs. You gave up on that?

The patch is simply called 'merde'. Yes, unwind on failure does not lend
itself to a simple tail call implementation :) And it doesn't lend
itself nicely to writing the stacked cleanup handlers either. (So I
stuck with the solution of just doing a single cleanup on failure, safe
in the knowledge that the most complicated case in this series is
trivial.)

Thinking about the issues with providing a stack for unwind, leads to
the nasty question of how big a stack exactly do we want to provide.
Limiting the chain is required for defense against misuse, but what
depth? For the chained parameter setup of a single shot context create,
we could easily be into the dozens of parameters and extensions blocks.
The extreme I've been contemplating is a multi-batch execbuf setup (with
all the fancy extensions for e.g. semi-privileged fancy register setup),
for that I've been thinking about how this interface would extend to
supporting many chained chunks. What makes a good upper bound for stack
depth? 32? 64? 512? Pick a number, it won't be enough for someone. (Now,
really passing that much information through an ioctl means our design
is broken ;)

So... The break on interrupt there was for the silly protection against
recursion, if it doesn't result in an invalid command.

Another reason the patch was called merde.

I think the chained API extension is very powerful. Being able to do
arbitrary things like a single-shot context creation ioctl and still be
able to redefine/extend the interface as needs demands, is compelling.

> > +/*
> > + * i915_user_extension: Base class for defining a chain of extensions
> > + *
> > + * Many interfaces need to grow over time. In most cases we can simply
> > + * extend the struct and have userspace pass in more data. Another option,
> > + * as demonstrated by Vulkan's approach to providing extensions for forward
> > + * and backward compatibility, is to use a list of optional structs to
> > + * provide those extra details.
> > + *
> > + * The key advantage to using an extension chain is that it allows us to
> > + * redefine the interface more easily than an ever growing struct of
> > + * increasing complexity, and for large parts of that interface to be
> > + * entirely optional. The downside is more pointer chasing; chasing across
> > + * the __user boundary with pointers encapsulated inside u64.
> > + */
> > +struct i915_user_extension {
> > + __u64 next_extension;
> > + __u64 name;
> 
> s/name/id/ ?

I think name is common parlance for extensions/parameters? At least I've
been using it like it was :) And I was trying to retrospectively restrict
'id' for handles tracked by an idr! :)
-Chris
___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx


Re: [Intel-gfx] [PATCH 27/38] drm/i915: Introduce the i915_user_extension_method

2019-01-22 Thread Tvrtko Ursulin


On 18/01/2019 14:00, Chris Wilson wrote:

An idea for extending uABI inspired by Vulkan's extension chains.
Instead of expanding the data struct for each ioctl every time we need
to add a new feature, define an extension chain instead. As we add
optional interfaces to control the ioctl, we define a new extension
struct that can be linked into the ioctl data only when required by the
user. The key advantage being able to ignore large control structs for
optional interfaces/extensions, while being able to process them in a
consistent manner.

In comparison to other extensible ioctls, the key difference is the
use of a linked chain of extension structs vs an array of tagged
pointers. For example,

struct drm_amdgpu_cs_chunk {
 __u32   chunk_id;
 __u32   length_dw;
 __u64   chunk_data;
};

struct drm_amdgpu_cs_in {
 __u32   ctx_id;
 __u32   bo_list_handle;
 __u32   num_chunks;
 __u32   _pad;
 __u64   chunks;
};

allows userspace to pass in array of pointers to extension structs, but
must therefore keep constructing that array along side the command stream.
In dynamic situations like that, a linked list is preferred and does not
similar from extra cache line misses as the extension structs themselves


s/similar/suffer/ I think.


must still be loaded separate to the chunks array.

v2: Apply the tail call optimisation directly to nip the worry of stack
overflow in the bud.

Signed-off-by: Chris Wilson 
---
  drivers/gpu/drm/i915/Makefile   |  1 +
  drivers/gpu/drm/i915/i915_user_extensions.c | 42 +
  drivers/gpu/drm/i915/i915_user_extensions.h | 20 ++
  include/uapi/drm/i915_drm.h | 20 ++
  4 files changed, 83 insertions(+)
  create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.c
  create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 65ed00db..f206fbc85cee 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -45,6 +45,7 @@ i915-y := i915_drv.o \
  i915_sw_fence.o \
  i915_syncmap.o \
  i915_sysfs.o \
+ i915_user_extensions.o \
  intel_csr.o \
  intel_device_info.o \
  intel_pm.o \
diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c 
b/drivers/gpu/drm/i915/i915_user_extensions.c
new file mode 100644
index ..5d90c368f185
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_user_extensions.c
@@ -0,0 +1,42 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+
+#include "i915_user_extensions.h"
+
+int i915_user_extensions(struct i915_user_extension __user *ext,
+const i915_user_extension_fn *tbl,
+unsigned long count,


I would be tempted to limit the count to unsigned int. 4 billion 
extensions should be enough for everyone. :)


ABI can remain u64, but implementation I think in this form does not 
need it.



+void *data)
+{
+   while (ext) {
+   int err;
+   u64 x;
+
+   cond_resched();
+   if (signal_pending(current))
+   return -EINTR;


What was your thinking behind this? It feels like, since here we are not 
doing any explicit wait/sleeps, that at this level the code shouldn't 
bother with it.



+
+   if (get_user(x, >name))
+   return -EFAULT;
+
+   err = -EINVAL;
+   if (x < count && tbl[x])
+   err = tbl[x](ext, data);
+   if (err)
+   return err;


We talked about providing unwind on failure ie. option for destructor 
call backs. You gave up on that?



+
+   if (get_user(x, >next_extension))
+   return -EFAULT;
+
+   ext = u64_to_user_ptr(x);
+   }
+
+   return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_user_extensions.h 
b/drivers/gpu/drm/i915/i915_user_extensions.h
new file mode 100644
index ..313a510b068a
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_user_extensions.h
@@ -0,0 +1,20 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#ifndef I915_USER_EXTENSIONS_H
+#define I915_USER_EXTENSIONS_H
+
+struct i915_user_extension;
+
+typedef int (*i915_user_extension_fn)(struct i915_user_extension __user *ext,
+ void *data);
+
+int i915_user_extensions(struct i915_user_extension __user *ext,
+const i915_user_extension_fn *tbl,
+unsigned long count,
+void *data);
+
+#endif /* I915_USER_EXTENSIONS_H */
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 

[Intel-gfx] [PATCH 27/38] drm/i915: Introduce the i915_user_extension_method

2019-01-18 Thread Chris Wilson
An idea for extending uABI inspired by Vulkan's extension chains.
Instead of expanding the data struct for each ioctl every time we need
to add a new feature, define an extension chain instead. As we add
optional interfaces to control the ioctl, we define a new extension
struct that can be linked into the ioctl data only when required by the
user. The key advantage being able to ignore large control structs for
optional interfaces/extensions, while being able to process them in a
consistent manner.

In comparison to other extensible ioctls, the key difference is the
use of a linked chain of extension structs vs an array of tagged
pointers. For example,

struct drm_amdgpu_cs_chunk {
__u32   chunk_id;
__u32   length_dw;
__u64   chunk_data;
};

struct drm_amdgpu_cs_in {
__u32   ctx_id;
__u32   bo_list_handle;
__u32   num_chunks;
__u32   _pad;
__u64   chunks;
};

allows userspace to pass in array of pointers to extension structs, but
must therefore keep constructing that array along side the command stream.
In dynamic situations like that, a linked list is preferred and does not
similar from extra cache line misses as the extension structs themselves
must still be loaded separate to the chunks array.

v2: Apply the tail call optimisation directly to nip the worry of stack
overflow in the bud.

Signed-off-by: Chris Wilson 
---
 drivers/gpu/drm/i915/Makefile   |  1 +
 drivers/gpu/drm/i915/i915_user_extensions.c | 42 +
 drivers/gpu/drm/i915/i915_user_extensions.h | 20 ++
 include/uapi/drm/i915_drm.h | 20 ++
 4 files changed, 83 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.c
 create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 65ed00db..f206fbc85cee 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -45,6 +45,7 @@ i915-y := i915_drv.o \
  i915_sw_fence.o \
  i915_syncmap.o \
  i915_sysfs.o \
+ i915_user_extensions.o \
  intel_csr.o \
  intel_device_info.o \
  intel_pm.o \
diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c 
b/drivers/gpu/drm/i915/i915_user_extensions.c
new file mode 100644
index ..5d90c368f185
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_user_extensions.c
@@ -0,0 +1,42 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#include 
+#include 
+#include 
+
+#include "i915_user_extensions.h"
+
+int i915_user_extensions(struct i915_user_extension __user *ext,
+const i915_user_extension_fn *tbl,
+unsigned long count,
+void *data)
+{
+   while (ext) {
+   int err;
+   u64 x;
+
+   cond_resched();
+   if (signal_pending(current))
+   return -EINTR;
+
+   if (get_user(x, >name))
+   return -EFAULT;
+
+   err = -EINVAL;
+   if (x < count && tbl[x])
+   err = tbl[x](ext, data);
+   if (err)
+   return err;
+
+   if (get_user(x, >next_extension))
+   return -EFAULT;
+
+   ext = u64_to_user_ptr(x);
+   }
+
+   return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_user_extensions.h 
b/drivers/gpu/drm/i915/i915_user_extensions.h
new file mode 100644
index ..313a510b068a
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_user_extensions.h
@@ -0,0 +1,20 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2018 Intel Corporation
+ */
+
+#ifndef I915_USER_EXTENSIONS_H
+#define I915_USER_EXTENSIONS_H
+
+struct i915_user_extension;
+
+typedef int (*i915_user_extension_fn)(struct i915_user_extension __user *ext,
+ void *data);
+
+int i915_user_extensions(struct i915_user_extension __user *ext,
+const i915_user_extension_fn *tbl,
+unsigned long count,
+void *data);
+
+#endif /* I915_USER_EXTENSIONS_H */
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 298b2e197744..6ee2221838da 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -62,6 +62,26 @@ extern "C" {
 #define I915_ERROR_UEVENT  "ERROR"
 #define I915_RESET_UEVENT  "RESET"
 
+/*
+ * i915_user_extension: Base class for defining a chain of extensions
+ *
+ * Many interfaces need to grow over time. In most cases we can simply
+ * extend the struct and have userspace pass in more data. Another option,
+ * as demonstrated by Vulkan's approach to providing extensions for forward
+ * and backward compatibility, is to use a