/* * See the comment in vnode.h for what is expected of this function. * * This function is similar to s5fs_create, but it creates a special * file specified by 'devid'. * * You probably want to use s5_alloc_inode, s5_link(), vget(), and vput(). */ static int s5fs_mknod(vnode_t *dir, const char *name, size_t namelen, int mode, devid_t devid) { KASSERT(namelen < NAME_LEN); kmutex_lock(&dir->vn_mutex); fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs; int ino; if (S_ISCHR(mode)){ ino = s5_alloc_inode(fs, S5_TYPE_CHR, devid); } else if (S_ISBLK(mode)){ ino = s5_alloc_inode(fs, S5_TYPE_BLK, devid); } else { panic("invalid mode"); } if (ino < 0){ dbg(DBG_S5FS, "unable to alloc a new inode\n"); kmutex_unlock(&dir->vn_mutex); return ino; } vnode_t *child = vget(fs, ino); kmutex_lock(&child->vn_mutex); /* make sure the state of the new vnode is correct */ assert_new_vnode_state(child, ino, S_ISCHR(mode) ? S5_TYPE_CHR : S5_TYPE_BLK, devid); int link_res = s5_link(dir, child, name, namelen); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n"); vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); /*s5_free_inode(child);*/ return link_res; } vput(child); KASSERT(child->vn_refcount == 0); KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 1); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return 0; }
/* * s5fs_create: * s5fs_create is called by open_namev(). it should vget() a new vnode, * and create an entry for this vnode in 'dir' of the specified name. * param *dir: * param name: the name string * param namelen: the length of the name * param **result: pointer to the address of the result vnode * return: 0 on success; negative number on a variety of errors */ static int s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result) { dbg(DBG_S5FS, "{\n"); KASSERT(dir != NULL); KASSERT(name != NULL); KASSERT(namelen <= NAME_LEN-1); vnode_t* vn = NULL; /* Must be non-exist */ KASSERT(0 != s5fs_lookup(dir, name, namelen, result)); /* Lock base */ kmutex_lock(&dir->vn_mutex); int ino; if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_DATA, 0)) < 0) { /* Unsuccessfull*/ kmutex_unlock(&dir->vn_mutex); return ino; } /* May block here */ vn = vget(dir->vn_fs, (ino_t)ino); KASSERT(vn->vn_vno == (ino_t)ino); KASSERT(vn != NULL); int ret = 0; if ((ret = s5_link(dir, vn, name, namelen)) < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return ret; } KASSERT(VNODE_TO_S5INODE(vn)->s5_linkcount == 2); KASSERT(vn->vn_refcount == 1); *result = vn; kmutex_unlock(&dir->vn_mutex); dbg(DBG_S5FS, "}\n"); return 0; }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount of the file should be 2 * and the vnode refcount should be 1. * * You probably want to use s5_alloc_inode(), s5_link(), and vget(). */ static int s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result) { KASSERT(namelen < NAME_LEN); kmutex_lock(&dir->vn_mutex); fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs; int ino = s5_alloc_inode(fs, S5_TYPE_DATA, NULL); if (ino < 0){ dbg(DBG_S5FS, "unable to alloc a new inode\n"); kmutex_unlock(&dir->vn_mutex); return ino; } vnode_t *child = vget(fs, ino); kmutex_lock(&child->vn_mutex); /* make sure the state of the new vnode is correct */ assert_new_vnode_state(child, ino, S5_TYPE_DATA, 0); int link_res = s5_link(dir, child, name, namelen); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n"); vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); /*s5_free_inode(child);*/ return link_res; } KASSERT(child->vn_refcount == 1); KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 2); *result = child; kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return 0; }
/* * s5fs_mkdir: * s5fs_mkdir creates a directory called name in dir * param *dir: the pointer to the vnode object of the parent directory * param *name: the name string * param namelen: the length of the name * return: 0 on success; negative number on a variety of errors */ static int s5fs_mkdir(vnode_t *dir, const char *name, size_t namelen) { dbg(DBG_S5FS, "{\n"); KASSERT(dir != NULL); KASSERT(name != NULL); KASSERT(namelen <= NAME_LEN-1); vnode_t* result = NULL; /* Must be non-exist */ KASSERT(s5fs_lookup(dir, name, namelen, &result) < 0); /* Lock */ kmutex_lock(&dir->vn_mutex); s5_inode_t* dir_inode = VNODE_TO_S5INODE(dir); int parent_link = dir_inode->s5_linkcount; int ino = 0; /* Allocate an inode */ if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_DIR, 0)) < 0) { /* Unsuccess */ kmutex_unlock(&dir->vn_mutex); return ino; } /* May block here */ vnode_t* vn = vget(dir->vn_fs, ino); KASSERT(vn != NULL); int ret = 0; ret = s5_link(dir, vn, name, namelen); if (ret < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return -1; } s5_inode_t* inode = VNODE_TO_S5INODE(vn); ret = s5_link(vn, vn, ".", 1); if (ret < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return -1; } int a = inode->s5_direct_blocks[0]; ret = s5_link(vn, dir, "..", 2); if (ret < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return -1; } int b = inode->s5_direct_blocks[0]; if (a != b) { KASSERT(0); b = a; } KASSERT(inode->s5_linkcount == 2); /* one is VFS, one is from the parent */ /* Not clear */ KASSERT(parent_link + 1 == dir_inode->s5_linkcount); /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); KASSERT(ret == 0); dbg(DBG_S5FS, "}\n"); return ret; }
/* * s5fs_mknod: * s5fs_mknod creates a special file for the device specified by * 'devid' and an entry for it in 'dir' of the specified name. * param dir: the pointer to the * param name: the name string * param namelen: the length of the name string * param mode: device mode * param devid: device id * return: 0 on success; negative number on a variety of errors */ static int s5fs_mknod(vnode_t *dir, const char *name, size_t namelen, int mode, devid_t devid) { dbg(DBG_S5FS, "{\n"); KASSERT(S_ISCHR(mode) || S_ISBLK(mode)); KASSERT(namelen <= S5_NAME_LEN-1); KASSERT(name != NULL); KASSERT(dir != NULL); vnode_t* vn = NULL; /* Must be non-exist */ vnode_t* result = NULL; KASSERT(0 != s5fs_lookup(dir, name, namelen, &result)); /* lock */ kmutex_lock(&dir->vn_mutex); int ino = 0; if (S_ISCHR(mode)) { if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_CHR, devid)) < 0) { /* Unsuccessfull*/ kmutex_unlock(&dir->vn_mutex); return ino; } }else if (S_ISBLK(mode)) { if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_BLK, devid)) < 0) { /* Unsuccessfull*/ kmutex_unlock(&dir->vn_mutex); return ino; } } else { panic("Impossible to get here!"); } /* May block here */ vn = vget(dir->vn_fs, (ino_t)ino); KASSERT(vn != NULL); KASSERT(vn->vn_vno == (ino_t)ino); int ret = 0; if ((ret = s5_link(dir, vn, name, namelen)) < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return ret; } /* new vnode */ KASSERT(vn->vn_refcount == 1); /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); dbg(DBG_S5FS, "}\n"); return 0; }
/* * See the comment in vnode.h for what is expected of this function. * * You need to create the "." and ".." directory entries in the new * directory. These are simply links to the new directory and its * parent. * * When this function returns, the inode refcount on the parent should * be incremented, and the inode refcount on the new directory should be * 1. It might make more sense for the inode refcount on the new * directory to be 2 (since "." refers to it as well as its entry in the * parent dir), but convention is that empty directories have only 1 * link. * * You probably want to use s5_alloc_inode, and s5_link(). * * Assert, a lot. */ static int s5fs_mkdir(vnode_t *dir, const char *name, size_t namelen) { static const char *dotstring = "."; static const char *dotdotstring = ".."; KASSERT(namelen < NAME_LEN); KASSERT(dir->vn_ops->mkdir != NULL); kmutex_lock(&dir->vn_mutex); fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs; int ino = s5_alloc_inode(fs, S5_TYPE_DIR, NULL); if (ino < 0){ dbg(DBG_S5FS, "unable to alloc a new inode\n"); kmutex_unlock(&dir->vn_mutex); return ino; } vnode_t *child = vget(fs, ino); kmutex_lock(&child->vn_mutex); /* make sure the state of the new vnode is correct */ assert_new_vnode_state(child, ino, S5_TYPE_DIR, 0); int link_res = s5_link(child, child, dotstring, 1); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for \'.\' in new directory\n"); /* TODO make sure we should be vputting */ /*s5_free_inode(child);*/ vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return link_res; } KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 1); link_res = s5_link(child, dir, dotdotstring, 2); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for \'..\' in new directory\n"); /*s5_free_inode(child);*/ vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return link_res; } link_res = s5_link(dir, child, name, namelen); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n"); /*s5_free_inode(child);*/ vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return link_res; } KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 2); vput(child); KASSERT(child->vn_refcount - child->vn_nrespages == 0); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return 0; }