This patch makes tmpfs work. Well, mostly. If you attempt to create
files too quickly on the tmpfs (e.g. extract a tar file), vm_map (when
passed memory objects, it works fine mapping anonymously) maps bad
memory regions into the server address space which cause the server to
stall during the memcpy in pager_memcpy. Note that once this happens,
_no_ process can successfully use vm_map with a memory object. As such,
I suspect that there is a race in the implementation of
default_pager_object_create in the default pager.
In implementing this patch, I found several bugs in libdiskfs, that patch
is also required to make tmpfs happy.
2001-04-15 Neal H Walfield <[EMAIL PROTECTED]>
* tmpfs.c (main): Do not deallocate the underlying node;
servers deallocate nodes based only on the number of outstanding
protids.
* dir.c (diskfs_get_directs): Total rewrite.
(diskfs_lookup_hard): Likewise.
(diskfs_enter_hard): Count node size the size of the dirent so
diskfs_get_directs does not have to guess; this is only a few
bytes different. Check the amount of space correctly, i.e.
we cannot compare bytes and pages.
* node.c: (diskfs_free_node): We already hold
diskfs_node_refcnt_lock; do not try to lock it again.
(diskfs_cached_lookup): Use diskfs_nref, that is why we have it.
Link the nodes correctly.
(diskfs_node_iterate): Check the return of alloca.
(diskfs_set_translator): Add or remove S_IPTRANS from
np->dn_stat.st_mode as appropriate.
(diskfs_truncate): We can truncate objects when they are being
truncated to a size of zero. Set the new np->dn_stat.st_size.
(diskfs_grow): Move the assert up.
diff --exclude CVS --exclude configure -urN hurd-20010412-snapshot/tmpfs/dir.c
hurd-20010412/tmpfs/dir.c
--- hurd-20010412-snapshot/tmpfs/dir.c Mon Feb 26 11:43:08 2001
+++ hurd-20010412/tmpfs/dir.c Sun Apr 15 12:03:02 2001
@@ -62,7 +62,8 @@
>= offsetof (struct dirent, d_name));
if (bufsiz == 0)
- bufsiz = dp->dn_stat.st_size + 2 * offsetof (struct dirent, d_name[4]);
+ bufsiz = dp->dn_stat.st_size
+ + 2 * ((offsetof (struct dirent, d_name[3]) + 7) & ~7);
if (bufsiz > *datacnt)
{
*data = mmap (0, bufsiz, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
@@ -108,19 +109,26 @@
for (d = dp->dn->u.dir.entries; i < entry && d != 0; d = d->next)
++i;
+ if (i < entry)
+ {
+ assert (d == 0);
+ *datacnt = 0;
+ *amt = 0;
+ return 0;
+ }
+
/* Now fill in the buffer with real entries. */
- for (; d != 0; d = d->next)
+ for (; d != 0; d = d->next, i++)
{
- if ((char *) entp - *data >= bufsiz || (n >= 0 && ++i > n))
+ size_t rlen = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & ~7;
+ if (rlen + (char *) entp - *data > bufsiz || (n >= 0 && i > n))
break;
entp->d_fileno = (ino_t) d->dn;
entp->d_type = DT_UNKNOWN;
entp->d_namlen = d->namelen;
memcpy (entp->d_name, d->name, d->namelen + 1);
- entp->d_reclen = ((&entp->d_name[d->namelen + 1] - (char *) entp + 7)
- & ~7);
- entp = (void *) entp + entp->d_reclen;
- ++i;
+ entp->d_reclen = rlen;
+ entp = (void *) entp + rlen;
}
*datacnt = (char *) entp - *data;
@@ -158,6 +166,9 @@
const size_t namelen = strlen (name);
struct tmpfs_dirent *d, **prevp;
+ if (type == REMOVE || type == RENAME)
+ assert (np);
+
if (namelen == 1 && name[0] == '.')
{
if (np != 0)
@@ -170,40 +181,54 @@
if (namelen == 2 && name[0] == '.' && name[1] == '.')
{
struct disknode *dddn = dp->dn->u.dir.dotdot;
- struct node *ddnp = 0;
error_t err;
assert (np != 0);
if (dddn == 0) /* root directory */
return EAGAIN;
- err = diskfs_cached_lookup ((int) dddn, &ddnp);
- switch (type)
- {
- case LOOKUP|SPEC_DOTDOT:
- diskfs_nput (dp);
- default:
- if (!err)
- {
- diskfs_nref (ddnp);
- mutex_lock (&ddnp->lock);
- }
- case REMOVE|SPEC_DOTDOT:
- case RENAME|SPEC_DOTDOT:
- *np = ddnp;
+ if (type == (REMOVE|SPEC_DOTDOT) || type == (RENAME|SPEC_DOTDOT))
+ {
+ *np = *dddn->hprevp;
+ assert (*np);
+ assert ((*np)->dn == dddn);
+ assert (*dddn->hprevp == *np);
+ return 0;
+ }
+ else
+ {
+ mutex_unlock (&dp->lock);
+ err = diskfs_cached_lookup ((int) dddn, np);
+
+ if (type == (LOOKUP|SPEC_DOTDOT))
+ diskfs_nrele (dp);
+ else
+ mutex_lock (&dp->lock);
+
+ if (err)
+ *np = 0;
+
+ return err;
}
- return err;
}
for (d = *(prevp = &dp->dn->u.dir.entries); d != 0;
d = *(prevp = &d->next))
if (d->namelen == namelen && !memcmp (d->name, name, namelen))
{
- ds->prevp = prevp;
- return diskfs_cached_lookup ((ino_t) d->dn, np);
+ if (ds)
+ ds->prevp = prevp;
+
+ if (np)
+ return diskfs_cached_lookup ((ino_t) d->dn, np);
+ else
+ return 0;
}
- ds->prevp = prevp;
+ if (ds)
+ ds->prevp = prevp;
+ if (np)
+ *np = 0;
return ENOENT;
}
@@ -214,10 +239,12 @@
struct protid *cred)
{
const size_t namelen = strlen (name);
- const size_t entsize = offsetof (struct tmpfs_dirent, name) + namelen + 1;
+ const size_t entsize
+ = (offsetof (struct dirent, d_name[1]) + namelen + 7) & ~7;
struct tmpfs_dirent *new;
- if (round_page (tmpfs_space_used + entsize) > tmpfs_page_limit)
+ if (round_page (tmpfs_space_used + entsize) / vm_page_size
+ > tmpfs_page_limit)
return ENOSPC;
new = malloc (entsize);
@@ -251,7 +278,8 @@
diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
{
struct tmpfs_dirent *d = *ds->prevp;
- const size_t entsize = &d->name[d->namelen + 1] - (char *) d;
+ const size_t entsize
+ = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & ~7;
*ds->prevp = d->next;
diff --exclude CVS --exclude configure -urN hurd-20010412-snapshot/tmpfs/node.c
hurd-20010412/tmpfs/node.c
--- hurd-20010412-snapshot/tmpfs/node.c Mon Feb 26 12:03:15 2001
+++ hurd-20010412/tmpfs/node.c Sun Apr 15 16:46:25 2001
@@ -74,10 +74,8 @@
free (np->dn);
np->dn = 0;
- spin_lock (&diskfs_node_refcnt_lock);
--num_files;
tmpfs_space_used -= sizeof *np->dn;
- spin_unlock (&diskfs_node_refcnt_lock);
}
void
@@ -150,31 +148,36 @@
st->st_blocks = (st->st_blocks + 511) / 512;
}
+/* Fetch inode INUM, set *NPP to the node structure;
+ gain one user reference and lock the node. */
error_t
diskfs_cached_lookup (int inum, struct node **npp)
{
struct disknode *dn = (void *) inum;
struct node *np;
+ assert (npp);
+
if (dn->hprevp != 0) /* There is already a node. */
{
np = *dn->hprevp;
assert (np->dn == dn);
assert (*dn->hprevp == np);
- spin_lock (&diskfs_node_refcnt_lock);
- np->references++;
- spin_unlock (&diskfs_node_refcnt_lock);
+
+ diskfs_nref (np);
}
else
+ /* Create the new node. */
{
struct stat *st;
- /* Create the new node. */
np = diskfs_make_node (dn);
np->cache_id = (ino_t) dn;
spin_lock (&diskfs_node_refcnt_lock);
dn->hnext = all_nodes;
+ if (dn->hnext)
+ dn->hnext->dn->hprevp = &dn->hnext;
dn->hprevp = &all_nodes;
all_nodes = np;
spin_unlock (&diskfs_node_refcnt_lock);
@@ -228,6 +231,9 @@
num_nodes++;
p = node_list = alloca (num_nodes * sizeof (struct node *));
+ if (! p)
+ return ENOMEM;
+
for (node = all_nodes; node != 0; node = node->dn->hnext)
{
*p++ = node;
@@ -303,6 +309,7 @@
{
free (np->dn->trans);
new = 0;
+ np->dn_stat.st_mode &= ~S_IPTRANS;
}
else
{
@@ -310,6 +317,7 @@
if (new == 0)
return ENOSPC;
memcpy (new, name, namelen);
+ np->dn_stat.st_mode |= S_IPTRANS;
}
adjust_used (namelen - np->dn->translen);
np->dn->trans = new;
@@ -393,13 +401,22 @@
if (np->dn->u.reg.memobj != MACH_PORT_NULL)
{
- /* XXX We have no way to truncate the memory object. */
- return 0;
+ if (size == 0)
+ {
+ mach_port_deallocate (mach_task_self (), np->dn->u.reg.memobj);
+ np->dn->u.reg.memobj = MACH_PORT_NULL;
+ }
+ else
+ {
+ /* XXX We have no way to truncate the memory object. */
+ return 0;
+ }
}
/* Otherwise it never had any real contents. */
adjust_used (size - np->allocsize);
np->dn_stat.st_blocks += (size - np->allocsize) / 512;
+ np->dn_stat.st_size = size;
np->allocsize = size;
return 0;
@@ -412,10 +429,10 @@
error_t
diskfs_grow (struct node *np, off_t size, struct protid *cred)
{
+ assert (np->dn->type == DT_REG);
+
if (np->allocsize >= size)
return 0;
-
- assert (np->dn->type == DT_REG);
size = round_page (size);
if (round_page (tmpfs_space_used + size) / vm_page_size > tmpfs_page_limit)
diff --exclude CVS --exclude configure -urN hurd-20010412-snapshot/tmpfs/tmpfs.c
hurd-20010412/tmpfs/tmpfs.c
--- hurd-20010412-snapshot/tmpfs/tmpfs.c Sun Apr 15 13:16:04 2001
+++ hurd-20010412/tmpfs/tmpfs.c Sat Apr 14 15:30:05 2001
@@ -265,7 +265,6 @@
/* Propagate permissions, owner, etc. from underlying node to
the root directory of the new (empty) filesystem. */
err = io_stat (realnode, &st);
- mach_port_deallocate (mach_task_self (), realnode);
if (err)
{
error (0, err, "cannot stat underlying node");
PGP signature