/* * Create a fresh proc for use by runprogram. * * It will have no address space and will inherit the current * process's (that is, the kernel menu's) current directory. */ struct proc * proc_create_runprogram(const char *name) { struct proc *proc; char *console_path; proc = proc_create(name); if (proc == NULL) { return NULL; } #ifdef UW /* open the console - this should always succeed */ console_path = kstrdup("con:"); if (console_path == NULL) { panic("unable to copy console path name during process creation\n"); } if (vfs_open(console_path,O_WRONLY,0,&(proc->console))) { panic("unable to open the console during process creation\n"); } kfree(console_path); #endif // UW /* VM fields */ proc->p_addrspace = NULL; /* VFS fields */ #ifdef UW /* we do not need to acquire the p_lock here, the running thread should have the only reference to this process */ /* also, acquiring the p_lock is problematic because VOP_INCREF may block */ if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } #else // UW spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); #endif // UW #ifdef UW /* increment the count of processes */ /* we are assuming that all procs, including those created by fork(), are created using a call to proc_create_runprogram */ P(proc_count_mutex); proc_count++; V(proc_count_mutex); #endif // UW return proc; }
/* * Create a fresh proc for use by runprogram. * * It will have no address space and will inherit the current * process's (that is, the kernel menu's) current directory. */ struct proc * proc_create_runprogram(const char *name) { struct proc *proc; proc = proc_create(name); if (proc == NULL) { return NULL; } /* VM fields */ proc->p_addrspace = NULL; /* VFS fields */ spinlock_acquire(&curproc->p_lock); /* we don't need to lock proc->p_lock as we have the only reference */ if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); return proc; }
/* * Function to load a vnode into memory. */ static int emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir, struct emufs_vnode **ret) { struct vnode *v; struct emufs_vnode *ev; unsigned i, num; int result; lock_acquire(ef->ef_emu->e_lock); num = vnodearray_num(ef->ef_vnodes); for (i=0; i<num; i++) { v = vnodearray_get(ef->ef_vnodes, i); ev = v->vn_data; if (ev->ev_handle == handle) { /* Found */ VOP_INCREF(&ev->ev_v); lock_release(ef->ef_emu->e_lock); *ret = ev; return 0; } } /* Didn't have one; create it */ ev = kmalloc(sizeof(struct emufs_vnode)); if (ev==NULL) { lock_release(ef->ef_emu->e_lock); return ENOMEM; } ev->ev_emu = ef->ef_emu; ev->ev_handle = handle; result = vnode_init(&ev->ev_v, isdir ? &emufs_dirops : &emufs_fileops, &ef->ef_fs, ev); if (result) { lock_release(ef->ef_emu->e_lock); kfree(ev); return result; } result = vnodearray_add(ef->ef_vnodes, &ev->ev_v, NULL); if (result) { /* note: vnode_cleanup undoes vnode_init - it does not kfree */ vnode_cleanup(&ev->ev_v); lock_release(ef->ef_emu->e_lock); kfree(ev); return result; } lock_release(ef->ef_emu->e_lock); *ret = ev; return 0; }
/* * VOP_LOOKPARENT */ static int emufs_lookparent(struct vnode *dir, char *pathname, struct vnode **ret, char *buf, size_t len) { char *s; s = strrchr(pathname, '/'); if (s==NULL) { /* just a last component, no directory part */ if (strlen(pathname)+1 > len) { return ENAMETOOLONG; } VOP_INCREF(dir); *ret = dir; strcpy(buf, pathname); return 0; } *s = 0; s++; if (strlen(s)+1 > len) { return ENAMETOOLONG; } strcpy(buf, s); return emufs_lookup(dir, pathname, ret); }
/* * Set current directory as a vnode. * The passed vnode must in fact be a directory. */ int vfs_setcurdir(struct vnode *dir) { struct vnode *old; mode_t vtype; int result; result = VOP_GETTYPE(dir, &vtype); if (result) { return result; } if (vtype != S_IFDIR) { return ENOTDIR; } VOP_INCREF(dir); spinlock_acquire(&curproc->p_lock); old = curproc->p_cwd; curproc->p_cwd = dir; spinlock_release(&curproc->p_lock); if (old!=NULL) { VOP_DECREF(old); } return 0; }
/* * Create a fresh proc for use by runprogram. * * It will have no address space and will inherit the current * process's (that is, the kernel menu's) current directory. * * It will be given no filetable. The filetable will be initialized in * runprogram(). */ struct proc * proc_create_runprogram(const char *name) { struct proc *newproc; newproc = proc_create(name); if (newproc == NULL) { return NULL; } /* VM fields */ newproc->p_addrspace = NULL; /* VFS fields */ /* * Lock the current process to copy its current directory. * (We don't need to lock the new process, though, as we have * the only reference to it.) */ spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); newproc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); return newproc; }
/* * lookparent returns the last path component as a string and the * directory it's in as a vnode. * * Since we don't support subdirectories, this is very easy - * return the root dir and copy the path. */ static int sfs_lookparent(struct vnode *v, char *path, struct vnode **ret, char *buf, size_t buflen) { struct sfs_vnode *sv = v->vn_data; vfs_biglock_acquire(); if (sv->sv_i.sfi_type != SFS_TYPE_DIR) { vfs_biglock_release(); return ENOTDIR; } if (strlen(path)+1 > buflen) { vfs_biglock_release(); return ENAMETOOLONG; } strcpy(buf, path); VOP_INCREF(&sv->sv_v); *ret = &sv->sv_v; vfs_biglock_release(); return 0; }
/* * Lookup: get a semaphore by name. */ static int semfs_lookup(struct vnode *dirvn, char *path, struct vnode **resultvn) { struct semfs_vnode *dirsemv = dirvn->vn_data; struct semfs *semfs = dirsemv->semv_semfs; struct semfs_direntry *dent; unsigned i, num; int result; if (!strcmp(path, ".") || !strcmp(path, "..")) { VOP_INCREF(dirvn); *resultvn = dirvn; return 0; } lock_acquire(semfs->semfs_dirlock); num = semfs_direntryarray_num(semfs->semfs_dents); for (i=0; i<num; i++) { dent = semfs_direntryarray_get(semfs->semfs_dents, i); if (dent == NULL) { continue; } if (!strcmp(path, dent->semd_name)) { result = semfs_getvnode(semfs, dent->semd_semnum, resultvn); lock_release(semfs->semfs_dirlock); return result; } } lock_release(semfs->semfs_dirlock); return ENOENT; }
/* * Lookup gets a vnode for a pathname. */ static int sfs_lookup(struct vnode *v, char *path, struct vnode **ret) { struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *parent, *child; char name[SFS_NAMELEN]; int i, err; if (sv->sv_i.sfi_type != SFS_TYPE_DIR) { return ENOTDIR; } parent = sv; VOP_INCREF(&parent->sv_v); child = NULL; //just to be safe while(1){ i = 0; while(path[i] != '/' && path[i] != '\0' && i < SFS_NAMELEN) i++; if(i >= SFS_NAMELEN){ VOP_DECREF(&parent->sv_v); return ENAMETOOLONG; } else if(path[i] == '/'){ path[i] = 0; strcpy(name, path); path = &path[i + 1]; err = sfs_lookonce(parent, name, &child, NULL); if(err){ VOP_DECREF(&parent->sv_v); return err; } VOP_DECREF(&parent->sv_v); parent = child; if(parent->sv_i.sfi_type != SFS_TYPE_DIR) return ENOTDIR; } else{ /* Hit NULL, so this is our last time through */ assert(path[i] == '\0'); err = sfs_lookonce(parent, path, &child, NULL); if(err){ VOP_DECREF(&parent->sv_v); return err; } VOP_DECREF(&parent->sv_v); break; } } *ret = &child->sv_v; return 0; }
struct proc* proc_createchild(struct proc* parent, struct addrspace** as) { struct proc* child = proc_create(parent->p_name); if (child == NULL) { return NULL; } unsigned int i; // TODO Move this to a separate method for (i = 0; i < array_num(parent->p_filetable); i++) { struct filetable_entry* entry = array_get(parent->p_filetable, i); struct filetable_entry* newentry = (struct filetable_entry*) kmalloc(sizeof(struct filetable_entry)); if(entry == NULL) { proc_destroy(child); return NULL; } newentry->ft_fd = entry->ft_fd; newentry->ft_handle = entry->ft_handle; filehandle_incref(entry->ft_handle); int s = array_add(child->p_filetable, newentry, NULL); if (s == ENOMEM) { proc_destroy(child); return NULL; } } child->p_fdcounter = parent->p_fdcounter; /** process table */ if (addTo_processtable(child) != 0) { return NULL; } child->p_ppid = parent->p_pid; /** cwd */ /* * Lock the current process to copy its current directory. * (We don't need to lock the new process, though, as we have * the only reference to it.) */ spinlock_acquire(&(parent->p_lock)); if (parent->p_cwd != NULL) { VOP_INCREF(parent->p_cwd); child->p_cwd = parent->p_cwd; } spinlock_release(&(parent->p_lock)); /** address space */ (void) as; return child; }
static int sfs_lookparent_internal(struct vnode *v, char *path, struct vnode **ret, char *buf, size_t buflen) { struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *next; char *s; int result; VOP_INCREF(&sv->sv_absvn); while (1) { /* Don't need lock to check vnode type; it's constant */ if (sv->sv_type != SFS_TYPE_DIR) { VOP_DECREF(&sv->sv_absvn); return ENOTDIR; } s = strchr(path, '/'); if (!s) { /* Last component. */ break; } *s = 0; s++; lock_acquire(sv->sv_lock); result = sfs_lookonce(sv, path, &next, NULL); lock_release(sv->sv_lock); if (result) { VOP_DECREF(&sv->sv_absvn); return result; } VOP_DECREF(&sv->sv_absvn); sv = next; path = s; } if (strlen(path)+1 > buflen) { VOP_DECREF(&sv->sv_absvn); return ENAMETOOLONG; } strcpy(buf, path); *ret = &sv->sv_absvn; return 0; }
/* * Lookparent: because we don't have subdirs, just return the root * dir and copy the name. */ static int semfs_lookparent(struct vnode *dirvn, char *path, struct vnode **resultdirvn, char *namebuf, size_t bufmax) { if (strlen(path)+1 > bufmax) { return ENAMETOOLONG; } strcpy(namebuf, path); VOP_INCREF(dirvn); *resultdirvn = dirvn; return 0; }
/* * Look up the vnode for a semaphore by number; if it doesn't exist, * create it. */ int semfs_getvnode(struct semfs *semfs, unsigned semnum, struct vnode **ret) { struct vnode *vn; struct semfs_vnode *semv; struct semfs_sem *sem; unsigned i, num; int result; /* Lock the vnode table */ lock_acquire(semfs->semfs_tablelock); /* Look for it */ num = vnodearray_num(semfs->semfs_vnodes); for (i=0; i<num; i++) { vn = vnodearray_get(semfs->semfs_vnodes, i); semv = vn->vn_data; if (semv->semv_semnum == semnum) { VOP_INCREF(vn); lock_release(semfs->semfs_tablelock); *ret = vn; return 0; } } /* Make it */ semv = semfs_vnode_create(semfs, semnum); if (semv == NULL) { lock_release(semfs->semfs_tablelock); return ENOMEM; } result = vnodearray_add(semfs->semfs_vnodes, &semv->semv_absvn, NULL); if (result) { semfs_vnode_destroy(semv); lock_release(semfs->semfs_tablelock); return ENOMEM; } if (semnum != SEMFS_ROOTDIR) { sem = semfs_semarray_get(semfs->semfs_sems, semnum); KASSERT(sem != NULL); KASSERT(sem->sems_hasvnode == false); sem->sems_hasvnode = true; } lock_release(semfs->semfs_tablelock); *ret = &semv->semv_absvn; return 0; }
/* * FSOP_GETROOT */ static struct vnode * emufs_getroot(struct fs *fs) { struct emufs_fs *ef; KASSERT(fs != NULL); ef = fs->fs_data; KASSERT(ef != NULL); KASSERT(ef->ef_root != NULL); VOP_INCREF(&ef->ef_root->ev_v); return &ef->ef_root->ev_v; }
/* * Get current directory as a vnode. */ int vfs_getcurdir(struct vnode **ret) { int rv = 0; spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd!=NULL) { VOP_INCREF(curproc->p_cwd); *ret = curproc->p_cwd; } else { rv = ENOENT; } spinlock_release(&curproc->p_lock); return rv; }
/* * Name lookup. * * One interesting feature of device:name pathname syntax is that you can * implement pathnames on arbitrary devices. For instance, if you had a * serial port that actually let you control the RS232 settings (unlike * the LAMEbus serial port), you might arrange things so that you could * open it with pathnames like "ser:9600/n/8/1" in order to select the * operating mode. * * However, we have no support for this in the base system. */ static int dev_lookup(struct vnode *dir, char *pathname, struct vnode **result) { /* * If the path was "device:", we get "". For that, return self. * Anything else is an error. * Increment the ref count of the vnode before returning it. */ if (strlen(pathname)>0) { return ENOENT; } VOP_INCREF(dir); *result = dir; return 0; }
/* * FSOP_GETROOT */ static int emufs_getroot(struct fs *fs, struct vnode **ret) { struct emufs_fs *ef; KASSERT(fs != NULL); ef = fs->fs_data; KASSERT(ef != NULL); KASSERT(ef->ef_root != NULL); VOP_INCREF(&ef->ef_root->ev_v); *ret = &ef->ef_root->ev_v; return 0; }
void ftab_copy(struct array *oldtab, struct array **newtab){ struct fildes *fd; if(oldtab == NULL){ return; } *newtab = ftab_init(); for(unsigned int i = 2; (fd = ftab_get(oldtab, i)) != NULL; i++){ // v = array_get(oldtab, i); ftab_set(*newtab, (void *)fd, i); VOP_INCREF(fd->vn); } }
int sys_fork(struct trapframe* tf, int *err) { struct trapframe* childtf = NULL; struct proc* childproc = NULL; struct addrspace* childaddr = NULL; int result; childtf = kmalloc(sizeof(struct trapframe)); if(childtf == NULL){ *err = ENOMEM; return -1; } memcpy(childtf, tf, sizeof(struct trapframe)); result = as_copy(curproc->p_addrspace, &childaddr); if(childaddr == NULL){ kfree(childtf); *err = ENOMEM; return -1; } childproc = proc_create_child("child"); if(childproc == NULL){ kfree(childtf); *err = ENOMEM; return -1; } result = thread_fork("process", childproc, child_forkentry, childtf, (unsigned long) childaddr); if(result) { return result; } result = childproc->pid; childproc->p_cwd = curproc->p_cwd; VOP_INCREF(curproc->p_cwd); curproc->p_numthreads++; return result; }
/* * Helper function for rename. Make sure COMPARE is not a direct * ancestor of (or the same as) CHILD. * * Note: acquires locks as it goes up. */ static int check_parent(struct sfs_vnode *lookfor, struct sfs_vnode *failon, struct sfs_vnode *child, int *found) { struct sfs_vnode *up; int result; *found = 0; VOP_INCREF(&child->sv_absvn); while (1) { if (failon == child) { /* Bad */ VOP_DECREF(&child->sv_absvn); return EINVAL; } if (lookfor == child) { *found = 1; } lock_acquire(child->sv_lock); result = sfs_lookonce(child, "..", &up, NULL); lock_release(child->sv_lock); if (result) { VOP_DECREF(&child->sv_absvn); return result; } if (child == up) { /* Hit root, done */ VOP_DECREF(&up->sv_absvn); break; } VOP_DECREF(&child->sv_absvn); child = up; } VOP_DECREF(&child->sv_absvn); return 0; }
/* * Clone the current process. * * The new thread is given a copy of the caller's file handles if RET * is not null. (If RET is null, what we're creating is a kernel-only * thread and it doesn't need an address space or file handles.) * However, the new thread always inherits its current working * directory from the caller. The new thread is given no address space * (the caller decides that). */ int proc_fork(struct proc **ret) { struct proc *proc; struct filetable *tbl; int result; proc = proc_create(curproc->p_name); if (proc == NULL) { return ENOMEM; } /* VM fields */ /* do not clone address space -- let caller decide on that */ /* VFS fields */ tbl = curproc->p_filetable; if (tbl != NULL) { result = filetable_copy(tbl, &proc->p_filetable); if (result) { as_destroy(proc->p_addrspace); proc->p_addrspace = NULL; proc_destroy(proc); return result; } } spinlock_acquire(&curproc->p_lock); /* we don't need to lock proc->p_lock as we have the only reference */ if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); *ret = proc; return 0; }
/* * Create a fresh proc for use by runprogram. * * It will have no address space and will inherit the current * process's (that is, the kernel menu's) current directory. */ struct proc * proc_create_runprogram(const char *name) { struct proc *newproc; newproc = proc_create(name); if (newproc == NULL) { return NULL; } addTo_processtable(newproc); /* VM fields */ newproc->p_addrspace = NULL; if (newproc->p_fdcounter == 0) { /* Create the standard fds */ proc_openstandardfds(newproc); } else { newproc->p_ppid = curproc->p_pid; } /* * Lock the current process to copy its current directory. * (We don't need to lock the new process, though, as we have * the only reference to it.) */ spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); newproc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); return newproc; }
int sys_fork(struct trapframe *tf, pid_t *retval) { int result; char* name; (void) result; (void) tf; (void) retval; struct trapframe *temp_tf = kmalloc(sizeof(*temp_tf)); *temp_tf = *tf; struct proc *newproc = proc_create("forked_process"); // TODO: concurrency issue? as_copy(curproc->p_addrspace, &newproc->p_addrspace); newproc->p_filetable = kmalloc(sizeof(struct filetable)); newproc->p_filetable->filetable_lock = lock_create("filetable_lock"); filetable_copy(newproc->p_filetable); // copied from proc.c init p_cwd spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); newproc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); newproc->parent_pid = curproc->pid; name = kstrdup(curproc->p_name); *retval = newproc->pid; thread_fork(name, newproc ,run_forked_proc, (void *)temp_tf, 0); return 0; }
/* * Create a new thread based on an existing one. * The new thread has name NAME, and starts executing in function FUNC. * DATA1 and DATA2 are passed to FUNC. */ int thread_fork(const char *name, void *data1, unsigned long data2, void (*func)(void *, unsigned long), pid_t *ret) { struct thread *newguy; int s, result; /* Allocate a thread */ newguy = thread_create(name); if (newguy==NULL) { return ENOMEM; } /* ASST1: Allocate a pid */ result = pid_alloc(&newguy->t_pid); if (result != 0) { kfree(newguy->t_name); kfree(newguy); return result; } /* Allocate a stack */ newguy->t_stack = kmalloc(STACK_SIZE); if (newguy->t_stack==NULL) { pid_unalloc(newguy->t_pid); /* ASST1: cleanup pid on fail */ kfree(newguy->t_name); kfree(newguy); return ENOMEM; } /* stick a magic number on the bottom end of the stack */ newguy->t_stack[0] = 0xae; newguy->t_stack[1] = 0x11; newguy->t_stack[2] = 0xda; newguy->t_stack[3] = 0x33; /* Inherit the current directory */ if (curthread->t_cwd != NULL) { VOP_INCREF(curthread->t_cwd); newguy->t_cwd = curthread->t_cwd; } /* ASST1: copy address space if there is one */ if (curthread->t_vmspace != NULL) { result = as_copy(curthread->t_vmspace, &newguy->t_vmspace); if (result) { pid_unalloc(newguy->t_pid); kfree(newguy->t_name); kfree(newguy->t_stack); kfree(newguy); return ENOMEM; } } /* Set up the pcb (this arranges for func to be called) */ md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func); /* Interrupts off for atomicity */ s = splhigh(); /* * Make sure our data structures have enough space, so we won't * run out later at an inconvenient time. */ result = array_preallocate(sleepers, numthreads+1); if (result) { goto fail; } result = array_preallocate(zombies, numthreads+1); if (result) { goto fail; } /* Do the same for the scheduler. */ result = scheduler_preallocate(numthreads+1); if (result) { goto fail; } /* Make the new thread runnable */ result = make_runnable(newguy); if (result != 0) { goto fail; } /* * Increment the thread counter. This must be done atomically * with the preallocate calls; otherwise the count can be * temporarily too low, which would obviate its reason for * existence. */ numthreads++; /* Done with stuff that needs to be atomic */ splx(s); /* * Return new thread structure if it's wanted. Note that * using the thread structure from the parent thread should be * done only with caution, because in general the child thread * might exit at any time. */ if (ret != NULL) { *ret = newguy->t_pid; /* ASST1 return pid, not thread struct */ } else { /* Not returning the pid... better detach the new thread */ result = thread_detach(newguy->t_pid); assert(result == 0); /* can't fail. */ } return 0; fail: splx(s); /* ASST1: cleanup pid and vmspace on fail */ pid_unalloc(newguy->t_pid); if (newguy->t_vmspace) { as_destroy(newguy->t_vmspace); } if (newguy->t_cwd != NULL) { VOP_DECREF(newguy->t_cwd); } kfree(newguy->t_stack); kfree(newguy->t_name); kfree(newguy); return result; }
/* * Given a device name (lhd0, emu0, somevolname, null, etc.), hand * back an appropriate vnode. */ int vfs_getroot(const char *devname, struct vnode **ret) { struct knowndev *kd; unsigned i, num; KASSERT(vfs_biglock_do_i_hold()); num = knowndevarray_num(knowndevs); for (i=0; i<num; i++) { kd = knowndevarray_get(knowndevs, i); /* * If this device has a mounted filesystem, and * DEVNAME names either the filesystem or the device, * return the root of the filesystem. * * If it has no mounted filesystem, it's mountable, * and DEVNAME names the device, return ENXIO. */ if (kd->kd_fs!=NULL) { const char *volname; volname = FSOP_GETVOLNAME(kd->kd_fs); if (!strcmp(kd->kd_name, devname) || (volname!=NULL && !strcmp(volname, devname))) { return FSOP_GETROOT(kd->kd_fs, ret); } } else { if (kd->kd_rawname!=NULL && !strcmp(kd->kd_name, devname)) { return ENXIO; } } /* * If DEVNAME names the device, and we get here, it * must have no fs and not be mountable. In this case, * we return the device itself. */ if (!strcmp(kd->kd_name, devname)) { KASSERT(kd->kd_fs==NULL); KASSERT(kd->kd_rawname==NULL); KASSERT(kd->kd_device != NULL); VOP_INCREF(kd->kd_vnode); *ret = kd->kd_vnode; return 0; } /* * If the device has a rawname and DEVNAME names that, * return the device itself. */ if (kd->kd_rawname!=NULL && !strcmp(kd->kd_rawname, devname)) { KASSERT(kd->kd_device != NULL); VOP_INCREF(kd->kd_vnode); *ret = kd->kd_vnode; return 0; } /* * If none of the above tests matched, we didn't name * any of the names of this device, so go on to the * next one. */ } /* * If we got here, the device specified by devname doesn't exist. */ return ENODEV; }
/* * Function to load a inode into memory as a vnode, or dig up one * that's already resident. */ static int sfs_loadvnode(struct sfs_fs *sfs, u_int32_t ino, int forcetype, struct sfs_vnode **ret) { struct sfs_vnode *sv; const struct vnode_ops *ops = NULL; int i, num; int result; lock_acquire(sfs->sfs_vnodes_lock); /* Look in the vnodes table */ num = array_getnum(sfs->sfs_vnodes); /* Linear search. Is this too slow? You decide. */ for (i=0; i<num; i++) { sv = array_getguy(sfs->sfs_vnodes, i); /* Every inode in memory must be in an allocated block */ if (!sfs_bused(sfs, sv->sv_ino)) { panic("sfs: Found inode %u in unallocated block\n", sv->sv_ino); } if (sv->sv_ino==ino) { /* Found */ /* May only be set when creating new objects */ assert(forcetype==SFS_TYPE_INVAL); VOP_INCREF(&sv->sv_v); lock_release(sfs->sfs_vnodes_lock); *ret = sv; return 0; } } /* Didn't have it loaded; load it */ sv = kmalloc(sizeof(struct sfs_vnode)); if (sv==NULL) { lock_release(sfs->sfs_vnodes_lock); return ENOMEM; } /* Must be in an allocated block */ if (!sfs_bused(sfs, ino)) { panic("sfs: Tried to load inode %u from unallocated block\n", ino); } /* Read the block the inode is in */ result = sfs_rblock(sfs, &sv->sv_i, ino); if (result) { kfree(sv); lock_release(sfs->sfs_vnodes_lock); return result; } /* Not dirty yet */ sv->sv_dirty = 0; /* * FORCETYPE is set if we're creating a new file, because the * block on disk will have been zeroed out and thus the type * recorded there will be SFS_TYPE_INVAL. */ if (forcetype != SFS_TYPE_INVAL) { assert(sv->sv_i.sfi_type == SFS_TYPE_INVAL); sv->sv_i.sfi_type = forcetype; sv->sv_dirty = 1; } /* * Choose the function table based on the object type. */ switch (sv->sv_i.sfi_type) { case SFS_TYPE_FILE: ops = &sfs_fileops; break; case SFS_TYPE_DIR: ops = &sfs_dirops; break; default: panic("sfs: loadvnode: Invalid inode type " "(inode %u, type %u)\n", ino, sv->sv_i.sfi_type); } /* Call the common vnode initializer */ result = VOP_INIT(&sv->sv_v, ops, &sfs->sfs_absfs, sv); if (result) { kfree(sv); lock_release(sfs->sfs_vnodes_lock); return result; } /* Set the other fields in our vnode structure */ sv->sv_ino = ino; /* Add it to our table */ result = array_add(sfs->sfs_vnodes, sv); if (result) { VOP_KILL(&sv->sv_v); kfree(sv); lock_release(sfs->sfs_vnodes_lock); return result; } lock_release(sfs->sfs_vnodes_lock); /* Hand it back */ *ret = sv; return 0; }
/* * Get the full pathname for a file. This only needs to work on directories. * Since we don't support subdirectories, assume it's the root directory * and hand back the empty string. (The VFS layer takes care of the * device name, leading slash, etc.) */ static int sfs_namefile(struct vnode *vv, struct uio *uio) { /* * 1. All you really have is inode number of directory passed in. * 2. Get inode number of parent by reading directory slot 0 (..) * 3. loadvnode of parent * 4. Get our name by reading through parent directory for our inode * number * 5. Add this name to string * 6. Repeat 2 through 5 until we hit root * 7. uiomove * Deal with reference counters as you need to, as loadvnode * increments refcount on vnode that we load. */ struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *child_dir, *parent_dir; struct sfs_dir tsd; int err, nentries, slot; char to_add[SFS_NAMELEN + 1], pathname[(SFS_NAMELEN + 1) * SFS_DIR_DEPTH]; /* If we're root, do nothing */ if(sv->sv_ino == SFS_ROOT_LOCATION) return 0; child_dir = sv; VOP_INCREF(&child_dir->sv_v); while(1){ err = sfs_readdir(child_dir, &tsd, 1); if(err) return err; assert(!strcmp(tsd.sfd_name, "..")); err = sfs_loadvnode(child_dir->sv_v.vn_fs->fs_data, tsd.sfd_ino, SFS_TYPE_INVAL, &parent_dir); if(err) return err; nentries = sfs_dir_nentries(parent_dir); slot = 2; while (slot < nentries){ err = sfs_readdir(parent_dir, &tsd, slot); if(err) return err; if(tsd.sfd_ino == child_dir->sv_ino) break; slot++; } /* * Doesn't make sense if we don't find our directory listed in our * parent directory.. */ assert(slot < nentries); strcpy(to_add, tsd.sfd_name); strcat(to_add, "/"); strcat(to_add, pathname); strcpy(pathname, to_add); VOP_DECREF(&child_dir->sv_v); if(parent_dir->sv_ino == SFS_ROOT_LOCATION){ VOP_DECREF(&parent_dir->sv_v); break; } else child_dir = parent_dir; } err = uiomove(pathname, strlen(pathname) + 1, uio); if(err) return err; return 0; }
/* * Create a new thread based on an existing one. * The new threaD has name NAME, and starts executing in function FUNC. * DATA1 and DATA2 are passed to FUNC. */ int thread_fork(const char *name, void *data1, unsigned long data2, void (*func)(void *, unsigned long), struct thread **ret) { struct thread *newguy; int s, result; /* Allocate a thread */ newguy = thread_create(name); if (newguy==NULL) { return ENOMEM; } /* Allocate a stack */ newguy->t_stack = kmalloc(STACK_SIZE); if (newguy->t_stack==NULL) { kfree(newguy->t_name); kfree(newguy); return ENOMEM; } /* stick a magic number on the bottom end of the stack */ newguy->t_stack[0] = 0xae; newguy->t_stack[1] = 0x11; newguy->t_stack[2] = 0xda; newguy->t_stack[3] = 0x33; /* Inherit the current directory */ if (curthread->t_cwd != NULL) { VOP_INCREF(curthread->t_cwd); newguy->t_cwd = curthread->t_cwd; } /* Set up the pcb (this arranges for func to be called) */ md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func); /* Interrupts off for atomicity */ s = splhigh(); /* * Make sure our data structures have enough space, so we won't * run out later at an inconvenient time. */ result = array_preallocate(sleepers, numthreads+1); if (result) { goto fail; } result = array_preallocate(zombies, numthreads+1); if (result) { goto fail; } /* Do the same for the scheduler. */ result = scheduler_preallocate(numthreads+1); if (result) { goto fail; } /* Make the new thread runnable */ result = make_runnable(newguy); if (result != 0) { goto fail; } /* * Increment the thread counter. This must be done atomically * with the preallocate calls; otherwise the count can be * temporarily too low, which would obviate its reason for * existence. */ numthreads++; //The child's Parent PID (curthread->pid) is stored in its PPID newguy->parent_pid = curthread->pid; struct pid_node *temp; struct pid_node *temp2; temp = find_node(curthread->pid); //return the pid_node of the parent. temp2 = find_node(newguy->pid); //return the pid_node of the forked child. if (temp->next_children == NULL) //this means that the parent has no children. { temp->next_children = temp2; } else{ //HAS CHILDREN. temp = temp->next_children; while (temp->next_siblings != NULL){ temp = temp->next_siblings; } temp->next_siblings = temp2; } /* Done with stuff that needs to be atomic */ splx(s); /* * Return new thread structure if it's wanted. Note that * using the thread structure from the parent thread should be * done only with caution, because in general the child thread * might exit at any time. */ if (ret != NULL) { *ret = newguy; } return 0; fail: splx(s); if (newguy->t_cwd != NULL) { VOP_DECREF(newguy->t_cwd); } kfree(newguy->t_stack); kfree(newguy->t_name); kfree(newguy); return result; }
/* * Get the full pathname for a file. This only needs to work on directories. * * Locking: Gets/releases vnode locks, but only one at a time. * * Requires up to 3 buffers. */ static int sfs_namefile(struct vnode *vv, struct uio *uio) { struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *parent = NULL; int result; char *buf; size_t bufpos, bufmax, len; KASSERT(uio->uio_rw == UIO_READ); bufmax = uio->uio_resid+1; if (bufmax > PATH_MAX) { bufmax = PATH_MAX; } buf = kmalloc(bufmax); if (buf == NULL) { return ENOMEM; } reserve_buffers(SFS_BLOCKSIZE); bufpos = bufmax; VOP_INCREF(&sv->sv_absvn); while (1) { lock_acquire(sv->sv_lock); /* not allowed to lock child since we're going up the tree */ result = sfs_lookonce(sv, "..", &parent, NULL); lock_release(sv->sv_lock); if (result) { VOP_DECREF(&sv->sv_absvn); kfree(buf); unreserve_buffers(SFS_BLOCKSIZE); return result; } if (parent == sv) { /* .. was equal to . - must be root, so we're done */ VOP_DECREF(&parent->sv_absvn); VOP_DECREF(&sv->sv_absvn); break; } lock_acquire(parent->sv_lock); result = sfs_getonename(parent, sv->sv_ino, buf, &bufpos); lock_release(parent->sv_lock); if (result) { VOP_DECREF(&parent->sv_absvn); VOP_DECREF(&sv->sv_absvn); kfree(buf); unreserve_buffers(SFS_BLOCKSIZE); return result; } VOP_DECREF(&sv->sv_absvn); sv = parent; parent = NULL; } /* Done looking, now send back the string */ if (bufmax == bufpos) { /* root directory; do nothing (send back empty string) */ result = 0; } else { len = bufmax - bufpos; len--; /* skip the trailing slash */ KASSERT(len <= uio->uio_resid); result = uiomove(buf+bufpos, len, uio); } kfree(buf); unreserve_buffers(SFS_BLOCKSIZE); return result; }
/* * Create a fresh proc for use by runprogram. * * It will have no address space and will inherit the current * process's (that is, the kernel menu's) current directory. */ struct proc * proc_create_runprogram(const char *name) { struct proc *proc; char *console_path; proc = proc_create(name); if (proc == NULL) { return NULL; } #ifdef UW /* open the console - this should always succeed */ console_path = kstrdup("con:"); if (console_path == NULL) { panic("unable to copy console path name during process creation\n"); } if (vfs_open(console_path,O_WRONLY,0,&(proc->console))) { panic("unable to open the console during process creation\n"); } #if OPT_A2 //first 3 file descriptors are always stdin, stdout, and stderr, which all point to the console int result; struct vnode* stdinvnode; console_path = kstrdup("con:"); result = vfs_open(console_path,O_RDWR,0,&(stdinvnode)); struct file* stdin; stdin = initfile(stdinvnode, O_RDWR, "stdin"); KASSERT(stdin != NULL); KASSERT(result == 0); struct vnode* stdoutvnode; console_path = kstrdup("con:"); result = vfs_open(console_path,O_RDWR,0,&(stdoutvnode)); struct file* stdout; stdout = initfile(stdoutvnode, O_RDWR, "stdout"); KASSERT(stdout != NULL); KASSERT(result == 0); struct vnode* stderrvnode; console_path = kstrdup("con:"); result = vfs_open(console_path,O_RDWR,0,&(stderrvnode)); struct file* stderr; stderr = initfile(stderrvnode, O_RDWR, "stderr"); KASSERT(stderr != NULL); KASSERT(result == 0); kfree(console_path); array_set(proc->filetable, 0, stdin); array_set(proc->filetable, 1, stdout); array_set(proc->filetable, 2, stderr); #endif #endif // UW /* VM fields */ proc->p_addrspace = NULL; /* VFS fields */ #ifdef UW /* we do not need to acquire the p_lock here, the running thread should have the only reference to this process */ /* also, acquiring the p_lock is problematic because VOP_INCREF may block */ if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } #else // UW spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); #endif // UW #ifdef UW /* increment the count of processes */ /* we are assuming that all procs, including those created by fork(), are created using a call to proc_create_runprogram */ P(proc_count_mutex); proc_count++; V(proc_count_mutex); #endif // UW return proc; }