summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fatfs/ChangeLog13
-rw-r--r--fatfs/fatfs.h3
-rw-r--r--fatfs/inode.c89
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;
}