Example #1
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 *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;
}
Example #2
0
File: proc.c Project: BWK/os161
/*
 * 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;
}
Example #3
0
/*
 * 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;
}
Example #4
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);
}
Example #5
0
/*
 * 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;
}
Example #6
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;
}
Example #7
0
/*
 * 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;
}
Example #8
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;
}
Example #9
0
/*
 * 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;
}
Example #11
0
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;
}
Example #12
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;
}
Example #13
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;
}
Example #14
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;
}
Example #15
0
/*
 * 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;
}
Example #16
0
/*
 * 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;
}
Example #17
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;
}
Example #18
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);
	}
}
Example #19
0
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;
}
Example #20
0
/*
 * 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;
}
Example #21
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;
}
Example #23
0
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;
}
Example #24
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;
}
Example #25
0
/*
 * 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;
}
Example #26
0
/*
 * 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;
}
Example #27
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;
}
Example #28
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;
}
Example #29
0
/*
 * 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;
}
Example #30
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 *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;
}