All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] ring.h: introduce macros to handle monodirectional rings with multiple req sizes
@ 2017-02-21  1:32 Stefano Stabellini
  2017-02-21  9:21 ` Jan Beulich
  0 siblings, 1 reply; 3+ messages in thread
From: Stefano Stabellini @ 2017-02-21  1:32 UTC (permalink / raw)
  To: xen-devel
  Cc: sstabellini, oleksandr_andrushchenko, andr2000, andrii.anisov,
	Stefano Stabellini, vlad.babchuk, al1img, JBeulich, joculator

This patch introduces macros, structs and functions to handle rings in
the format described by docs/misc/pvcalls.markdown and
docs/misc/9pfs.markdown. The index page (struct __name##_data_intf)
contains the indexes and the grant refs to setup two rings.

               Indexes page
               +----------------------+
               |@0 $NAME_data_intf:   |
               |@76: ring_order = 1   |
               |@80: ref[0]+          |
               |@84: ref[1]+          |
               |           |          |
               |           |          |
               +----------------------+
                           |
                           v (data ring)
                   +-------+-----------+
                   |  @0->4098: in     |
                   |  ref[0]           |
                   |-------------------|
                   |  @4099->8196: out |
                   |  ref[1]           |
                   +-------------------+

$NAME_read_packet and $NAME_write_packet are provided to read or write
any data struct from/to the ring. In pvcalls, they are unused. In xen
9pfs, they are used to read or write the 9pfs header. In other protocols
they could be used to read/write the whole request structure. See
docs/misc/9pfs.markdown:Ring Usage to learn how to check how much data
is on the ring, and how to handle notifications.

There is a ring_size parameter to most functions so that protocols using
these macros don't have to have a statically defined ring order at build
time. In pvcalls for example, each new ring could have a different
order.

These macros don't help you share the indexes page or the event channels
needed for notifications. You can do that with other out of band
mechanisms, such as xenstore or another ring.

Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
CC: konrad.wilk@oracle.com
CC: andr2000@gmail.com
CC: oleksandr_andrushchenko@epam.com
CC: andrii.anisov@gmail.com
CC: vlad.babchuk@gmail.com
CC: al1img@gmail.com
CC: joculator@gmail.com
CC: JBeulich@suse.com

---
Changes in v2:
- fix typo
- remove leading underscores from names
- use UL
- do not parenthesize parameters
- code readability improvements

Give a look at the following branch to see how they are used with
pvcalls and xen-9pfs (the drivers are still work in progress):

git://git.kernel.org/pub/scm/linux/kernel/git/sstabellini/xen.git 9pfs-async-v5
---
 xen/include/public/io/ring.h | 114 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h
index 801c0da..381be70 100644
--- a/xen/include/public/io/ring.h
+++ b/xen/include/public/io/ring.h
@@ -313,6 +313,120 @@ typedef struct __name##_back_ring __name##_back_ring_t
     (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                  \
 } while (0)
 
+
+/*
+ * DEFINE_XEN_FLEX_RING defines two monodirectional rings and functions
+ * to check if there is data on the ring, and to read and write to them.
+ *
+ * XEN_FLEX_RING_SIZE
+ *   Convenience macro to calculate the size of one of the two rings
+ *   from the overall order.
+ *
+ * $NAME_mask
+ *   Function to apply the size mask to an index, to reduce the index
+ *   within the range [0-size].
+ *
+ * $NAME_read_packet
+ *   Function to read a defined amount of data from the ring. The amount
+ *   of data read is sizeof(__packet_t).
+ *
+ * $NAME_write_packet
+ *   Function to write a defined amount of data to the ring. The amount
+ *   of data to write is sizeof(__packet_t).
+ *
+ * $NAME_data_intf
+ *   Indexes page, shared between frontend and backend. It also
+ *   contains the array of grant refs. Different protocols can have
+ *   extensions to the basic format, in such cases please define your
+ *   own data_intf struct.
+ *
+ * $NAME_queued
+ *   Function to calculate how many bytes are currently on the ring,
+ *   ready to be read. It can also be used to calculate how much free
+ *   space is currently on the ring (ring_size - $NAME_queued()).
+ */
+#define XEN_FLEX_RING_SIZE(order)                                             \
+    (1UL << (order + PAGE_SHIFT - 1))
+
+#define DEFINE_XEN_FLEX_RING(name, packet_t)                                  \
+                                                                              \
+static inline RING_IDX name##_mask(RING_IDX idx, RING_IDX ring_size)          \
+{                                                                             \
+    return (idx & (ring_size - 1));                                           \
+}                                                                             \
+                                                                              \
+static inline RING_IDX name##_mask_order(RING_IDX idx, RING_IDX ring_order)   \
+{                                                                             \
+    return (idx & (XEN_FLEX_RING_SIZE(ring_order) - 1));                      \
+}                                                                             \
+                                                                              \
+static inline void name##_read_packet(char *buf,                              \
+        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \
+        RING_IDX ring_size, packet_t *h) {                                    \
+    if (*masked_cons < *masked_prod ||                                        \
+            sizeof(*h) <= ring_size - *masked_cons) {                         \
+        memcpy(h, buf + *masked_cons, sizeof(*h));                            \
+    } else {                                                                  \
+        memcpy(h, buf + *masked_cons, ring_size - *masked_cons);              \
+        memcpy((char *)h + ring_size - *masked_cons, buf,                     \
+                sizeof(*h) - (ring_size - *masked_cons));                     \
+    }                                                                         \
+    *masked_cons = name##_mask(*masked_cons + sizeof(*h), ring_size);         \
+}                                                                             \
+                                                                              \
+static inline void name##_write_packet(char *buf,                             \
+        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \
+        RING_IDX ring_size, packet_t *h) {                                    \
+    if (*masked_prod < *masked_cons ||                                        \
+        sizeof(*h) <= ring_size - *masked_prod) {                             \
+        memcpy(buf + *masked_prod, h, sizeof(*h));                            \
+    } else {                                                                  \
+        memcpy(buf + *masked_prod, h, ring_size - *masked_prod);              \
+        memcpy(buf, (char *)h + (ring_size - *masked_prod),                   \
+                sizeof(*h) - (ring_size - *masked_prod));                     \
+    }                                                                         \
+    *masked_prod = name##_mask(*masked_prod + sizeof(*h), ring_size);         \
+}                                                                             \
+                                                                              \
+struct name##_data {                                                          \
+    unsigned char *in; /* half of the allocation */                           \
+    unsigned char *out; /* half of the allocation */                          \
+};                                                                            \
+                                                                              \
+struct name##_data_intf {                                                     \
+    RING_IDX in_cons, in_prod;                                                \
+                                                                              \
+    uint8_t pad1[56];                                                         \
+                                                                              \
+    RING_IDX out_cons, out_prod;                                              \
+                                                                              \
+    uint8_t pad2[56];                                                         \
+                                                                              \
+    RING_IDX ring_order;                                                      \
+    grant_ref_t ref[];                                                        \
+};                                                                            \
+                                                                              \
+static inline RING_IDX name##_queued(RING_IDX prod,                           \
+        RING_IDX cons, RING_IDX ring_size)                                    \
+{                                                                             \
+    RING_IDX size;                                                            \
+                                                                              \
+    if (prod == cons)                                                         \
+        return 0;                                                             \
+                                                                              \
+    prod = name##_mask(prod, ring_size);                                      \
+    cons = name##_mask(cons, ring_size);                                      \
+                                                                              \
+    if (prod == cons)                                                         \
+        return ring_size;                                                     \
+                                                                              \
+    if (prod > cons)                                                          \
+        size = prod - cons;                                                   \
+    else                                                                      \
+        size = ring_size - (cons - prod);                                     \
+    return size;                                                              \
+};
+
 #endif /* __XEN_PUBLIC_IO_RING_H__ */
 
 /*
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] ring.h: introduce macros to handle monodirectional rings with multiple req sizes
  2017-02-21  1:32 [PATCH v2] ring.h: introduce macros to handle monodirectional rings with multiple req sizes Stefano Stabellini
@ 2017-02-21  9:21 ` Jan Beulich
  2017-02-21 23:24   ` Stefano Stabellini
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Beulich @ 2017-02-21  9:21 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: oleksandr_andrushchenko, andr2000, andrii.anisov,
	Stefano Stabellini, vlad.babchuk, al1img, xen-devel, joculator

>>> On 21.02.17 at 02:32, <sstabellini@kernel.org> wrote:
> +static inline void name##_read_packet(char *buf,                              \
> +        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \

The const/indirection problems is still there.

> +static inline void name##_write_packet(char *buf,                             \
> +        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \
> +        RING_IDX ring_size, packet_t *h) {                                    \

Same here - it being a pointer now, the last parameter should then
be a pointer to const (and you shouldn't cast away constness below).

> +struct name##_data_intf {                                                     \
> +    RING_IDX in_cons, in_prod;                                                \
> +                                                                              \
> +    uint8_t pad1[56];                                                         \
> +                                                                              \
> +    RING_IDX out_cons, out_prod;                                              \
> +                                                                              \
> +    uint8_t pad2[56];                                                         \
> +                                                                              \
> +    RING_IDX ring_order;                                                      \
> +    grant_ref_t ref[];                                                        \
> +};                                                                          

The use of a variable sized array here should also be mentioned as
an exception from the C89-compatibility rule in the description.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] ring.h: introduce macros to handle monodirectional rings with multiple req sizes
  2017-02-21  9:21 ` Jan Beulich
