/*===========================================================================* * pm_fork * *===========================================================================*/ void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid) { /* Perform those aspects of the fork() system call that relate to files. * In particular, let the child inherit its parent's file descriptors. * The parent and child parameters tell who forked off whom. The file * system uses the same slot numbers as the kernel. Only PM makes this call. */ struct fproc *cp, *pp; int i, parentno, childno; mutex_t c_fp_lock; /* Check up-to-dateness of fproc. */ okendpt(pproc, &parentno); /* PM gives child endpoint, which implies process slot information. * Don't call isokendpt, because that will verify if the endpoint * number is correct in fproc, which it won't be. */ childno = _ENDPOINT_P(cproc); if (childno < 0 || childno >= NR_PROCS) panic("VFS: bogus child for forking: %d", cproc); if (fproc[childno].fp_pid != PID_FREE) panic("VFS: forking on top of in-use child: %d", childno); /* Copy the parent's fproc struct to the child. */ /* However, the mutex variables belong to a slot and must stay the same. */ c_fp_lock = fproc[childno].fp_lock; fproc[childno] = fproc[parentno]; fproc[childno].fp_lock = c_fp_lock; /* Increase the counters in the 'filp' table. */ cp = &fproc[childno]; pp = &fproc[parentno]; for (i = 0; i < OPEN_MAX; i++) if (cp->fp_filp[i] != NULL) cp->fp_filp[i]->filp_count++; /* Fill in new process and endpoint id. */ cp->fp_pid = cpid; cp->fp_endpoint = cproc; /* A forking process never has an outstanding grant, as it isn't blocking on * I/O. */ if (GRANT_VALID(pp->fp_grant)) { panic("VFS: fork: pp (endpoint %d) has grant %d\n", pp->fp_endpoint, pp->fp_grant); } if (GRANT_VALID(cp->fp_grant)) { panic("VFS: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, cp->fp_grant); } /* A child is not a process leader, not being revived, etc. */ cp->fp_flags = FP_NOFLAGS; /* Record the fact that both root and working dir have another user. */ if (cp->fp_rd) dup_vnode(cp->fp_rd); if (cp->fp_wd) dup_vnode(cp->fp_wd); }
/*===========================================================================* * do_fchdir * *===========================================================================*/ PUBLIC int do_fchdir() { /* Change directory on already-opened fd. */ struct filp *rfilp; /* Is the file descriptor valid? */ if ((rfilp = get_filp(m_in.fd)) == NULL) return(err_code); dup_vnode(rfilp->filp_vno); /* Change into expects a reference. */ return change_into(&fp->fp_wd, rfilp->filp_vno); }
/*===========================================================================* * change_into * *===========================================================================*/ static int change_into(struct vnode **result, struct vnode *vp) { int r; if (*result == vp) return(OK); /* Nothing to do */ /* It must be a directory and also be searchable */ if ((vp->v_mode & I_TYPE) != I_DIRECTORY) r = ENOTDIR; else r = forbidden(fp, vp, X_BIT); /* Check if dir is searchable*/ if (r != OK) return(r); /* Everything is OK. Make the change. */ put_vnode(*result); /* release the old directory */ dup_vnode(vp); *result = vp; /* acquire the new one */ return(OK); }
/*===========================================================================* * do_pipe * *===========================================================================*/ PUBLIC int do_pipe() { /* Perform the pipe(fil_des) system call. */ register struct fproc *rfp; int r; struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ struct vnode *vp; struct vmnt *vmp; struct node_details res; /* See if a free vnode is available */ if ( (vp = get_free_vnode()) == NIL_VNODE) return(err_code); /* Acquire two file descriptors. */ rfp = fp; if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r); rfp->fp_filp[fil_des[0]] = fil_ptr0; FD_SET(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 1; if ((r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NIL_FILP; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; FD_SET(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 1; /* Create a named pipe inode on PipeFS */ r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, (dev_t) 0, &res); if (r != OK) { rfp->fp_filp[fil_des[0]] = NIL_FILP; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NIL_FILP; FD_CLR(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 0; return(r); } /* Fill in vnode */ vp->v_fs_e = res.fs_e; vp->v_mapfs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mapinode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_pipe = I_PIPE; vp->v_pipe_rd_pos= 0; vp->v_pipe_wr_pos= 0; vp->v_fs_count = 1; vp->v_mapfs_count = 1; vp->v_ref_count = 1; vp->v_size = 0; vp->v_vmnt = NIL_VMNT; vp->v_dev = NO_DEV; /* Fill in filp objects */ fil_ptr0->filp_vno = vp; dup_vnode(vp); fil_ptr1->filp_vno = vp; fil_ptr0->filp_flags = O_RDONLY; fil_ptr1->filp_flags = O_WRONLY; m_out.reply_i1 = fil_des[0]; m_out.reply_i2 = fil_des[1]; return(OK); }
/*===========================================================================* * sef_cb_init_fresh * *===========================================================================*/ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) { /* Initialize the virtual file server. */ int s, i; register struct fproc *rfp; struct vmnt *vmp; struct vnode *root_vp; message mess; struct rprocpub rprocpub[NR_BOOT_PROCS]; /* Clear endpoint field */ last_login_fs_e = NONE; mount_m_in.m1_p3 = (char *) NONE; /* Initialize the process table with help of the process manager messages. * Expect one message for each system process with its slot number and pid. * When no more processes follow, the magic process number NONE is sent. * Then, stop and synchronize with the PM. */ do { if (OK != (s=sef_receive(PM_PROC_NR, &mess))) panic("FS couldn't receive from PM: %d", s); if (mess.m_type != PM_INIT) panic("unexpected message from PM: %d", mess.m_type); if (NONE == mess.PM_PROC) break; rfp = &fproc[mess.PM_SLOT]; rfp->fp_pid = mess.PM_PID; rfp->fp_endpoint = mess.PM_PROC; rfp->fp_openfd = 0; rfp->fp_realuid = (uid_t) SYS_UID; rfp->fp_effuid = (uid_t) SYS_UID; rfp->fp_realgid = (gid_t) SYS_GID; rfp->fp_effgid = (gid_t) SYS_GID; rfp->fp_umask = ~0; rfp->fp_grant = GRANT_INVALID; rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; rfp->fp_revived = NOT_REVIVING; rfp->fp_fsizelim.rlim_cur = RLIM_FSIZE_DEFAULT; rfp->fp_fsizelim.rlim_max = RLIM_FSIZE_DEFAULT; rfp->fp_nofilelim.rlim_cur = RLIM_NOFILE_DEFAULT; rfp->fp_nofilelim.rlim_max = RLIM_NOFILE_DEFAULT; } while (TRUE); /* continue until process NONE */ mess.m_type = OK; /* tell PM that we succeeded */ s = send(PM_PROC_NR, &mess); /* send synchronization message */ /* All process table entries have been set. Continue with initialization. */ /* The following initializations are needed to let dev_opcl succeed .*/ fp = (struct fproc *) NULL; who_e = who_p = VFS_PROC_NR; /* Initialize device table. */ build_dmap(); /* Map all the services in the boot image. */ if((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0, (vir_bytes) rprocpub, sizeof(rprocpub), S)) != OK) { panic("sys_safecopyfrom failed: %d", s); } for(i=0;i < NR_BOOT_PROCS;i++) { if(rprocpub[i].in_use) { if((s = map_service(&rprocpub[i])) != OK) { panic("unable to map service: %d", s); } } } init_root(); /* init root device and load super block */ init_select(); /* init select() structures */ vmp = &vmnt[0]; /* Should be the root filesystem */ if (vmp->m_dev == NO_DEV) panic("vfs: no root filesystem"); root_vp= vmp->m_root_node; /* The root device can now be accessed; set process directories. */ for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { FD_ZERO(&(rfp->fp_filp_inuse)); if (rfp->fp_pid != PID_FREE) { dup_vnode(root_vp); rfp->fp_rd = root_vp; dup_vnode(root_vp); rfp->fp_wd = root_vp; } else rfp->fp_endpoint = NONE; } system_hz = sys_hz(); /* Subscribe to driver events for VFS drivers. */ s = ds_subscribe("drv\\.vfs\\..*", DSF_INITIAL | DSF_OVERWRITE); if(s != OK) { panic("vfs: can't subscribe to driver events"); } SANITYCHECK; #if DO_SANITYCHECKS FIXME("VFS: DO_SANITYCHECKS is on"); #endif return(OK); }
/*===========================================================================* * do_pipe * *===========================================================================*/ int do_pipe() { /* Perform the pipe(fil_des) system call. */ register struct fproc *rfp; int r; struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ struct vnode *vp; struct vmnt *vmp; struct node_details res; /* Get a lock on PFS */ if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone"); if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r); /* See if a free vnode is available */ if ((vp = get_free_vnode()) == NULL) { unlock_vmnt(vmp); return(err_code); } lock_vnode(vp, VNODE_OPCL); /* Acquire two file descriptors. */ rfp = fp; if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) { unlock_vnode(vp); unlock_vmnt(vmp); return(r); } rfp->fp_filp[fil_des[0]] = fil_ptr0; FD_SET(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 1; /* mark filp in use */ if ((r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NULL; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; /* mark filp free */ unlock_filp(fil_ptr0); unlock_vnode(vp); unlock_vmnt(vmp); return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; FD_SET(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 1; /* Create a named pipe inode on PipeFS */ r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, NO_DEV, &res); if (r != OK) { rfp->fp_filp[fil_des[0]] = NULL; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NULL; FD_CLR(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 0; unlock_filp(fil_ptr1); unlock_filp(fil_ptr0); unlock_vnode(vp); unlock_vmnt(vmp); return(r); } /* Fill in vnode */ vp->v_fs_e = res.fs_e; vp->v_mapfs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mapinode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_fs_count = 1; vp->v_mapfs_count = 1; vp->v_ref_count = 1; vp->v_size = 0; vp->v_vmnt = NULL; vp->v_dev = NO_DEV; /* Fill in filp objects */ fil_ptr0->filp_vno = vp; dup_vnode(vp); fil_ptr1->filp_vno = vp; fil_ptr0->filp_flags = O_RDONLY; fil_ptr1->filp_flags = O_WRONLY; m_out.reply_i1 = fil_des[0]; m_out.reply_i2 = fil_des[1]; unlock_filps(fil_ptr0, fil_ptr1); unlock_vmnt(vmp); return(OK); }
/*===========================================================================* * do_pipe * *===========================================================================*/ PUBLIC int do_pipe() { /* Perform the pipe(fil_des) system call. */ register struct fproc *rfp; int r; struct filp *fil_ptr0, *fil_ptr1; int fil_des[2]; /* reply goes here */ struct vnode *vp; struct node_details res; /* See if a free vnode is available */ if ( (vp = get_free_vnode()) == NULL) return(err_code); /* Acquire two file descriptors. */ rfp = fp; /* Check if process can open 2 more files */ if(rfp->fp_openfd + 1 >= (unsigned int)rfp->fp_nofilelim.rlim_cur && rfp->fp_nofilelim.rlim_cur != RLIM_INFINITY) return(EMFILE); if ((r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r); rfp->fp_filp[fil_des[0]] = fil_ptr0; FD_SET(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 1; if ((r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NULL; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; FD_SET(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 1; /* Create a named pipe inode on PipeFS */ r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, NO_DEV, &res); if (r != OK) { rfp->fp_filp[fil_des[0]] = NULL; FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NULL; FD_CLR(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 0; return(r); } /* 2 new files openned */ rfp->fp_openfd+=2; /* Fill in vnode */ vp->v_fs_e = res.fs_e; vp->v_mapfs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mapinode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_pipe = I_PIPE; vp->v_pipe_rd_pos= 0; vp->v_pipe_wr_pos= 0; vp->v_fs_count = 1; vp->v_mapfs_count = 1; vp->v_ref_count = 1; vp->v_size = 0; vp->v_vmnt = NULL; vp->v_dev = NO_DEV; /* Fill in filp objects */ fil_ptr0->filp_vno = vp; dup_vnode(vp); fil_ptr1->filp_vno = vp; fil_ptr0->filp_flags = O_RDONLY; fil_ptr1->filp_flags = O_WRONLY; m_out.reply_i1 = fil_des[0]; m_out.reply_i2 = fil_des[1]; return(OK); }
/*===========================================================================* * create_pipe * *===========================================================================*/ static int create_pipe(int fil_des[2], int flags) { register struct fproc *rfp; int r; struct filp *fil_ptr0, *fil_ptr1; struct vnode *vp; struct vmnt *vmp; struct node_details res; /* Get a lock on PFS */ if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL) panic("PFS gone"); if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) return(r); /* See if a free vnode is available */ if ((vp = get_free_vnode()) == NULL) { unlock_vmnt(vmp); return(err_code); } lock_vnode(vp, VNODE_OPCL); /* Acquire two file descriptors. */ rfp = fp; if ((r = get_fd(fp, 0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) { unlock_vnode(vp); unlock_vmnt(vmp); return(r); } rfp->fp_filp[fil_des[0]] = fil_ptr0; fil_ptr0->filp_count = 1; /* mark filp in use */ if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NULL; fil_ptr0->filp_count = 0; /* mark filp free */ unlock_filp(fil_ptr0); unlock_vnode(vp); unlock_vmnt(vmp); return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; fil_ptr1->filp_count = 1; /* Create a named pipe inode on PipeFS */ r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, I_NAMED_PIPE, NO_DEV, &res); if (r != OK) { rfp->fp_filp[fil_des[0]] = NULL; fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NULL; fil_ptr1->filp_count = 0; unlock_filp(fil_ptr1); unlock_filp(fil_ptr0); unlock_vnode(vp); unlock_vmnt(vmp); return(r); } /* Fill in vnode */ vp->v_fs_e = res.fs_e; vp->v_mapfs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mapinode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_fs_count = 1; vp->v_mapfs_count = 1; vp->v_ref_count = 1; vp->v_size = 0; vp->v_vmnt = NULL; vp->v_dev = NO_DEV; /* Fill in filp objects */ fil_ptr0->filp_vno = vp; dup_vnode(vp); fil_ptr1->filp_vno = vp; fil_ptr0->filp_flags = O_RDONLY | (flags & ~O_ACCMODE); fil_ptr1->filp_flags = O_WRONLY | (flags & ~O_ACCMODE); if (flags & O_CLOEXEC) { FD_SET(fil_des[0], &rfp->fp_cloexec_set); FD_SET(fil_des[1], &rfp->fp_cloexec_set); } unlock_filps(fil_ptr0, fil_ptr1); unlock_vmnt(vmp); return(OK); }