summaryrefslogtreecommitdiff
path: root/fd.c
diff options
context:
space:
mode:
authorrtm <rtm>2006-08-13 12:22:44 +0000
committerrtm <rtm>2006-08-13 12:22:44 +0000
commit211ff0c67ea6737853cf932313cf4e27cc15f55c (patch)
treee28f2e9f39ddc226203c16e955337216bbdab7f5 /fd.c
parentc372e8dc348e4bb30aae7642db92ecbeedbc83ab (diff)
downloadxv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.tar.gz
xv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.tar.bz2
xv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.zip
namei returns locked parent dir inode for create / unlink
don't hold fd table lock across idecref() (latter does block i/o) idecref calls iput() in case last ref -> freeing inode dir size is 512 * # blocks, so readi/writei &c work unlink deletes dirent even if ip->nlink > 0
Diffstat (limited to 'fd.c')
-rw-r--r--fd.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/fd.c b/fd.c
index c5c3e57..25a51fb 100644
--- a/fd.c
+++ b/fd.c
@@ -108,18 +108,22 @@ fd_close(struct fd *fd)
panic("fd_close");
if(--fd->ref == 0){
- if(fd->type == FD_PIPE){
- pipe_close(fd->pipe, fd->writeable);
- } else if(fd->type == FD_FILE){
- idecref(fd->ip);
+ struct fd dummy = *fd;
+
+ fd->ref = 0;
+ fd->type = FD_CLOSED;
+ release(&fd_table_lock);
+
+ if(dummy.type == FD_PIPE){
+ pipe_close(dummy.pipe, dummy.writeable);
+ } else if(dummy.type == FD_FILE){
+ idecref(dummy.ip);
} else {
panic("fd_close");
}
- fd->ref = 0;
- fd->type = FD_CLOSED;
+ } else {
+ release(&fd_table_lock);
}
-
- release(&fd_table_lock);
}
int