diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index 859e53ff..c75426ea 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -1643,7 +1643,7 @@ static int ext2_munmap(vnode_t *node, void *addr, uintmax_t offset, int flags, c } static int handleinodeunlink(ext2fs_t *fs, ext2node_t *node, int inode, ext2node_t *known) { - bool isdir = false; + bool cleanup_parent_dir = false; void *v; MUTEX_ACQUIRE(&fs->inodetablelock); int err = hashtable_get(&fs->inodetable, &v, &inode, sizeof(inode)); @@ -1653,8 +1653,8 @@ static int handleinodeunlink(ext2fs_t *fs, ext2node_t *node, int inode, ext2node err = readinode(fs, &buff, inode); ASSERT_UNCLEAN(fs, err == 0); if (err == 0) { - if (INODE_TYPEPERM_TYPE(buff.typeperm) == INODE_TYPE_DIR) { // account for . entry - isdir = true; + if (INODE_TYPEPERM_TYPE(buff.typeperm) == INODE_TYPE_DIR && buff.links == 2) { // dir cleanup if nlinks == 2 + cleanup_parent_dir = true; buff.links -= 1; } @@ -1681,8 +1681,8 @@ static int handleinodeunlink(ext2fs_t *fs, ext2node_t *node, int inode, ext2node if (known == NULL) VOP_LOCK(&unlinknode->vnode); - if (INODE_TYPEPERM_TYPE(unlinknode->inode.typeperm) == INODE_TYPE_DIR) { // account for . entry - isdir = 1; + if (INODE_TYPEPERM_TYPE(unlinknode->inode.typeperm) == INODE_TYPE_DIR && unlinknode->inode.links == 2) { // cleanup dir if nlinks == 2 + cleanup_parent_dir = true; unlinknode->inode.links -= 1; } @@ -1700,7 +1700,7 @@ static int handleinodeunlink(ext2fs_t *fs, ext2node_t *node, int inode, ext2node } } - if (isdir) { // account for .. entry in unlinked dir + if (cleanup_parent_dir) { // account for .. entry in unlinked dir --node->inode.links; ASSERT_UNCLEAN(fs, writeinode(fs, &node->inode, node->id) == 0); } @@ -1743,7 +1743,7 @@ static int ext2_unlink(vnode_t *vnode, vnode_t *child, char *name, cred_t *cred) ext2node_t *node = (ext2node_t *)vnode; ext2fs_t *fs = (ext2fs_t *)vnode->vfs; - int err = child->type == V_TYPE_DIR ? is_directory_empty(node) : 0; + int err = child->type == V_TYPE_DIR ? is_directory_empty((ext2node_t *)child) : 0; if (err) return err; @@ -1894,14 +1894,18 @@ static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode err = handleinodeunlink(fs, ext2sourcedirnode, inode, (ext2node_t *)ext2sourcenode); ASSERT_UNCLEAN(fs, err == 0); - // handle .. entry when directory - if (source->type == V_TYPE_DIR) { + // handle .. entry when directory and have different parent directoriess + if (source->type == V_TYPE_DIR && ext2sourcedirnode != ext2targetdirnode) { err = findindir(fs, ext2sourcenode, "..", &inode, ext2targetdirnode); ASSERT_UNCLEAN(fs, err == 0); if (err) return err; - // no need to change nlinks, as renaming on a dir is only possible when there was already a dir there + ext2targetdirnode->inode.links += 1; + ASSERT_UNCLEAN(fs, writeinode(fs, &ext2targetdirnode->inode, ext2targetdirnode->id) == 0); + + ext2sourcedirnode->inode.links -= 1; + ASSERT_UNCLEAN(fs, writeinode(fs, &ext2sourcedirnode->inode, ext2sourcedirnode->id) == 0); } return err; diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index bfd57c6a..4d70cc8d 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -117,7 +117,7 @@ static int tmpfs_create(vnode_t *parent, char *name, vattr_t *attr, int type, vn tmpattr.size = 0; tmpattr.type = type; int error = tmpfs_setattr(node, &tmpattr, V_ATTR_ALL, cred); - tmpnode->attr.nlinks = 1; + tmpnode->attr.nlinks = type == V_TYPE_DIR ? 2 : 1; if (error) { VOP_RELEASE(node); @@ -141,8 +141,10 @@ static int tmpfs_create(vnode_t *parent, char *name, vattr_t *attr, int type, vn } // hold the .. reference (done here to reduce cleanup) - if (type == V_TYPE_DIR) + if (type == V_TYPE_DIR) { + parenttmpnode->attr.nlinks += 1; VOP_HOLD(parent); + } node->vfs = parent->vfs; *result = node; @@ -286,6 +288,13 @@ static int tmpfs_unlink(vnode_t *node, vnode_t *child, char *name, cred_t *cred) return err; --unlinktmpnode->attr.nlinks; + + if (child->type == V_TYPE_DIR) { + // undo .. entry link + VOP_RELEASE(node); + --tmpnode->attr.nlinks; + } + VOP_RELEASE(unlinknode); return 0; @@ -375,8 +384,22 @@ static int tmpfs_rename(vnode_t *source, vnode_t *sourcefile, char *oldname, vno // remove old link. should not fail __assert(hashtable_remove(&sourcedir->children, oldname, oldlen) == 0); - if (oldnode) + if (sourcefile->type == V_TYPE_DIR && targetdir != sourcedir) { + tmpfsnode_t *v = (tmpfsnode_t *)sourcefile; + // handle .. entry + __assert(hashtable_set(&v->children, targetdir, "..", 3, false) == 0); + sourcedir->attr.nlinks -= 1; + targetdir->attr.nlinks += 1; + + VOP_RELEASE(source); + VOP_HOLD(target); + } + + if (oldnode) { + tmpfsnode_t *old_tmpnode = (tmpfsnode_t *)oldnode; + --old_tmpnode->attr.nlinks; VOP_RELEASE(oldnode); + } cleanup: return error; @@ -469,10 +492,12 @@ static int tmpfs_getdents(vnode_t *node, dent_t *buffer, size_t count, uintmax_t } static int tmpfs_inactive(vnode_t *node) { + tmpfsnode_t *tmp_node = (tmpfsnode_t *)node; + __assert(tmp_node->attr.nlinks == (node->type == V_TYPE_DIR ? 1 : 0)); if (node->type == V_TYPE_REGULAR) { vmmcache_truncate(node, 0); } - freenode((tmpfsnode_t *)node); + freenode(tmp_node); return 0; } diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index f5712360..6f13bc86 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -440,8 +440,6 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size page_t *page = NULL; if (startoffset) { - if (node->type == V_TYPE_BLKDEV) - arch_e9_puts("1\n"); // unaligned first page err = vmmcache_getpage(node, pageoffset * PAGE_SIZE, &page); if (err) @@ -471,8 +469,6 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size } for (uintmax_t offset = 0; offset < pagecount * PAGE_SIZE; offset += PAGE_SIZE) { - if (node->type == V_TYPE_BLKDEV) - arch_e9_puts("2\n"); // the other pages err = vmmcache_getpage(node, pageoffset * PAGE_SIZE + offset, &page); if (err)