Backport of fix from asynchvfs branch for PM-LOG-VFS-PM deadlock that resulted in VFS panics.
This commit is contained in:
		
							parent
							
								
									39aa2e6489
								
							
						
					
					
						commit
						f73b541952
					
				@ -18,7 +18,7 @@ LDFLAGS = -i
 | 
			
		||||
 | 
			
		||||
OBJ = 	main.o forkexit.o break.o exec.o time.o timers.o \
 | 
			
		||||
	signal.o alloc.o utility.o table.o trace.o getset.o misc.o \
 | 
			
		||||
	profile.o
 | 
			
		||||
	profile.o asynsend.o kputc.o
 | 
			
		||||
 | 
			
		||||
# build local binary
 | 
			
		||||
all build:	$(SERVER)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										90
									
								
								servers/pm/asynsend.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								servers/pm/asynsend.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
 | 
			
		||||
#include "pm.h"
 | 
			
		||||
 | 
			
		||||
#define ASYN_NR	100
 | 
			
		||||
PRIVATE asynmsg_t msgtable[ASYN_NR];
 | 
			
		||||
PRIVATE int first_slot= 0, next_slot= 0;
 | 
			
		||||
 | 
			
		||||
PUBLIC int asynsend(dst, mp)
 | 
			
		||||
endpoint_t dst;
 | 
			
		||||