@ 2017-02-21 23:24   ` Stefano Stabellini
  0 siblings, 0 replies; 3+ messages in thread
From: Stefano Stabellini @ 2017-02-21 23:24 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, oleksandr_andrushchenko, andr2000,
	andrii.anisov, Stefano Stabellini, vlad.babchuk, al1img,
	xen-devel, joculator

On Tue, 21 Feb 2017, Jan Beulich wrote:
> >>> On 21.02.17 at 02:32, <sstabellini@kernel.org> wrote:
> > +static inline void name##_read_packet(char *buf,                              \
> > +        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \
> 
> The const/indirection problems is still there.

I'll fix


> > +static inline void name##_write_packet(char *buf,                             \
> > +        RING_IDX *masked_prod, RING_IDX *masked_cons,                         \
> > +        RING_IDX ring_size, packet_t *h) {                                    \
> 
> Same here - it being a pointer now, the last parameter should then
> be a pointer to const (and you shouldn't cast away constness below).

OK


> > +struct name##_data_intf {                                                     \
> > +    RING_IDX in_cons, in_prod;                                                \
> > +                                                                              \
> > +    uint8_t pad1[56];                                                         \
> > +                                                                              \
> > +    RING_IDX out_cons, out_prod;                                              \
> > +                                                                              \
> > +    uint8_t pad2[56];                                                         \
> > +                                                                              \
> > +    RING_IDX ring_order;                                                      \
> > +    grant_ref_t ref[];                                                        \
> > +};                                                                          
> 
> The use of a variable sized array here should also be mentioned as
> an exception from the C89-compatibility rule in the description.
 
Makes sense

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-02-21 23:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-21  1:32 [PATCH v2] ring.h: introduce macros to handle monodirectional rings with multiple req sizes Stefano Stabellini
2017-02-21  9:21 ` Jan Beulich
2017-02-21 23:24   ` Stefano Stabellini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.