fs: fix locking in rename for fatfs and ext2

This commit is contained in:
Matheus
2025-11-08 02:20:56 -03:00
parent ab90700203
commit 36bec0427a
2 changed files with 19 additions and 3 deletions
+7 -1
View File
@@ -1833,30 +1833,34 @@ static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode
if (replaced_vnode) { if (replaced_vnode) {
// we are replacing an existing link // we are replacing an existing link
// do some checks expected by posix // do some checks expected by posix
// TODO add these to fatfs and tmpfs
if (source->type != V_TYPE_DIR && replaced_vnode->type == V_TYPE_DIR) { if (source->type != V_TYPE_DIR && replaced_vnode->type == V_TYPE_DIR) {
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
return EISDIR; return EISDIR;
} }
if (source->type == V_TYPE_DIR && replaced_vnode->type != V_TYPE_DIR) { if (source->type == V_TYPE_DIR && replaced_vnode->type != V_TYPE_DIR) {
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
return ENOTDIR; return ENOTDIR;
} }
if (replaced_vnode->vfsmounted) { if (replaced_vnode->vfsmounted) {
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
return EBUSY; return EBUSY;
} }
err = replaced_vnode->type == V_TYPE_DIR ? is_directory_empty(ext2_replaced_node) : 0; err = replaced_vnode->type == V_TYPE_DIR ? is_directory_empty(ext2_replaced_node) : 0;
if (err) { if (err) {
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
return err; return err;
} }
if (source == replaced_vnode) { if (source == replaced_vnode) {
// POSIX says that if both are the same file, rename is a no-op // POSIX says that if both are the same file, rename is a no-op
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
return 0; return 0;
} }
@@ -1873,9 +1877,11 @@ static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode
err = handleinodeunlink(fs, ext2targetdirnode, oldinode, ext2_replaced_node); err = handleinodeunlink(fs, ext2targetdirnode, oldinode, ext2_replaced_node);
ext2sourcenode->inode.links += 1; ext2sourcenode->inode.links += 1;
ASSERT_UNCLEAN(fs, writeinode(fs, &ext2sourcenode->inode, ext2sourcenode->id) == 0); ASSERT_UNCLEAN(fs, writeinode(fs, &ext2sourcenode->inode, ext2sourcenode->id) == 0);
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
} else if (err) { } else if (err) {
if (replaced_vnode) { if (replaced_vnode) {
VOP_UNLOCK(replaced_vnode);
VOP_RELEASE(replaced_vnode); VOP_RELEASE(replaced_vnode);
} }
} }
+12 -2
View File
@@ -731,28 +731,33 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name,
// we are replacing an existing link // we are replacing an existing link
// do some checks expected by posix // do some checks expected by posix
if (vsource->type != V_TYPE_DIR && vtarget->type == V_TYPE_DIR) { if (vsource->type != V_TYPE_DIR && vtarget->type == V_TYPE_DIR) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return EISDIR; return EISDIR;
} }
if (vsource->type == V_TYPE_DIR && vtarget->type != V_TYPE_DIR) { if (vsource->type == V_TYPE_DIR && vtarget->type != V_TYPE_DIR) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return ENOTDIR; return ENOTDIR;
} }
if (vtarget->vfsmounted) { if (vtarget->vfsmounted) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return EBUSY; return EBUSY;
} }
error = vtarget->type == V_TYPE_DIR ? is_directory_empty(target) : 0; error = vtarget->type == V_TYPE_DIR ? is_directory_empty(target) : 0;
if (error) { if (error) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return error; return error;
} }
if (source == target) { if (source == target) {
// POSIX says that if both are the same file, rename is a no-op // POSIX says that if both are the same file, rename is a no-op
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return 0; return 0;
} }
@@ -782,6 +787,7 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name,
size_t written; size_t written;
error = vfs_write(fatfs->backing, &new_dent, sizeof(new_dent), dent_disk_offset, &written, 0); error = vfs_write(fatfs->backing, &new_dent, sizeof(new_dent), dent_disk_offset, &written, 0);
if (error) { if (error) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); VOP_RELEASE(vtarget);
return error; return error;
} }
@@ -796,13 +802,17 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name,
VOP_RELEASE(vtarget); // table hold VOP_RELEASE(vtarget); // table hold
__assert(target->parent_dir == target_dir); __assert(target->parent_dir == target_dir);
VOP_RELEASE(vtarget_dir) VOP_RELEASE(vtarget_dir);
target->parent_dir = NULL; target->parent_dir = NULL;
target->dent_disk_offset = 0; target->dent_disk_offset = 0;
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget); // lookup hold VOP_RELEASE(vtarget); // lookup hold
} else { } else {
VOP_RELEASE(vtarget); if (vtarget) {
VOP_UNLOCK(vtarget);
VOP_RELEASE(vtarget);
}
return error; return error;
} }