Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Feb 2010 11:49:32 -0800
From:      "Matthew Fleming" <matthew.fleming@isilon.com>
To:        <freebsd-current@freebsd.org>
Subject:   [PATCH] Fix LOR #185
Message-ID:  <06D5F9F6F655AD4C92E28B662F7F853E0366328E@seaxch09.desktop.isilon.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
We've seen LOR #185 on http://sources.zabbadoz.net/freebsd/lor.html
locally on and off since October 2007.  This patch has been compiled but
I don't have a reliable way to repro the LOR so it's not been properly
tested.

If someone who has seen this LOR can confirm the patch fixes it, and
could commit, that would be nice.

Thanks,
matthew

[-- Attachment #2 --]
Index: kern_event.c
===================================================================
--- kern_event.c	(revision 140805)
+++ kern_event.c	(working copy)
@@ -1094,82 +1094,86 @@ kqueue_schedtask(struct kqueue *kq)
 
 /*
  * Expand the kq to make sure we have storage for fops/ident pair.
  *
  * Return 0 on success (or no work necessary), return errno on failure.
  *
  * Not calling hashinit w/ waitok (proper malloc flag) should be safe.
  * If kqueue_register is called from a non-fd context, there usually/should
  * be no locks held.
  */
 static int
 kqueue_expand(struct kqueue *kq, struct filterops *fops, uintptr_t ident,
 	int waitok)
 {
 	struct klist *list, *tmp_knhash;
+	struct klist *to_free = NULL;
 	u_long tmp_knhashmask;
 	int size;
 	int fd;
 	int mflag = waitok ? M_WAITOK : M_NOWAIT;
 
 	KQ_NOTOWNED(kq);
 
 	if (fops->f_isfd) {
 		fd = ident;
 		if (kq->kq_knlistsize <= fd) {
 			size = kq->kq_knlistsize;
 			while (size <= fd)
 				size += KQEXTENT;
 			list = malloc(size * sizeof(*list), M_KQUEUE, mflag);
 			if (list == NULL)
 				return ENOMEM;
 			KQ_LOCK(kq);
 			if (kq->kq_knlistsize > fd) {
-				free(list, M_KQUEUE);
+				to_free = list;
 				list = NULL;
 			} else {
 				if (kq->kq_knlist != NULL) {
 					bcopy(kq->kq_knlist, list,
 					    kq->kq_knlistsize * sizeof list);
-					free(kq->kq_knlist, M_KQUEUE);
+					to_free = kq->kq_knlist;
 					kq->kq_knlist = NULL;
 				}
 				bzero((caddr_t)list +
 				    kq->kq_knlistsize * sizeof list,
 				    (size - kq->kq_knlistsize) * sizeof list);
 				kq->kq_knlistsize = size;
 				kq->kq_knlist = list;
 			}
 			KQ_UNLOCK(kq);
 		}
 	} else {
 		if (kq->kq_knhashmask == 0) {
 			tmp_knhash = hashinit(KN_HASHSIZE, M_KQUEUE,
 			    &tmp_knhashmask);
 			if (tmp_knhash == NULL)
 				return ENOMEM;
 			KQ_LOCK(kq);
 			if (kq->kq_knhashmask == 0) {
 				kq->kq_knhash = tmp_knhash;
 				kq->kq_knhashmask = tmp_knhashmask;
 			} else {
-				free(tmp_knhash, M_KQUEUE);
+				to_free = tmp_knhash;
 			}
 			KQ_UNLOCK(kq);
 		}
 	}
 
+	if (to_free != NULL)
+		free(to_free, M_KQUEUE);
+
 	KQ_NOTOWNED(kq);
 	return 0;
 }
 
 static void
 kqueue_task(void *arg, int pending)
 {
 	struct kqueue *kq;
 	int haskqglobal;
 
 	haskqglobal = 0;
 	kq = arg;
 
 	KQ_GLOBAL_LOCK(&kq_global, haskqglobal);
 	KQ_LOCK(kq);

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?06D5F9F6F655AD4C92E28B662F7F853E0366328E>