Module Name:    src
Committed By:   riastradh
Date:           Mon Aug 27 14:01:15 UTC 2018

Modified Files:
        src/sys/external/bsd/drm2/include/linux: reservation.h
        src/sys/external/bsd/drm2/linux: linux_reservation.c

Log Message:
Draft reservation_object_get_fences_rcu.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 \
    src/sys/external/bsd/drm2/include/linux/reservation.h
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/linux/linux_reservation.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/include/linux/reservation.h
diff -u src/sys/external/bsd/drm2/include/linux/reservation.h:1.6 src/sys/external/bsd/drm2/include/linux/reservation.h:1.7
--- src/sys/external/bsd/drm2/include/linux/reservation.h:1.6	Mon Aug 27 13:55:46 2018
+++ src/sys/external/bsd/drm2/include/linux/reservation.h	Mon Aug 27 14:01:14 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: reservation.h,v 1.6 2018/08/27 13:55:46 riastradh Exp $	*/
+/*	$NetBSD: reservation.h,v 1.7 2018/08/27 14:01:14 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -58,6 +58,7 @@ struct reservation_object_list {
 #define	reservation_object_add_shared_fence	linux_reservation_object_add_shared_fence
 #define	reservation_object_fini			linux_reservation_object_fini
 #define	reservation_object_get_excl		linux_reservation_object_get_excl
+#define	reservation_object_get_fences_rcu	linux_reservation_object_get_fences_rcu
 #define	reservation_object_get_list		linux_reservation_object_get_list
 #define	reservation_object_held			linux_reservation_object_held
 #define	reservation_object_init			linux_reservation_object_init
@@ -80,6 +81,10 @@ void	reservation_object_add_excl_fence(s
 	    struct fence *);
 void	reservation_object_add_shared_fence(struct reservation_object *,
 	    struct fence *);
+
+int	reservation_object_get_fences_rcu(struct reservation_object *,
+	    struct fence **, unsigned *, struct fence ***);
+
 bool	reservation_object_test_signaled_rcu(struct reservation_object *,
 	    bool);
 long	reservation_object_wait_timeout_rcu(struct reservation_object *,

Index: src/sys/external/bsd/drm2/linux/linux_reservation.c
diff -u src/sys/external/bsd/drm2/linux/linux_reservation.c:1.3 src/sys/external/bsd/drm2/linux/linux_reservation.c:1.4
--- src/sys/external/bsd/drm2/linux/linux_reservation.c:1.3	Mon Aug 27 13:55:46 2018
+++ src/sys/external/bsd/drm2/linux/linux_reservation.c	Mon Aug 27 14:01:14 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_reservation.c,v 1.3 2018/08/27 13:55:46 riastradh Exp $	*/
+/*	$NetBSD: linux_reservation.c,v 1.4 2018/08/27 14:01:14 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.3 2018/08/27 13:55:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.4 2018/08/27 14:01:14 riastradh Exp $");
 
 #include <linux/fence.h>
 #include <linux/reservation.h>
@@ -444,6 +444,130 @@ reservation_object_add_shared_fence(stru
 		fence_put(replace);
 }
 
+int
+reservation_object_get_fences_rcu(struct reservation_object *robj,
+    struct fence **fencep, unsigned *nsharedp, struct fence ***sharedp)
+{
+	struct reservation_object_list *list;
+	struct fence *fence;
+	struct fence **shared = NULL;
+	unsigned shared_alloc, shared_count, i;
+	struct reservation_object_read_ticket ticket;
+
+top:
+	/* Enter an RCU read section and get a read ticket.  */
+	rcu_read_lock();
+	reservation_object_read_begin(robj, &ticket);
+
+	/* If there is a shared list, grab it.  */
+	if ((list = robj->robj_list) != NULL) {
+		/* Make sure the content of the list has been published.  */
+		membar_datadep_consumer();
+
+		/* Check whether we have a buffer.  */
+		if (shared == NULL) {
+			/*
+			 * We don't have a buffer yet.  Try to allocate
+			 * one without waiting.
+			 */
+			shared_alloc = list->shared_max;
+			__insn_barrier();
+			shared = kcalloc(shared_alloc, sizeof(shared[0]),
+			    GFP_NOWAIT);
+			if (shared == NULL) {
+				/*
+				 * Couldn't do it immediately.  Back
+				 * out of RCU and allocate one with
+				 * waiting.
+				 */
+				rcu_read_unlock();
+				shared = kcalloc(shared_alloc,
+				    sizeof(shared[0]), GFP_KERNEL);
+				if (shared == NULL)
+					return -ENOMEM;
+				goto top;
+			}
+		} else if (shared_alloc < list->shared_max) {
+			/*
+			 * We have a buffer but it's too small.  We're
+			 * already racing in this case, so just back
+			 * out and wait to allocate a bigger one.
+			 */
+			shared_alloc = list->shared_max;
+			__insn_barrier();
+			rcu_read_unlock();
+			kfree(shared);
+			shared = kcalloc(shared_alloc, sizeof(shared[0]),
+			    GFP_KERNEL);
+			if (shared == NULL)
+				return -ENOMEM;
+		}
+
+		/*
+		 * We got a buffer large enough.  Copy into the buffer
+		 * and record the number of elements.
+		 */
+		memcpy(shared, list->shared, shared_alloc * sizeof(shared[0]));
+		shared_count = list->shared_count;
+	} else {
+		/* No shared list: shared count is zero.  */
+		shared_count = 0;
+	}
+
+	/* If there is an exclusive fence, grab it.  */
+	if ((fence = robj->robj_fence) != NULL) {
+		/* Make sure the content of the fence has been published.  */
+		membar_datadep_consumer();
+	}
+
+	/*
+	 * We are done reading from robj and list.  Validate our
+	 * parking ticket.  If it's invalid, do not pass go and do not
+	 * collect $200.
+	 */
+	if (!reservation_object_read_valid(robj, &ticket))
+		goto restart;
+
+	/*
+	 * Try to get a reference to the exclusive fence, if there is
+	 * one.  If we can't, start over.
+	 */
+	if (fence) {
+		if (fence_get_rcu(fence) == NULL)
+			goto restart;
+	}
+
+	/*
+	 * Try to get a reference to all of the shared fences.
+	 */
+	for (i = 0; i < shared_count; i++) {
+		if (fence_get_rcu(shared[i]) == NULL)
+			goto put_restart;
+	}
+
+	/* Success!  */
+	rcu_read_unlock();
+	*fencep = fence;
+	*nsharedp = shared_count;
+	*sharedp = shared;
+	return 0;
+
+put_restart:
+	/* Back out.  */
+	while (i --> 0) {
+		fence_put(shared[i]);
+		shared[i] = NULL; /* paranoia */
+	}
+	if (fence) {
+		fence_put(fence);
+		fence = NULL;	/* paranoia */
+	}
+
+restart:
+	rcu_read_unlock();
+	goto top;
+}
+
 /*
  * reservation_object_test_signaled_rcu(robj, shared)
  *

Reply via email to