make unpause() decrease susp_count, as it shouldn't be decreased
if the process was REVIVING. (susp_count doesn't count those processes.) this together with dev_io SELECT suspend side effect for asynch. character devices solves the hanging pipe bug. or at last vastly improves it. added sanity checks, turned off by default. made the {NOT_,}{SUSPENDING,REVIVING} constants weirder to help sanity checking.
This commit is contained in:
parent
113b1ec5f3
commit
dc1238b7b9
9 changed files with 123 additions and 59 deletions
|
@ -25,8 +25,8 @@ EXTERN struct fproc {
|
|||
char *fp_buffer; /* place to save buffer if rd/wr can't finish*/
|
||||
int fp_nbytes; /* place to save bytes if rd/wr can't finish */
|
||||
int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */
|
||||
char fp_suspended; /* set to indicate process hanging */
|
||||
char fp_revived; /* set to indicate process being revived */
|
||||
int fp_suspended; /* set to indicate process hanging */
|
||||
int fp_revived; /* set to indicate process being revived */
|
||||
int fp_task; /* which task is proc suspended on */
|
||||
|
||||
endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */
|
||||
|
@ -47,10 +47,12 @@ EXTERN struct fproc {
|
|||
*/
|
||||
|
||||
/* Field values. */
|
||||
#define NOT_SUSPENDED 0 /* process is not suspended on pipe or task */
|
||||
#define SUSPENDED 1 /* process is suspended on pipe or task */
|
||||
#define NOT_REVIVING 0 /* process is not being revived */
|
||||
#define REVIVING 1 /* process is being revived from suspension */
|
||||
/* fp_suspended is one of these. */
|
||||
#define NOT_SUSPENDED 0xC0FFEE /* process is not suspended on pipe or task */
|
||||
#define SUSPENDED 0xDEAD /* process is suspended on pipe or task */
|
||||
|
||||
#define NOT_REVIVING 0xC0FFEEE /* process is not being revived */
|
||||
#define REVIVING 0xDEEAD /* process is being revived from suspension */
|
||||
#define PID_FREE 0 /* process slot free */
|
||||
|
||||
/* Check is process number is acceptable - includes system processes. */
|
||||
|
|
|
@ -5,7 +5,19 @@
|
|||
#define _MINIX 1 /* tell headers to include MINIX stuff */
|
||||
#define _SYSTEM 1 /* tell headers that this is the kernel */
|
||||
|
||||
#define VERBOSE 0 /* show messages during initialization? */
|
||||
#define DO_SANITYCHECKS 0
|
||||
|
||||
#if DO_SANITYCHECKS
|
||||
#define SANITYCHECK do { \
|
||||
if(!check_vrefs() || !check_pipe()) { \
|
||||
printf("VFS:%s:%d: call_nr %d who_e %d\n", \
|
||||
__FILE__, __LINE__, call_nr, who_e); \
|
||||
panic(__FILE__, "sanity check failed", NO_NUM); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define SANITYCHECK
|
||||
#endif
|
||||
|
||||
/* The following are so basic, all the *.c files get them automatically. */
|
||||
#include <minix/config.h> /* MUST be first */
|
||||
|
|
|
@ -57,8 +57,11 @@ PUBLIC int main()
|
|||
|
||||
fs_init();
|
||||
|
||||
SANITYCHECK;
|
||||
|
||||
/* This is the main loop that gets work, processes it, and sends replies. */
|
||||
while (TRUE) {
|
||||
SANITYCHECK;
|
||||
get_work(); /* sets who and call_nr */
|
||||
|
||||
if (who_e == PM_PROC_NR && call_nr != PROC_EVENT)
|
||||
|
@ -121,14 +124,7 @@ PUBLIC int main()
|
|||
/* Device notifies us of an event. */
|
||||
dev_status(&m_in);
|
||||
}
|
||||
#if 0
|
||||
if (!check_vrefs())
|
||||
{
|
||||
printf("after call %d from %d/%d\n",
|
||||
call_nr, who_p, who_e);
|
||||
panic(__FILE__, "check_vrefs failed at line", __LINE__);
|
||||
}
|
||||
#endif
|
||||
SANITYCHECK;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -143,6 +139,14 @@ PUBLIC int main()
|
|||
fp = &fproc[who_p]; /* pointer to proc table struct */
|
||||
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
|
||||
|
||||
#if DO_SANITYCHECKS
|
||||
if(fp->fp_suspended != NOT_SUSPENDED) {
|
||||
printf("VFS: requester %d call %d: not not suspended\n",
|
||||
who_e, call_nr);
|
||||
panic(__FILE__, "requester suspended", NO_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calls from VM. */
|
||||
if(who_e == VM_PROC_NR) {
|
||||
int caught = 1;
|
||||
|
@ -167,6 +171,8 @@ PUBLIC int main()
|
|||
}
|
||||
}
|
||||
|
||||
SANITYCHECK;
|
||||
|
||||
/* Other calls. */
|
||||
switch(call_nr)
|
||||
{
|
||||
|
@ -196,21 +202,15 @@ PUBLIC int main()
|
|||
#if ENABLE_SYSCALL_STATS
|
||||
calls_stats[call_nr]++;
|
||||
#endif
|
||||
SANITYCHECK;
|
||||
error = (*call_vec[call_nr])();
|
||||
SANITYCHECK;
|
||||
}
|
||||
|
||||
/* Copy the results back to the user and send reply. */
|
||||
if (error != SUSPEND) { reply(who_e, error); }
|
||||
}
|
||||
#if 0
|
||||
if (!check_vrefs())
|
||||
{
|
||||
printf("after call %d from %d/%d\n", call_nr, who_p, who_e);
|
||||
panic(__FILE__, "check_vrefs failed at line", __LINE__);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
SANITYCHECK;
|
||||
}
|
||||
return(OK); /* shouldn't come here */
|
||||
}
|
||||
|
@ -352,6 +352,8 @@ PRIVATE void fs_init()
|
|||
rfp->fp_effgid = (gid_t) SYS_GID;
|
||||
rfp->fp_umask = ~0;
|
||||
rfp->fp_grant = GRANT_INVALID;
|
||||
rfp->fp_suspended = NOT_SUSPENDED;
|
||||
rfp->fp_revived = NOT_REVIVING;
|
||||
|
||||
} while (TRUE); /* continue until process NONE */
|
||||
mess.m_type = OK; /* tell PM that we succeeded */
|
||||
|
|
|
@ -312,12 +312,12 @@ void unmount_all(void)
|
|||
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
|
||||
if (vmp->m_dev != NO_DEV) {
|
||||
found++;
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
if(unmount(vmp->m_dev) == OK)
|
||||
worked++;
|
||||
else
|
||||
remain++;
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ PUBLIC void pm_reboot()
|
|||
|
||||
do_sync();
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Do exit processing for all leftover processes and servers,
|
||||
* but don't actually exit them (if they were really gone, PM
|
||||
|
@ -350,11 +350,11 @@ PUBLIC void pm_reboot()
|
|||
*/
|
||||
free_proc(&fproc[i], 0);
|
||||
}
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
unmount_all();
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
}
|
||||
|
||||
|
@ -436,6 +436,8 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
|
|||
register struct vnode *vp;
|
||||
dev_t dev;
|
||||
|
||||
SANITYCHECK;
|
||||
|
||||
fp = exiter; /* get_filp() needs 'fp' */
|
||||
|
||||
if(fp->fp_endpoint == NONE) {
|
||||
|
@ -443,12 +445,14 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
|
|||
}
|
||||
|
||||
if (fp->fp_suspended == SUSPENDED) {
|
||||
SANITYCHECK;
|
||||
task = -fp->fp_task;
|
||||
if (task == XPIPE || task == XPOPEN) susp_count--;
|
||||
unpause(fp->fp_endpoint);
|
||||
fp->fp_suspended = NOT_SUSPENDED;
|
||||
SANITYCHECK;
|
||||
}
|
||||
|
||||
SANITYCHECK;
|
||||
|
||||
/* Loop on file descriptors, closing any that are open. */
|
||||
for (i = 0; i < OPEN_MAX; i++) {
|
||||
(void) close_fd(fp, i);
|
||||
|
@ -465,13 +469,13 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
|
|||
if(fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NIL_VNODE; }
|
||||
if(fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NIL_VNODE; }
|
||||
|
||||
CHECK_VREFS;
|
||||
|
||||
/* The rest of these actions is only done when processes actually
|
||||
* exit.
|
||||
*/
|
||||
if(!(flags & FP_EXITING))
|
||||
if(!(flags & FP_EXITING)) {
|
||||
SANITYCHECK;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Invalidate endpoint number for error and sanity checks. */
|
||||
fp->fp_endpoint = NONE;
|
||||
|
@ -504,6 +508,8 @@ PRIVATE void free_proc(struct fproc *exiter, int flags)
|
|||
|
||||
/* Exit done. Mark slot as free. */
|
||||
fp->fp_pid = PID_FREE;
|
||||
|
||||
SANITYCHECK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -71,7 +71,7 @@ PUBLIC int do_mount()
|
|||
{
|
||||
endpoint_t fs_e;
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Only the super-user may do MOUNT. */
|
||||
if (!super_user) return(EPERM);
|
||||
|
@ -107,7 +107,7 @@ PRIVATE int mount_fs(endpoint_t fs_e)
|
|||
char *label;
|
||||
struct node_details res;
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Only the super-user may do MOUNT. */
|
||||
if (!super_user) return(EPERM);
|
||||
|
@ -337,7 +337,7 @@ PRIVATE int mount_fs(endpoint_t fs_e)
|
|||
if(tfp->fp_wd) MAKEROOT(tfp->fp_wd);
|
||||
}
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ PRIVATE int mount_fs(endpoint_t fs_e)
|
|||
printf("VFSmount: moving opened block spec to new FS_e: %d...\n", fs_e);
|
||||
bspec->v_bfs_e = fs_e;
|
||||
}
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
@ -382,17 +382,17 @@ PUBLIC int do_umount()
|
|||
{
|
||||
/* Perform the umount(name) system call. */
|
||||
dev_t dev;
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Only the super-user may do UMOUNT. */
|
||||
if (!super_user) return(EPERM);
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* If 'name' is not for a block special file, return error. */
|
||||
if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
if ( (dev = name_to_dev()) == NO_DEV) return(err_code);
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
return(unmount(dev));
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ Dev_t dev;
|
|||
int count, r;
|
||||
int fs_e;
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Find vmnt */
|
||||
for (vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) {
|
||||
|
@ -472,16 +472,16 @@ Dev_t dev;
|
|||
count += vp->v_ref_count;
|
||||
}
|
||||
}
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
if (count > 1) {
|
||||
return(EBUSY); /* can't umount a busy file system */
|
||||
}
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
vnode_clean_refs(vmp->m_root_node);
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
if (vmp->m_mounted_on) {
|
||||
put_vnode(vmp->m_mounted_on);
|
||||
|
@ -504,7 +504,7 @@ Dev_t dev;
|
|||
vmp->m_dev = NO_DEV;
|
||||
vmp->m_fs_e = NONE;
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
/* Is there a block special file that was handled by that partition? */
|
||||
for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) {
|
||||
|
@ -531,7 +531,7 @@ Dev_t dev;
|
|||
}
|
||||
}
|
||||
|
||||
CHECK_VREFS;
|
||||
SANITYCHECK;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
|
@ -240,9 +240,14 @@ int task; /* who is proc waiting for? (PIPE = pipe) */
|
|||
* The SUSPEND pseudo error should be returned after calling suspend().
|
||||
*/
|
||||
|
||||
#if DO_SANITYCHECKS
|
||||
if (task == XPIPE)
|
||||
panic(__FILE__, "suspend: called for XPIPE", NO_NUM);
|
||||
|
||||
if(fp->fp_suspended == SUSPENDED)
|
||||
panic(__FILE__, "suspend: called for suspended process", NO_NUM);
|
||||
#endif
|
||||
|
||||
if (task == XPOPEN) susp_count++;/* #procs susp'ed on pipe*/
|
||||
fp->fp_suspended = SUSPENDED;
|
||||
assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant));
|
||||
|
@ -277,6 +282,10 @@ size_t size;
|
|||
* but they are needed for pipes, and it is not worth making the distinction.)
|
||||
* The SUSPEND pseudo error should be returned after calling suspend().
|
||||
*/
|
||||
#if DO_SANITYCHECKS
|
||||
if(fp->fp_suspended == SUSPENDED)
|
||||
panic(__FILE__, "pipe_suspend: called for suspended process", NO_NUM);
|
||||
#endif
|
||||
|
||||
susp_count++; /* #procs susp'ed on pipe*/
|
||||
fp->fp_suspended = SUSPENDED;
|
||||
|
@ -463,6 +472,7 @@ int proc_nr_e;
|
|||
struct filp *f;
|
||||
dev_t dev;
|
||||
message mess;
|
||||
int wasreviving = 0;
|
||||
|
||||
if(isokendpt(proc_nr_e, &proc_nr_p) != OK) {
|
||||
printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_nr_e);
|
||||
|
@ -478,8 +488,10 @@ int proc_nr_e;
|
|||
{
|
||||
rfp->fp_revived = NOT_REVIVING;
|
||||
reviving--;
|
||||
wasreviving = 1;
|
||||
}
|
||||
|
||||
|
||||
switch (task) {
|
||||
case XPIPE: /* process trying to read or write a pipe */
|
||||
break;
|
||||
|
@ -540,6 +552,11 @@ int proc_nr_e;
|
|||
}
|
||||
|
||||
rfp->fp_suspended = NOT_SUSPENDED;
|
||||
|
||||
if ((task == XPIPE || task == XPOPEN) && !wasreviving) {
|
||||
susp_count--;
|
||||
}
|
||||
|
||||
reply(proc_nr_e, status); /* signal interrupted call */
|
||||
}
|
||||
|
||||
|
@ -587,6 +604,34 @@ PUBLIC int select_match_pipe(struct filp *f)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if DO_SANITYCHECKS
|
||||
/*===========================================================================*
|
||||
* check_pipe *
|
||||
*===========================================================================*/
|
||||
PUBLIC int check_pipe(void)
|
||||
{
|
||||
struct fproc *rfp;
|
||||
int mycount = 0;
|
||||
for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if (rfp->fp_pid == PID_FREE)
|
||||
continue;
|
||||
if(rfp->fp_suspended != SUSPENDED &&
|
||||
rfp->fp_suspended != NOT_SUSPENDED) {
|
||||
printf("check_pipe: %d invalid suspended value 0x%x\n",
|
||||
rfp->fp_endpoint, rfp->fp_suspended);
|
||||
return 0;
|
||||
}
|
||||
if(rfp->fp_suspended == SUSPENDED && rfp->fp_revived != REVIVING && (-rfp->fp_task == XPIPE || -rfp->fp_task == XPOPEN)) {
|
||||
mycount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(mycount != susp_count) {
|
||||
printf("check_pipe: mycount %d susp_count %d\n",
|
||||
mycount, susp_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -138,6 +138,9 @@ _PROTOTYPE( int select_match_pipe, (struct filp *f) );
|
|||
_PROTOTYPE( void unsuspend_by_endpt, (int) );
|
||||
_PROTOTYPE( void select_reply1, (void) );
|
||||
_PROTOTYPE( void select_reply2, (void) );
|
||||
#if DO_SANITYCHECKS
|
||||
_PROTOTYPE( int check_pipe, (void) );
|
||||
#endif
|
||||
|
||||
/* protect.c */
|
||||
_PROTOTYPE( int do_access, (void) );
|
||||
|
@ -251,15 +254,9 @@ _PROTOTYPE( struct vnode *find_vnode, (int fs_e, int numb) );
|
|||
_PROTOTYPE( void dup_vnode, (struct vnode *vp) );
|
||||
_PROTOTYPE( void put_vnode, (struct vnode *vp) );
|
||||
_PROTOTYPE( void vnode_clean_refs, (struct vnode *vp) );
|
||||
#if 0
|
||||
_PROTOTYPE( struct vnode *get_vnode, (int fs_e, int inode_nr) );
|
||||
_PROTOTYPE( struct vnode *get_vnode_x, (int fs_e, int inode_nr) );
|
||||
_PROTOTYPE( void mark_vn, (struct vnode *vp, char *file, int line) );
|
||||
#endif
|
||||
#define CHECK_VREFS do { if(!check_vrefs()) { \
|
||||
printf("VFS:%s:%d: check_vrefs failed\n", __FILE__, __LINE__); \
|
||||
panic("VFS", "check_vrefs failed", NO_NUM);} } while(0)
|
||||
#if DO_SANITYCHECKS
|
||||
_PROTOTYPE( int check_vrefs, (void) );
|
||||
#endif
|
||||
|
||||
/* write.c */
|
||||
_PROTOTYPE( int do_write, (void) );
|
||||
|
|
|
@ -169,6 +169,7 @@ int line;
|
|||
|
||||
#define REFVP(v) { vp = (v); CHECKVN(v); vp->v_ref_check++; }
|
||||
|
||||
#if DO_SANITYCHECKS
|
||||
/*===========================================================================*
|
||||
* check_vrefs *
|
||||
*===========================================================================*/
|
||||
|
@ -245,3 +246,4 @@ PUBLIC int check_vrefs()
|
|||
}
|
||||
return !bad;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -38,5 +38,3 @@ EXTERN struct vnode {
|
|||
#define NO_SEEK 0 /* i_seek = NO_SEEK if last op was not SEEK */
|
||||
#define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */
|
||||
|
||||
|
||||
#define SANITYCHECK do { if(!check_vrefs()) { printf("VFS:%s:%d: vref check failed\n", __FILE__, __LINE__); util_stacktrace(); } } while(0)
|
||||
|
|
Loading…
Reference in a new issue