diff options
-rw-r--r-- | fatfs/ChangeLog | 13 | ||||
-rw-r--r-- | fatfs/fatfs.h | 3 | ||||
-rw-r--r-- | fatfs/inode.c | 89 |
3 files changed, 73 insertions, 32 deletions
diff --git a/fatfs/ChangeLog b/fatfs/ChangeLog index 63c9fcb4..3c5acce8 100644 --- a/fatfs/ChangeLog +++ b/fatfs/ChangeLog @@ -1,3 +1,16 @@ +2003-08-03 Marco Gerards <metgerards@student.han.nl> + + * fatfs.h (struct disknode): New member DIRNODE. + * inode.c (read_node): Added assertion to be sure the directory + can always be found. Add directory dependancy to node by + initializing DIRNODE and holding a reference. + (diskfs_node_norefs): Release reference to DIRNODE. + (write_node): Don't use diskfs_cached_lookup to lookup the + directory, use DIRNODE instead and lock DP. Don't use diskfs_nput, + use mutex_unlock instead. + (diskfs_alloc_node): Add directory dependancy to node by + initializing DIRNODE and holding a reference. + 2003-08-05 Marcus Brinkmann <marcus@gnu.org> * fat.c (fat_read_sblock): Catch error from store_read. diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h index 943ccad3..16b058a8 100644 --- a/fatfs/fatfs.h +++ b/fatfs/fatfs.h @@ -42,6 +42,9 @@ struct disknode /* The inode as returned by virtual inode management routines. */ inode_t inode; + /* The directory that hold this file, always hold a reference. */ + struct node *dirnode; + struct rwlock dirent_lock; char *link_target; /* For S_ISLNK. */ diff --git a/fatfs/inode.c b/fatfs/inode.c index f8780eb5..9122fee4 100644 --- a/fatfs/inode.c +++ b/fatfs/inode.c @@ -223,6 +223,15 @@ diskfs_node_norefs (struct node *np) if (np->dn->translator) free (np->dn->translator); + /* It is safe to unlock diskfs_node_refcnt_lock here for a while because + all references to the node have been deleted. */ + if (np->dn->dirnode) + { + spin_unlock (&diskfs_node_refcnt_lock); + diskfs_nrele (np->dn->dirnode); + spin_lock (&diskfs_node_refcnt_lock); + } + assert (!np->dn->pager); free (np->dn); @@ -255,7 +264,7 @@ diskfs_new_hardrefs (struct node *np) static error_t read_node (struct node *np, vm_address_t buf) { - /* XXX This needs careful investigation */ + /* XXX This needs careful investigation. */ error_t err; struct stat *st = &np->dn_stat; struct disknode *dn = np->dn; @@ -267,6 +276,30 @@ read_node (struct node *np, vm_address_t buf) vm_size_t buflen = 0; int our_buf = 0; + st->st_fstype = FSTYPE_MSLOSS; + st->st_fsid = getpid (); + st->st_ino = np->cache_id; + st->st_gen = 0; + st->st_rdev = 0; + + st->st_nlink = 1; + st->st_uid = fs_uid; + st->st_gid = fs_gid; + + st->st_rdev = 0; + + np->dn->translator = 0; + np->dn->translen = 0; + + st->st_flags = 0; + + /* FIXME: If we are called through diskfs_alloc_node for a newly + allocated node that has no directory entry yet, only set a + minimal amount of data until the dirent is created (and we get + called a second time?). */ + if (vk.dir_inode == 0 && vk.dir_offset == (void *) 2) + return 0; + if (vk.dir_inode == 0) dr = &dr_root_node; else @@ -277,6 +310,7 @@ read_node (struct node *np, vm_address_t buf) by libdiskfs. The only case it is not locked is for NFS (fsys_getfile) and we disabled that. */ dp = ifind (vk.dir_inode); + assert (dp); /* Map in the directory contents. */ memobj = diskfs_get_filemap (dp, prot); @@ -294,30 +328,10 @@ read_node (struct node *np, vm_address_t buf) dr = (struct dirrect *) (buf + vk.dir_offset); } - st->st_fstype = FSTYPE_MSLOSS; - st->st_fsid = getpid (); - st->st_ino = np->cache_id; - st->st_gen = 0; - st->st_rdev = 0; - - st->st_nlink = 1; - st->st_uid = fs_uid; - st->st_gid = fs_gid; - - st->st_rdev = 0; - - np->dn->translator = 0; - np->dn->translen = 0; - - st->st_flags = 0; - - /* If we are called for a newly allocated node that has no directory - entry yet, only set a minimal amount of data until the dirent is - created (and we get called a second time?). */ - /* We will avoid this by overriding the relevant functions. - if (dr == (void *)1) - return 0; - */ + /* Files in fatfs depend on the directory that hold the file. */ + np->dn->dirnode = dp; + if (dp) + dp->references++; rwlock_reader_lock(&np->dn->dirent_lock); @@ -464,15 +478,20 @@ write_node (struct node *np) { assert (!diskfs_readonly); - err = diskfs_cached_lookup (vk.dir_inode, &dp); - if (err) - return; + dp = np->dn->dirnode; + assert (dp); + + mutex_lock (&dp->lock); /* Map in the directory contents. */ memobj = diskfs_get_filemap (dp, prot); if (memobj == MACH_PORT_NULL) - return; + { + mutex_unlock (&dp->lock); + /* FIXME: We shouldn't ignore this error. */ + return; + } buflen = round_page (dp->dn_stat.st_size); err = vm_map (mach_task_self (), @@ -487,7 +506,7 @@ write_node (struct node *np) write_dword (dr->file_size, st->st_size); - /* Write time. */ + /* Write time. */ fat_from_epoch ((unsigned char *) &dr->write_date, (unsigned char *) &dr->write_time, &st->st_mtime); @@ -495,7 +514,7 @@ write_node (struct node *np) np->dn_stat_dirty = 0; munmap ((caddr_t) buf, buflen); - diskfs_nput (dp); + mutex_unlock (&dp->lock); } } @@ -745,7 +764,9 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) assert (!diskfs_readonly); - err = vi_new((struct vi_key) {0,1} /* XXX not allocated yet */, &inum, &inode); + /* FIXME: We use a magic key here that signals read_node that we are + not entered in any directory yet. */ + err = vi_new((struct vi_key) {0,2}, &inum, &inode); if (err) return err; @@ -753,6 +774,10 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) if (err) return err; + /* FIXME: We know that readnode couldn't put this in. */ + np->dn->dirnode = dir; + dir->references++; + *node = np; return 0; } |