message *mp;
 | 
			
		||||
{
 | 
			
		||||
	int r, src_ind, dst_ind;
 | 
			
		||||
	unsigned flags;
 | 
			
		||||
 | 
			
		||||
	/* Update first_slot */
 | 
			
		||||
	for (; first_slot < next_slot; first_slot++)
 | 
			
		||||
	{
 | 
			
		||||
		flags= msgtable[first_slot].flags;
 | 
			
		||||
		if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
 | 
			
		||||
		{
 | 
			
		||||
			if (msgtable[first_slot].result != OK)
 | 
			
		||||
			{
 | 
			
		||||
				printf(
 | 
			
		||||
			"asynsend: found completed entry %d with error %d\n",
 | 
			
		||||
					first_slot,
 | 
			
		||||
					msgtable[first_slot].result);
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (flags != AMF_EMPTY)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (first_slot >= next_slot)
 | 
			
		||||
	{
 | 
			
		||||
		/* Reset first_slot and next_slot */
 | 
			
		||||
		next_slot= first_slot= 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (next_slot >= ASYN_NR)
 | 
			
		||||
	{
 | 
			
		||||
		/* Tell the kernel to stop processing */
 | 
			
		||||
		r= senda(NULL, 0);
 | 
			
		||||
		if (r != OK)
 | 
			
		||||
			panic(__FILE__, "asynsend: senda failed", r);
 | 
			
		||||
 | 
			
		||||
		dst_ind= 0;
 | 
			
		||||
		for (src_ind= first_slot; src_ind<next_slot; src_ind++)
 | 
			
		||||
		{
 | 
			
		||||
			flags= msgtable[src_ind].flags;
 | 
			
		||||
			if ((flags & (AMF_VALID|AMF_DONE)) ==
 | 
			
		||||
				(AMF_VALID|AMF_DONE))
 | 
			
		||||
			{
 | 
			
		||||
				if (msgtable[src_ind].result != OK)
 | 
			
		||||
				{
 | 
			
		||||
					printf(
 | 
			
		||||
			"asynsend: found completed entry %d with error %d\n",
 | 
			
		||||
						src_ind,
 | 
			
		||||
						msgtable[src_ind].result);
 | 
			
		||||
				}
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (flags == AMF_EMPTY)
 | 
			
		||||
				continue;
 | 
			
		||||
#if 0
 | 
			
		||||
			printf("asynsend: copying entry %d to %d\n",
 | 
			
		||||
				src_ind, dst_ind);
 | 
			
		||||
#endif
 | 
			
		||||
			if (src_ind != dst_ind)
 | 
			
		||||
				msgtable[dst_ind]= msgtable[src_ind];
 | 
			
		||||
			dst_ind++;
 | 
			
		||||
		}
 | 
			
		||||
		first_slot= 0;
 | 
			
		||||
		next_slot= dst_ind;
 | 
			
		||||
		if (next_slot >= ASYN_NR)
 | 
			
		||||
			panic(__FILE__, "asynsend: msgtable full", NO_NUM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgtable[next_slot].dst= dst;
 | 
			
		||||
	msgtable[next_slot].msg= *mp;
 | 
			
		||||
	msgtable[next_slot].flags= AMF_VALID;	/* Has to be last. The kernel 
 | 
			
		||||
					 	 * scans this table while we
 | 
			
		||||
						 * are sleeping.
 | 
			
		||||
					 	 */
 | 
			
		||||
	next_slot++;
 | 
			
		||||
 | 
			
		||||
	/* Tell the kernel to rescan the table */
 | 
			
		||||
	return senda(msgtable+first_slot, next_slot-first_slot);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										149
									
								
								servers/pm/kputc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								servers/pm/kputc.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
			
		||||
/* A server must occasionally print some message.  It uses a simple version of 
 | 
			
		||||
 * printf() found in the system lib that calls kputc() to output characters.
 | 
			
		||||
 * Printing is done with a call to the kernel, and not by going through FS.
 | 
			
		||||
 *
 | 
			
		||||
 * This routine can only be used by servers and device drivers.  The kernel
 | 
			
		||||
 * must define its own kputc(). Note that the log driver also defines its own 
 | 
			
		||||
 * kputc() to directly call the TTY instead of going through this library.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "pm.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <minix/com.h>
 | 
			
		||||
 | 
			
		||||
#define OVERFLOW_STR "[...]\n"
 | 
			
		||||
 | 
			
		||||
#define PRINTPROCS (sizeof(procs)/sizeof(procs[0]))
 | 
			
		||||
 | 
			
		||||
static char print_buf[80];	/* output is buffered here */
 | 
			
		||||
 | 
			
		||||
int kputc_use_private_grants= 0;
 | 
			
		||||
 | 
			
		||||
static int buf_count = 0;	/* # characters in the buffer */
 | 
			
		||||
static int buf_offset = 0;	/* Start of current line in buffer */
 | 
			
		||||
static int procs[] = OUTPUT_PROCS_ARRAY;
 | 
			
		||||
static cp_grant_id_t printgrants[PRINTPROCS];
 | 
			
		||||
static int procbusy[PRINTPROCS];
 | 
			
		||||
static int do_flush = FALSE;
 | 
			
		||||
static int overflow = FALSE;
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				kputc					     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void kputc(c)
 | 
			
		||||
int c;
 | 
			
		||||
{
 | 
			
		||||
/* Accumulate another character.  If 0 or buffer full, print it. */
 | 
			
		||||
  int p;
 | 
			
		||||
  message m;
 | 
			
		||||
 | 
			
		||||
  static int firstprint = 1;
 | 
			
		||||
 | 
			
		||||
  if (c == 0)
 | 
			
		||||
  {
 | 
			
		||||
	if (buf_count > buf_offset)
 | 
			
		||||
		do_flush= TRUE;
 | 
			
		||||
  }
 | 
			
		||||
  else if (buf_count >= sizeof(print_buf))
 | 
			
		||||
  {
 | 
			
		||||
	overflow= TRUE;
 | 
			
		||||
	if (buf_count > buf_offset)
 | 
			
		||||
		do_flush= TRUE;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  	print_buf[buf_count++] = c;
 | 
			
		||||
 | 
			
		||||
  if (!do_flush || buf_offset != 0)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
	buf_offset= buf_count;
 | 
			
		||||
	if (kputc_use_private_grants)
 | 
			
		||||
	{
 | 
			
		||||
		for (p= 0; p<PRINTPROCS; p++)
 | 
			
		||||
			printgrants[p]= GRANT_INVALID;
 | 
			
		||||
		firstprint= 0;
 | 
			
		||||
	}
 | 
			
		||||
	if(firstprint) {
 | 
			
		||||
		for(p = 0; procs[p] != NONE; p++) {
 | 
			
		||||
			printgrants[p] = GRANT_INVALID;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		firstprint = 0;
 | 
			
		||||
 | 
			
		||||
		/* First time? Initialize grant table;
 | 
			
		||||
		 * Grant printing processes read copy access to our
 | 
			
		||||
		 * print buffer forever. (So buffer can't be on stack!)
 | 
			
		||||
		 */
 | 
			
		||||
		for(p = 0; procs[p] != NONE; p++) {
 | 
			
		||||
			printgrants[p] = cpf_grant_direct(procs[p],
 | 
			
		||||
				(vir_bytes) print_buf,
 | 
			
		||||
				sizeof(print_buf), CPF_READ);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do_flush= FALSE;
 | 
			
		||||
	for(p = 0; procs[p] != NONE; p++) {
 | 
			
		||||
		/* Send the buffer to this output driver. */
 | 
			
		||||
		m.DIAG_BUF_COUNT = buf_count;
 | 
			
		||||
		if(GRANT_VALID(printgrants[p])) {
 | 
			
		||||
			m.m_type = DIAGNOSTICS_S;
 | 
			
		||||
			m.DIAG_PRINT_BUF_G = (char *) printgrants[p];
 | 
			
		||||
		} else {
 | 
			
		||||
			m.m_type = DIAGNOSTICS;
 | 
			
		||||
			m.DIAG_PRINT_BUF_G = print_buf;
 | 
			
		||||
		}
 | 
			
		||||
		if (procs[p] == LOG_PROC_NR)
 | 
			
		||||
		{
 | 
			
		||||
			procbusy[p]= TRUE;
 | 
			
		||||
			(void) asynsend(procs[p], &m);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			sendrec(procs[p], &m);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void diag_repl()
 | 
			
		||||
{
 | 
			
		||||
	endpoint_t driver_e;
 | 
			
		||||
	int p;
 | 
			
		||||
 | 
			
		||||
	driver_e= m_in.m_source;
 | 
			
		||||
 | 
			
		||||
	/* Find busy flag to clear */
 | 
			
		||||
	for(p = 0; procs[p] != NONE; p++)
 | 
			
		||||
	{
 | 
			
		||||
		if (procs[p] == driver_e)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if (procs[p] == NONE)
 | 
			
		||||
	{
 | 
			
		||||
		/* Message from wrong source */
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	procbusy[p]= FALSE;
 | 
			
		||||
 | 
			
		||||
	/* Wait for more replies? */
 | 
			
		||||
	for(p = 0; procs[p] != NONE; p++)
 | 
			
		||||
	{
 | 
			
		||||
		if (procbusy[p])
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
	if (buf_count > buf_offset)
 | 
			
		||||
	{
 | 
			
		||||
		memmove(&print_buf[0], &print_buf[buf_offset], 
 | 
			
		||||
			buf_count-buf_offset);
 | 
			
		||||
	}
 | 
			
		||||
	buf_count -= buf_offset;
 | 
			
		||||
	buf_offset= 0;
 | 
			
		||||
	if (overflow)
 | 
			
		||||
	{
 | 
			
		||||
		if (buf_count + sizeof(OVERFLOW_STR) > sizeof(print_buf))
 | 
			
		||||
			buf_count= sizeof(print_buf)-sizeof(OVERFLOW_STR);
 | 
			
		||||
		overflow= FALSE;
 | 
			
		||||
		do_flush= FALSE;
 | 
			
		||||
		printf("%s", OVERFLOW_STR);
 | 
			
		||||
	}
 | 
			
		||||
	kputc(0);
 | 
			
		||||
}
 | 
			
		||||
@ -124,6 +124,10 @@ PUBLIC int main()
 | 
			
		||||
	case GETPUID:
 | 
			
		||||
		result= do_getpuid();
 | 
			
		||||
		break;
 | 
			
		||||
	case DIAG_REPL :
 | 
			
		||||
		diag_repl();
 | 
			
		||||
		result= SUSPEND;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		/* Else, if the system call number is valid, perform the
 | 
			
		||||
		 * call.
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,9 @@ _PROTOTYPE( void swap_inqueue, (struct mproc *rmp)			);
 | 
			
		||||
#endif /* !SWAP */
 | 
			
		||||
_PROTOTYPE(int mem_holes_copy, (struct hole *, size_t *, u32_t *)	);
 | 
			
		||||
 | 
			
		||||
/* asynsend.c */
 | 
			
		||||
_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp)			);
 | 
			
		||||
 | 
			
		||||
/* break.c */
 | 
			
		||||
_PROTOTYPE( int adjust, (struct mproc *rmp,
 | 
			
		||||
			vir_clicks data_clicks, vir_bytes sp)		);
 | 
			
		||||
@ -63,6 +66,9 @@ _PROTOTYPE( void real_cleanup, (struct mproc *rmp)			);
 | 
			
		||||
/* getset.c */
 | 
			
		||||
_PROTOTYPE( int do_getset, (void)					);
 | 
			
		||||
 | 
			
		||||
/* kputc.c */
 | 
			
		||||
_PROTOTYPE( void diag_repl, (void)					);
 | 
			
		||||
 | 
			
		||||
/* main.c */
 | 
			
		||||
_PROTOTYPE( int main, (void)						);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user