cvs commit: src/sys/kern syscalls.master vfs_aio.c

David Xu davidxu at freebsd.org
Mon Jan 23 16:16:16 PST 2006


John Baldwin wrote:

>On Sunday 22 January 2006 00:59, David Xu wrote:
>  
>
>>davidxu     2006-01-22 05:59:28 UTC
>>
>>  FreeBSD src repository
>>
>>  Modified files:
>>    sys/kern             syscalls.master vfs_aio.c
>>  Log:
>>  Make aio code MP safe.
>>    
>>
>
>Thanks for doing this.  This is something I had sort of been working on but 
>hadn't gotten too in a while.  (I don't think I had many uncommitted diffs, I 
>think mostly I had just done the fget() and TAILQ_FOREACH_SAFE() cleanups I 
>committed earlier.)  One thing I would appreciate is if you could add some 
>comments explaining the locking strategy and annotating which fields are 
>protected by which locks similar to sys/proc.h, etc.  I've attached my 
>current set of diffs in case you wanted to look at them.
>  
>
I will add locking annotating, in fact, I will do it today,
it is morning here, I have slept, so now I have interest to work
on it again : -)

>  
>
>------------------------------------------------------------------------
>
>--- //depot/projects/smpng/sys/kern/vfs_aio.c	2006/01/17 17:16:05
>+++ //depot/user/jhb/proc/kern/vfs_aio.c	2006/01/17 17:49:55
>@@ -108,6 +108,8 @@
> #define AIOD_LIFETIME_DEFAULT	(30 * hz)
> #endif
> 
>+static int aiod_creation_in_progress;
>+
> static SYSCTL_NODE(_vfs, OID_AUTO, aio, CTLFLAG_RW, 0, "Async IO management");
> 
> static int max_aio_procs = MAX_AIO_PROCS;
>@@ -266,7 +268,7 @@
> static void	aio_onceonly(void);
> static int	aio_free_entry(struct aiocblist *aiocbe);
> static void	aio_process(struct aiocblist *aiocbe);
>-static int	aio_newproc(void);
>+static int	aio_newproc(int always);
> static int	aio_aqueue(struct thread *td, struct aiocb *job, int type,
> 			int osigev);
> static void	aio_physwakeup(struct buf *bp);
>@@ -411,9 +413,17 @@
> 	error = kqueue_del_filteropts(EVFILT_AIO);
> 	if (error)
> 		return error;
>+	error = kqueue_del_filteropts(EVFILT_LIO);
>+	if (error)
>+		return error;
> 
> 	async_io_version = 0;
> 	aio_swake = NULL;
>+	uma_zdestroy(kaio_zone);
>+	uma_zdestroy(aiop_zone);
>+	uma_zdestroy(aiocb_zone);
>+	uma_zdestroy(aiol_zone);
>+	uma_zdestroy(aiolio_zone);
> 	EVENTHANDLER_DEREGISTER(process_exit, exit_tag);
> 	EVENTHANDLER_DEREGISTER(process_exec, exec_tag);
> 	mtx_destroy(&aio_freeproc_mtx);
>@@ -456,8 +466,10 @@
> 		uma_zfree(kaio_zone, ki);
> 	}
> 
>+	mtx_lock(&aio_freeproc_mtx);
> 	while (num_aio_procs < target_aio_procs)
>-		aio_newproc();
>+		aio_newproc(0);
>+	mtx_unlock(&aio_freeproc_mtx);
> }
> 
> static int
>@@ -901,8 +913,6 @@
> 	struct proc *curcp, *mycp, *userp;
> 	struct vmspace *myvm, *tmpvm;
> 	struct thread *td = curthread;
>-	struct pgrp *newpgrp;
>-	struct session *newsess;
> 
> 	/*
> 	 * Local copies of curproc (cp) and vmspace (myvm)
>@@ -918,16 +928,8 @@
> 	 */
> 	aiop = uma_zalloc(aiop_zone, M_WAITOK);
> 	aiop->aiothread = td;
>-	aiop->aiothreadflags |= AIOP_FREE;
> 
> 	/*
>-	 * Place thread (lightweight process) onto the AIO free thread list.
>-	 */
>-	mtx_lock(&aio_freeproc_mtx);
>-	TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list);
>-	mtx_unlock(&aio_freeproc_mtx);
>-
>-	/*
> 	 * Get rid of our current filedescriptors.  AIOD's don't need any
> 	 * filedescriptors, except as temporarily inherited from the client.
> 	 */
>@@ -936,15 +938,16 @@
> 
> 	mtx_unlock(&Giant);
> 	/* The daemon resides in its own pgrp. */
>-	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
>-		M_WAITOK | M_ZERO);
>-	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION,
>-		M_WAITOK | M_ZERO);
>+	setsid(td, NULL);
> 
>-	sx_xlock(&proctree_lock);
>-	enterpgrp(mycp, mycp->p_pid, newpgrp, newsess);
>-	sx_xunlock(&proctree_lock);
>-	mtx_lock(&Giant);
>+	/*
>+	 * Place thread (lightweight process) onto the AIO free thread list.
>+	 */
>+	mtx_lock(&aio_freeproc_mtx);
>+	num_aio_procs++;
>+	aiop->aiothreadflags |= AIOP_FREE;
>+	TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list);
>+	mtx_unlock(&aio_freeproc_mtx);
> 
> 	/*
> 	 * Wakeup parent process.  (Parent sleeps to keep from blasting away
>@@ -952,6 +955,7 @@
> 	 */
> 	wakeup(mycp);
> 
>+	mtx_lock(&aio_freeproc_mtx);
> 	for (;;) {
> 		/*
> 		 * curcp is the current daemon process context.
>@@ -962,7 +966,6 @@
> 		/*
> 		 * Take daemon off of free queue
> 		 */
>-		mtx_lock(&aio_freeproc_mtx);
> 		if (aiop->aiothreadflags & AIOP_FREE) {
> 			TAILQ_REMOVE(&aio_freeproc, aiop, list);
> 			aiop->aiothreadflags &= ~AIOP_FREE;
>@@ -972,6 +975,7 @@
> 		/*
> 		 * Check for jobs.
> 		 */
>+		mtx_lock(&Giant);
> 		while ((aiocbe = aio_selectjob(aiop)) != NULL) {
> 			cb = &aiocbe->uaiocb;
> 			userp = aiocbe->userproc;
>@@ -1054,6 +1058,7 @@
> 
> 			curcp = mycp;
> 		}
>+		mtx_unlock(&Giant);
> 
> 		mtx_lock(&aio_freeproc_mtx);
> 		TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list);
>@@ -1063,18 +1068,17 @@
> 		 * If daemon is inactive for a long time, allow it to exit,
> 		 * thereby freeing resources.
> 		 */
>-		if (msleep(aiop->aiothread, &aio_freeproc_mtx, PDROP | PRIBIO,
>+		if (msleep(aiop->aiothread, &aio_freeproc_mtx, PRIBIO,
> 		    "aiordy", aiod_lifetime)) {
> 			s = splnet();
> 			if (TAILQ_EMPTY(&aio_jobs)) {
>-				mtx_lock(&aio_freeproc_mtx);
> 				if ((aiop->aiothreadflags & AIOP_FREE) &&
> 				    (num_aio_procs > target_aio_procs)) {
> 					TAILQ_REMOVE(&aio_freeproc, aiop, list);
>+					num_aio_procs--;
> 					mtx_unlock(&aio_freeproc_mtx);
> 					splx(s);
> 					uma_zfree(aiop_zone, aiop);
>-					num_aio_procs--;
> #ifdef DIAGNOSTIC
> 					if (mycp->p_vmspace->vm_refcnt <= 1) {
> 						printf("AIOD: bad vm refcnt for"
>@@ -1084,7 +1088,6 @@
> #endif
> 					kthread_exit(0);
> 				}
>-				mtx_unlock(&aio_freeproc_mtx);
> 			}
> 			splx(s);
> 		}
>@@ -1096,24 +1099,36 @@
>  * AIO daemon modifies its environment itself.
>  */
> static int
>-aio_newproc(void)
>+aio_newproc(int always)
> {
>-	int error;
> 	struct proc *p;
>+	int error, n;
> 
>+	mtx_assert(&aio_freeproc_mtx, MA_OWNED);
>+	n = num_aio_procs;
>+	while (aiod_creation_in_progress) {
>+		error = msleep(&aiod_creation_in_progress, &aio_freeproc_mtx,
>+		    PZERO, "aionew", aiod_timeout);
>+		if (error || !always)
>+			return (error);
>+	}
>+	aiod_creation_in_progress = 1;
>+	mtx_unlock(&aio_freeproc_mtx);
>+	
> 	error = kthread_create(aio_daemon, curproc, &p, RFNOWAIT, 0, "aiod%d",
>-	    num_aio_procs);
>-	if (error)
>-		return (error);
>+	    n);
> 
>-	/*
>-	 * Wait until daemon is started, but continue on just in case to
>-	 * handle error conditions.
>-	 */
>-	error = tsleep(p, PZERO, "aiosta", aiod_timeout);
>+	mtx_lock(&aio_freeproc_mtx);
>+	if (error == 0)
>+		/*
>+		 * Wait until daemon is started, but continue on just in
>+		 * case to handle error conditions.
>+		 */
>+		error = msleep(p, &aio_freeproc_mtx, PZERO, "aiosta",
>+		    aiod_timeout);
> 
>-	num_aio_procs++;
>-
>+	aiod_creation_in_progress = 0;
>+	wakeup(&aiod_creation_in_progress);
> 	return (error);
> }
> 
>@@ -1597,9 +1612,7 @@
> 	    ((ki->kaio_active_count + num_aio_resv_start) <
> 	    ki->kaio_maxactive_count)) {
> 		num_aio_resv_start++;
>-		mtx_unlock(&aio_freeproc_mtx);ing
>-		error = aio_newproc();
>-		mtx_lock(&aio_freeproc_mtx);
>+		error = aio_newproc(1);
> 		num_aio_resv_start--;
> 		if (error)
> 			goto retryproc;
>  
>
I will check my code to see if I missed something and will integrate
your code if it is needed.
Thank you!



More information about the cvs-all mailing list