/* Does most of the work for link(). */ int vfs_link(char *oldpath, char *newpath) { struct vnode *oldfile; struct vnode *newdir; char newname[NAME_MAX+1]; int result; result = vfs_lookup(oldpath, &oldfile); if (result) { return result; } result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname)); if (result) { VOP_DECREF(oldfile); return result; } if (oldfile->vn_fs==NULL || newdir->vn_fs==NULL || oldfile->vn_fs != newdir->vn_fs) { VOP_DECREF(newdir); VOP_DECREF(oldfile); return EXDEV; } result = VOP_LINK(newdir, newname, oldfile); VOP_DECREF(newdir); VOP_DECREF(oldfile); return result; }
/* * 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; }
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; }
/* * 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; }
/* * Delete a file. */ static int sfs_remove(struct vnode *dir, const char *name) { struct sfs_vnode *sv = dir->vn_data; struct sfs_vnode *victim; int slot; int result; /* Look for the file and fetch a vnode for it. */ result = sfs_lookonce(sv, name, &victim, &slot); if (result) { return result; } /* Erase its directory entry. */ result = sfs_dir_unlink(sv, slot); if (result==0) { /* If we succeeded, decrement the link count. */ assert(victim->sv_i.sfi_linkcount > 0); victim->sv_i.sfi_linkcount--; victim->sv_dirty = 1; } /* Discard the reference that sfs_lookonce got us */ VOP_DECREF(&victim->sv_v); return result; }
/** * close the file given by the descriptor */ int file_close_descriptor( struct proc *p, int fd ) { struct file *f = NULL; int err = 0; err = file_get( p, fd, &f ); if( err ) return err; //make sure there are programs using it KASSERT( f->f_refcount > 0 ); //detach from the file descriptor table fd_detach( p->p_fd, fd ); //decrease both refcounts f->f_refcount--; VOP_DECREF( f->f_vnode ); //destroy if we are the only ones using it if( f->f_refcount == 0 ) { F_UNLOCK( f ); file_destroy( f ); return 0; } //unlock the file F_UNLOCK( f ); return 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; }
/* Setup . and .. in root directory if this is the first mount */ int sfs_setup_root(struct sfs_fs *sfs) { struct fs *fs = &sfs->sfs_absfs; struct vnode *root_vv; struct sfs_vnode *root_sv; int result; root_vv = sfs_getroot(fs); root_sv = root_vv->vn_data; if(sfs_dir_nentries(root_sv) != 0){ VOP_DECREF(root_vv); return 0; } result = sfs_dir_link(root_sv, ".", SFS_ROOT_LOCATION, NULL); if (result) { VOP_DECREF(root_vv); return result; } root_sv->sv_i.sfi_linkcount++; root_sv->sv_dirty = 1; result = sfs_dir_link(root_sv, "..", SFS_ROOT_LOCATION, NULL); if (result) { sfs_dir_unlink(root_sv, 0); /* Hope this doesn't fail?? */ root_sv->sv_i.sfi_linkcount--; root_sv->sv_dirty = 1; VOP_DECREF(root_vv); return result; } root_sv->sv_i.sfi_linkcount++; root_sv->sv_dirty = 1; /* Decrement reference that sfs_getroot incremented */ VOP_DECREF(root_vv); return 0; }
/* * Cause the current thread to exit. * * We clean up the parts of the thread structure we don't actually * need to run right away. The rest has to wait until thread_destroy * gets called from exorcise(). */ void thread_exit(int exitcode) { DEBUG(DB_THREADS,"Thread %s exiting with %d", curthread->t_name, exitcode); /* ASST1: Let the pid management system know this thread is done. */ pid_setexited(curthread->t_pid, exitcode); if (curthread->t_stack != NULL) { /* * Check the magic number we put on the bottom end of * the stack in thread_fork. If these assertions go * off, it most likely means you overflowed your stack * at some point, which can cause all kinds of * mysterious other things to happen. */ assert(curthread->t_stack[0] == (char)0xae); assert(curthread->t_stack[1] == (char)0x11); assert(curthread->t_stack[2] == (char)0xda); assert(curthread->t_stack[3] == (char)0x33); } splhigh(); if (curthread->t_vmspace) { /* * Do this carefully to avoid race condition with * context switch code. */ struct addrspace *as = curthread->t_vmspace; curthread->t_vmspace = NULL; as_destroy(as); } if (curthread->t_cwd) { VOP_DECREF(curthread->t_cwd); curthread->t_cwd = NULL; } /* A3 SETUP */ if (curthread->t_filetable) { filetable_destroy(curthread->t_filetable); /* set it back to NULL so it can be initialized again */ curthread->t_filetable = NULL; } /* END A3 SETUP */ assert(numthreads>0); numthreads--; mi_switch(S_ZOMB); panic("Thread came back from the dead!\n"); }
/* * Create a file. If EXCL is set, insist that the filename not already * exist; otherwise, if it already exists, just open it. */ static int sfs_creat(struct vnode *v, const char *name, int excl, struct vnode **ret) { struct sfs_fs *sfs = v->vn_fs->fs_data; struct sfs_vnode *sv = v->vn_data; struct sfs_vnode *newguy; u_int32_t ino; int result; /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { return result; } /* If it exists and we didn't want it to, fail */ if (result==0 && excl) { return EEXIST; } if (result==0) { /* We got a file; load its vnode and return */ result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy); if (result) { return result; } *ret = &newguy->sv_v; return 0; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy); if (result) { return result; } /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); if (result) { VOP_DECREF(&newguy->sv_v); return result; } /* Update the linkcount of the new file */ newguy->sv_i.sfi_linkcount++; /* and consequently mark it dirty. */ newguy->sv_dirty = 1; *ret = &newguy->sv_v; return 0; }
/* * Cause the current thread to exit. * * We clean up the parts of the thread structure we don't actually * need to run right away. The rest has to wait until thread_destroy * gets called from exorcise(). */ void thread_exit(void) { if (curthread->t_stack != NULL) { /* * Check the magic number we put on the bottom end of * the stack in thread_fork. If these assertions go * off, it most likely means you overflowed your stack * at some point, which can cause all kinds of * mysterious other things to happen. */ assert(curthread->t_stack[0] == (char)0xae); assert(curthread->t_stack[1] == (char)0x11); assert(curthread->t_stack[2] == (char)0xda); assert(curthread->t_stack[3] == (char)0x33); } #if OPT_A2 vfs_close(curthread->ft[0]->file); vfs_close(curthread->ft[1]->file); vfs_close(curthread->ft[2]->file); #endif splhigh(); if (curthread->t_vmspace) { /* * Do this carefully to avoid race condition with * context switch code. */ struct addrspace *as = curthread->t_vmspace; curthread->t_vmspace = NULL; as_destroy(as); } if (curthread->t_cwd) { VOP_DECREF(curthread->t_cwd); curthread->t_cwd = NULL; } assert(numthreads>0); numthreads--; /* #if OPT_A2 struct process* current = p_table[curthread->pid]; if (current->ppid != -1){ struct process* parent = p_table[current->ppid]; if (parent->waiting) cv_broadcast(parent->exit,parent->exitlock); } #endif */ mi_switch(S_ZOMB); panic("Thread came back from the dead!\n"); }
/* * Destroy a proc structure. * * Note: nothing currently calls this. Your wait/exit code will * probably want to do so. */ void proc_destroy(struct proc *proc) { /* * You probably want to destroy and null out much of the * process (particularly the address space) at exit time if * your wait/exit design calls for the process structure to * hang around beyond process exit. Some wait/exit designs * do, some don't. */ KASSERT(proc != NULL); KASSERT(proc != kproc); /* * We don't take p_lock in here because we must have the only * reference to this structure. (Otherwise it would be * incorrect to destroy it.) */ /* VFS fields */ if (proc->p_cwd) { VOP_DECREF(proc->p_cwd); proc->p_cwd = NULL; } /* VM fields */ if (proc->p_addrspace) { /* * In case p is the currently running process (which * it might be in some circumstances, or if this code * gets moved into exit as suggested above), clear * p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ struct addrspace *as; as_deactivate(); as = curproc_setas(NULL); as_destroy(as); } threadarray_cleanup(&proc->p_threads); spinlock_cleanup(&proc->p_lock); kfree(proc->p_name); kfree(proc); }
/* * Set current directory, as a pathname. Use vfs_lookup to translate * it to a vnode. */ int vfs_chdir(char *path) { struct vnode *vn; int result; result = vfs_lookup(path, &vn); if (result) { return result; } result = vfs_setcurdir(vn); VOP_DECREF(vn); return result; }
/* * Set current directory to "none". */ int vfs_clearcurdir(void) { struct vnode *old; spinlock_acquire(&curproc->p_lock); old = curproc->p_cwd; curproc->p_cwd = NULL; spinlock_release(&curproc->p_lock); if (old!=NULL) { VOP_DECREF(old); } return 0; }
/* * Does most of the work for symlink(). * * Note, however, if you're implementing symlinks, that various * other parts of the VFS layer are missing crucial elements of * support for symlinks. */ int vfs_symlink(const char *contents, char *path) { struct vnode *newdir; char newname[NAME_MAX+1]; int result; result = vfs_lookparent(path, &newdir, newname, sizeof(newname)); if (result) { return result; } result = VOP_SYMLINK(newdir, newname, contents); VOP_DECREF(newdir); return result; }
/* * Does most of the work for readlink(). * * Note, however, if you're implementing symlinks, that various * other parts of the VFS layer are missing crucial elements of * support for symlinks. */ int vfs_readlink(char *path, struct uio *uio) { struct vnode *vn; int result; result = vfs_lookup(path, &vn); if (result) { return result; } result = VOP_READLINK(vn, uio); VOP_DECREF(vn); return result; }
/* Does most of the work for remove(). */ int vfs_remove(char *path) { struct vnode *dir; char name[NAME_MAX+1]; int result; result = vfs_lookparent(path, &dir, name, sizeof(name)); if (result) { return result; } result = VOP_REMOVE(dir, name); VOP_DECREF(dir); return result; }
/* * Cause the current thread to exit. * * We clean up the parts of the thread structure we don't actually * need to run right away. The rest has to wait until thread_destroy * gets called from exorcise(). */ void thread_exit(void) { if (curthread->t_stack != NULL) { /* * Check the magic number we put on the bottom end of * the stack in thread_fork. If these assertions go * off, it most likely means you overflowed your stack * at some point, which can cause all kinds of * mysterious other things to happen. */ assert(curthread->t_stack[0] == (char)0xae); assert(curthread->t_stack[1] == (char)0x11); assert(curthread->t_stack[2] == (char)0xda); assert(curthread->t_stack[3] == (char)0x33); } splhigh(); if (curthread->t_vmspace) { /* * Do this carefully to avoid race condition with * context switch code. */ struct addrspace *as = curthread->t_vmspace; curthread->t_vmspace = NULL; as_destroy(as); } if (curthread->t_cwd) { VOP_DECREF(curthread->t_cwd); curthread->t_cwd = NULL; } if(curthread->ft) { delete_process_filetable(curthread->ft); curthread->ft = NULL; } assert(numthreads>0); numthreads--; mi_switch(S_ZOMB); panic("Thread came back from the dead!\n"); }
/* * Does most of the work for rmdir. */ int vfs_rmdir(char *path) { struct vnode *parent; char name[NAME_MAX+1]; int result; result = vfs_lookparent(path, &parent, name, sizeof(name)); if (result) { return result; } result = VOP_RMDIR(parent, name); VOP_DECREF(parent); return result; }
/* Does most of the work for close(). */ void vfs_close(struct vnode *vn) { /* * VOP_DECOPEN and VOP_DECREF don't return errors. * * We assume that the file system makes every reasonable * effort to not fail. If it does fail - such as on a hard I/O * error or something - vnode.c prints a warning. The reason * we don't report errors up to or above this level is that * (1) most application software does not check for close * failing, and more importantly * (2) we're often called from places like process exit * where reporting the error is impossible and * meaningful recovery is entirely impractical. */ VOP_DECOPEN(vn); VOP_DECREF(vn); }
/* * Routine for "mounting" an emufs - we're not really mounted in the * sense that the VFS understands that term, because we're not * connected to a block device. * * Basically, we just add ourselves to the name list in the VFS layer. */ static int emufs_addtovfs(struct emu_softc *sc, const char *devname) { struct emufs_fs *ef; int result; ef = kmalloc(sizeof(struct emufs_fs)); if (ef==NULL) { return ENOMEM; } ef->ef_fs.fs_sync = emufs_sync; ef->ef_fs.fs_getvolname = emufs_getvolname; ef->ef_fs.fs_getroot = emufs_getroot; ef->ef_fs.fs_unmount = emufs_unmount; ef->ef_fs.fs_data = ef; ef->ef_emu = sc; ef->ef_root = NULL; ef->ef_vnodes = vnodearray_create(); if (ef->ef_vnodes == NULL) { kfree(ef); return ENOMEM; } result = emufs_loadvnode(ef, EMU_ROOTHANDLE, 1, &ef->ef_root); if (result) { kfree(ef); return result; } KASSERT(ef->ef_root!=NULL); result = vfs_addfs(devname, &ef->ef_fs); if (result) { VOP_DECREF(&ef->ef_root->ev_v); kfree(ef); } return result; }
/* * Get current directory, as a pathname. * Use VOP_NAMEFILE to get the pathname and FSOP_GETVOLNAME to get the * volume name. */ int vfs_getcwd(struct uio *uio) { struct vnode *cwd; int result; const char *name; char colon=':'; KASSERT(uio->uio_rw==UIO_READ); result = vfs_getcurdir(&cwd); if (result) { return result; } /* The current dir must be a directory, and thus it is not a device. */ KASSERT(cwd->vn_fs != NULL); name = FSOP_GETVOLNAME(cwd->vn_fs); if (name==NULL) { name = vfs_getdevname(cwd->vn_fs); } KASSERT(name != NULL); result = uiomove((char *)name, strlen(name), uio); if (result) { goto out; } result = uiomove(&colon, 1, uio); if (result) { goto out; } result = VOP_NAMEFILE(cwd, uio); out: VOP_DECREF(cwd); return result; }
/* * Lookup gets a vnode for a pathname. * * Locking: gets the vnode lock while calling sfs_lookonce. Doesn't * lock the new vnode, but does hand back a reference to it (so it * won't evaporate). * * Requires up to 3 buffers. */ static int sfs_lookup(struct vnode *v, char *path, struct vnode **ret) { struct sfs_vnode *sv = v->vn_data; struct vnode *dirv; struct sfs_vnode *dir; struct sfs_vnode *final; int result; char name[SFS_NAMELEN]; reserve_buffers(SFS_BLOCKSIZE); result = sfs_lookparent_internal(&sv->sv_absvn, path, &dirv, name, sizeof(name)); if (result) { unreserve_buffers(SFS_BLOCKSIZE); return result; } dir = dirv->vn_data; lock_acquire(dir->sv_lock); result = sfs_lookonce(dir, name, &final, NULL); lock_release(dir->sv_lock); VOP_DECREF(dirv); if (result) { unreserve_buffers(SFS_BLOCKSIZE); return result; } *ret = &final->sv_absvn; unreserve_buffers(SFS_BLOCKSIZE); return 0; }
static int sfs_rmdir(struct vnode *vv, const char *name){ struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *victim; struct sfs_dir tsd; int slot, slot2, nentries; int result; /* Look for the directory and fetch a vnode for it. */ result = sfs_lookonce(sv, name, &victim, &slot); if (result) { return result; } /* Make sure it's a directory and that only . and .. are left */ if(victim->sv_i.sfi_type != SFS_TYPE_DIR){ VOP_DECREF(&victim->sv_v); return ENOTDIR; } nentries = sfs_dir_nentries(victim); if(nentries != 2){ slot2 = 2; while(slot2 < nentries){ /* Ensure all other entries are blank */ result = sfs_readdir(victim, &tsd, slot2); if(result){ VOP_DECREF(&victim->sv_v); return result; } if(tsd.sfd_ino != SFS_NOINO){ VOP_DECREF(&victim->sv_v); return ENOTEMPTY; } slot2++; } } /* Get rid of . and .. (should always be in slot 0 and 1) */ result = sfs_dir_unlink(victim, 0); if(result){ VOP_DECREF(&victim->sv_v); return result; } assert(victim->sv_i.sfi_linkcount > 0); victim->sv_i.sfi_linkcount--; victim->sv_dirty = 1; result = sfs_dir_unlink(victim, 1); if(result){ VOP_DECREF(&victim->sv_v); return result; } assert(sv->sv_i.sfi_linkcount > 0); sv->sv_i.sfi_linkcount--; sv->sv_dirty = 1; /* Erase its directory entry. */ result = sfs_dir_unlink(sv, slot); if (result==0) { /* If we succeeded, decrement the link count. */ assert(victim->sv_i.sfi_linkcount > 0); victim->sv_i.sfi_linkcount--; victim->sv_dirty = 1; } /* Discard the reference that sfs_lookonce got us */ VOP_DECREF(&victim->sv_v); return result; }
static int sfs_mkdir(struct vnode *vv, const char *name){ struct sfs_fs *sfs = vv->vn_fs->fs_data; struct sfs_vnode *sv = vv->vn_data; struct sfs_vnode *newguy; u_int32_t ino; int result, result2, slot1, slot2; /* Look up the name */ result = sfs_dir_findname(sv, name, &ino, NULL, NULL); if (result!=0 && result!=ENOENT) { return result; } if (result==0) { /* Directory or file of same name already exists */ return EINVAL; } /* Didn't exist - create it */ result = sfs_makeobj(sfs, SFS_TYPE_DIR, &newguy); if (result) { return result; } /* Link it into the directory */ result = sfs_dir_link(sv, name, newguy->sv_ino, &slot1); if (result) { VOP_DECREF(&newguy->sv_v); return result; } /* Increment linkcount of the new directory and mark it dirty */ newguy->sv_i.sfi_linkcount++; newguy->sv_dirty = 1; /* Link . and .. into our directory */ result = sfs_dir_link(newguy, ".", newguy->sv_ino, &slot2); if (result) { result2 = sfs_dir_unlink(sv, slot1); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return result; } newguy->sv_i.sfi_linkcount++; newguy->sv_dirty = 1; result = sfs_dir_link(newguy, "..", sv->sv_ino, NULL); if (result) { result2 = sfs_dir_unlink(newguy, slot2); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; result2 = sfs_dir_unlink(sv, slot1); if(result2){ VOP_DECREF(&newguy->sv_v); return result2; } newguy->sv_i.sfi_linkcount--; newguy->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return result; } sv->sv_i.sfi_linkcount++; sv->sv_dirty = 1; VOP_DECREF(&newguy->sv_v); return 0; }
/* * Rename a file. */ static int sfs_rename(struct vnode *d1, const char *n1, struct vnode *d2, const char *n2) { struct sfs_vnode *sv1 = d1->vn_data; struct sfs_vnode *sv2 = d2->vn_data; struct sfs_vnode *g1; int slot1, slot2; int result, result2; /* Look up the old name of the file and get its inode and slot number*/ result = sfs_lookonce(sv1, n1, &g1, &slot1); if (result) { return result; } /* * Link it to the 'new' directory under the new name. * * We could theoretically just overwrite the original * directory entry, except that we need to check to make sure * the new name doesn't already exist; might as well use the * existing link routine. */ result = sfs_dir_link(sv2, n2, g1->sv_ino, &slot2); if (result) { goto puke; } /* Increment the link count, and mark inode dirty */ g1->sv_i.sfi_linkcount++; g1->sv_dirty = 1; /* Unlink the old slot */ result = sfs_dir_unlink(sv1, slot1); if (result) { goto puke_harder; } /* * Decrement the link count again, and mark the inode dirty again, * in case it's been synced behind our back. */ assert(g1->sv_i.sfi_linkcount>0); g1->sv_i.sfi_linkcount--; g1->sv_dirty = 1; /* Let go of the reference to g1 */ VOP_DECREF(&g1->sv_v); return 0; puke_harder: /* * Error recovery: try to undo what we already did */ result2 = sfs_dir_unlink(sv2, slot2); if (result2) { kprintf("sfs: rename: %s\n", strerror(result)); kprintf("sfs: rename: while cleaning up: %s\n", strerror(result2)); panic("sfs: rename: Cannot recover\n"); } g1->sv_i.sfi_linkcount--; puke: /* Let go of the reference to g1 */ VOP_DECREF(&g1->sv_v); return result; }
/* * 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), 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; }
/* * Delete a file. * * Locking: locks the directory, then the file. Unlocks both. * This follows the hierarchical locking order imposed by the directory tree. * * Requires up to 4 buffers. */ static int sfs_remove(struct vnode *dir, const char *name) { struct sfs_vnode *sv = dir->vn_data; struct sfs_vnode *victim; struct sfs_dinode *victim_inodeptr; struct sfs_dinode *dir_inodeptr; int slot; int result; /* need to check this to avoid deadlock even in error condition */ if (!strcmp(name, ".") || !strcmp(name, "..")) { return EISDIR; } lock_acquire(sv->sv_lock); reserve_buffers(SFS_BLOCKSIZE); result = sfs_dinode_load(sv); if (result) { goto out_buffers; } dir_inodeptr = sfs_dinode_map(sv); if (dir_inodeptr->sfi_linkcount == 0) { result = ENOENT; goto out_loadsv; } /* Look for the file and fetch a vnode for it. */ result = sfs_lookonce(sv, name, &victim, &slot); if (result) { goto out_loadsv; } lock_acquire(victim->sv_lock); result = sfs_dinode_load(victim); if (result) { lock_release(victim->sv_lock); VOP_DECREF(&victim->sv_absvn); goto out_loadsv; } victim_inodeptr = sfs_dinode_map(victim); KASSERT(victim_inodeptr->sfi_linkcount > 0); /* Not allowed on directories */ if (victim_inodeptr->sfi_type == SFS_TYPE_DIR) { result = EISDIR; goto out_reference; } /* Erase its directory entry. */ result = sfs_dir_unlink(sv, slot); if (result) { goto out_reference; } /* Decrement the link count. */ KASSERT(victim_inodeptr->sfi_linkcount > 0); victim_inodeptr->sfi_linkcount--; sfs_dinode_mark_dirty(victim); out_reference: /* Discard the reference that sfs_lookonce got us */ sfs_dinode_unload(victim); lock_release(victim->sv_lock); VOP_DECREF(&victim->sv_absvn); out_loadsv: sfs_dinode_unload(sv); out_buffers: lock_release(sv->sv_lock); unreserve_buffers(SFS_BLOCKSIZE); return result; }
/* * 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; }