fs: fix some nlinks handling

This commit is contained in:
Matheus
2025-10-23 15:04:25 -03:00
parent d8c377f0d8
commit 0957ff6e71
3 changed files with 43 additions and 18 deletions
+14 -10
View File
@@ -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;
+29 -4
View File
@@ -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;
}
-4
View File
@@ -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)