kern/78179: bus_dmamem_alloc() with BUS_DMA_NOWAIT can block

Peter Jeremy PeterJeremy at optushome.com.au
Sat Nov 19 23:40:34 GMT 2005


The following reply was made to PR kern/78179; it has been noted by GNATS.

From: Peter Jeremy <PeterJeremy at optushome.com.au>
To: Mark Tinguely <tinguely at casselton.net>
Cc: bug-followup at freebsd.org
Subject: Re: kern/78179: bus_dmamem_alloc() with BUS_DMA_NOWAIT can block
Date: Sun, 20 Nov 2005 10:39:09 +1100

 On Thu, 2005-Nov-17 16:04:14 -0600, Mark Tinguely wrote:
 >I took a stab at the problem that NOWAIT is not being honored in
 >contigmalloc() by making the vm_contig_launder_page() honor
 >the flag.
 
 Thank you.  Of course, this doesn't help drivers like bktr(4) that
 use contigmalloc(M_NOWAIT) and panic() if the memory isn't available.
 
 I've gone through your changes and suspect you may have missed a
 few possibilities that can sleep.
 
 >*** vm/vm_contig.c.orig	Thu Nov 17 15:10:10 2005
 >--- vm/vm_contig.c	Thu Nov 17 13:59:47 2005
 >***************
 >*** 95,100 ****
 >--- 95,105 ----
 >  	object = m->object;
 >  	if (!VM_OBJECT_TRYLOCK(object))
 >  		return (EAGAIN);
 >+ 	if (flags & M_NOWAIT && (m->flags & PG_BUSY ||  m->busy)) {
 >+ 		VM_OBJECT_UNLOCK(object);
 >+ 		printf("vm_contig_launder_page: would sleep (busy)\n");
 >+ 		return (EWOULDBLOCK);
 
 I suspect all your EWOULDBLOCK should be EAGAIN for consistency.
 
 >+ 	}
 >  	if (vm_page_sleep_if_busy(m, TRUE, "vpctw0")) {
 >  		VM_OBJECT_UNLOCK(object);
 >  		vm_page_lock_queues();
 >***************
 >*** 104,126 ****
 ...
 >--- 109,149 ----
 >  	if (m->dirty == 0 && m->hold_count == 0)
 >  		pmap_remove_all(m);
 
 This can sleep because it seizes a mutex for each entry.
 
 >  	if (m->dirty) {
 >+ 			/* Both paths use vm_pageout_flush() which forces
 >+ 			 * a syncronous putpage for the kernel_object.
 >+ 			 */
 >+ 		if (flags & M_NOWAIT && object == kernel_object) {
 >+ 			VM_OBJECT_UNLOCK(object);
 >+ 			printf("vm_contig_launder_page: would sleep (kobject)\n");
 >+ 			return (EWOULDBLOCK);
 >+ 		}
 >  		if (object->type == OBJT_VNODE) {
 >  			vm_page_unlock_queues();
 >  			vp = object->handle;
 >  			VM_OBJECT_UNLOCK(object);
 >  			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
 
 vn_lock(9) implies this can sleep unless the 2nd argument includes LK_NOWAIT.
 
 >  			VM_OBJECT_LOCK(object);
 
 This will sleep if something else has grabbed the object mutex.
 
 >! 			vm_object_page_clean(object, 0, 0,
 >! 				(flags & M_NOWAIT) ? 0 :  OBJPC_SYNC);
 >  			VM_OBJECT_UNLOCK(object);
 >  			VOP_UNLOCK(vp, 0, curthread);
 >  			vm_page_lock_queues();
 
 This will sleep if something else is holding vm_page_queue_mtx.
 
 >! 			if ((flags & M_NOWAIT) && m->dirty) {
 >! 				printf("vm_contig_launder_page: would sleep (dirty)\n");
 >! 				return (EWOULDBLOCK);
 >! 			} else
 >! 				return (0);
 >  		} else if (object->type == OBJT_SWAP ||
 >  			   object->type == OBJT_DEFAULT) {
 >  			m_tmp = m;
 >! 			vm_pageout_flush(&m_tmp, 1, 
 >! 				(flags & M_NOWAIT) ? 0 : VM_PAGER_PUT_SYNC);
 >  			VM_OBJECT_UNLOCK(object);
 >! 			if ((flags & M_NOWAIT) && m->dirty) {
 >! 				printf("vm_contig_launder_page: would sleep (dirty)\n");
 >! 				return (EWOULDBLOCK);
 >! 			} else
 >! 				return (0);
 >  		}
 >  	} else if (m->hold_count == 0)
 >  		vm_page_cache(m);
 >***************
 
 -- 
 Peter Jeremy


More information about the freebsd-bugs mailing list