summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdiskfs/diskfs.h27
-rw-r--r--libdiskfs/init-init.c4
-rw-r--r--libdiskfs/name-cache.c410
-rw-r--r--libdiskfs/node-make.c39
-rw-r--r--libnetfs/init-init.c3
-rw-r--r--libnetfs/make-node.c29
-rw-r--r--libnetfs/netfs.h27
-rw-r--r--trans/fakeroot.c135
8 files changed, 439 insertions, 235 deletions
diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
index ae1a1502..2c68aa34 100644
--- a/libdiskfs/diskfs.h
+++ b/libdiskfs/diskfs.h
@@ -686,6 +686,33 @@ diskfs_notice_filechange (struct node *np, enum file_changed_type type,
The new node will have one hard reference and no light references. */
struct node *diskfs_make_node (struct disknode *dn);
+/* Create a new node structure. Also allocate SIZE bytes for the
+ disknode. The address of the disknode can be obtained using
+ diskfs_node_disknode. The new node will have one hard reference
+ and no light references. */
+struct node *diskfs_make_node_alloc (size_t size);
+
+/* To avoid breaking the ABI whenever sizeof (struct node) changes, we
+ explicitly provide the size. The following two functions will use
+ this value for offset calculations. */
+extern const size_t _diskfs_sizeof_struct_node;
+
+/* Return the address of the disknode for NODE. NODE must have been
+ allocated using diskfs_make_node_alloc. */
+static inline struct disknode *
+diskfs_node_disknode (struct node *node)
+{
+ return (struct disknode *) ((char *) node + _diskfs_sizeof_struct_node);
+}
+
+/* Return the address of the node for DISKNODE. DISKNODE must have
+ been allocated using diskfs_make_node_alloc. */
+static inline struct node *
+diskfs_disknode_node (struct disknode *disknode)
+{
+ return (struct node *) ((char *) disknode - _diskfs_sizeof_struct_node);
+}
+
/* The library also exports the following functions; they are not generally
useful unless you are redefining other functions the library provides. */
diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c
index 35be7edd..7a7f2485 100644
--- a/libdiskfs/init-init.c
+++ b/libdiskfs/init-init.c
@@ -25,6 +25,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <maptime.h>
+/* For safe inlining of diskfs_node_disknode and
+ diskfs_disknode_node. */
+size_t const _diskfs_sizeof_struct_node = sizeof (struct node);
+
mach_port_t diskfs_default_pager;
mach_port_t diskfs_auth_server_port;
volatile struct mapped_time_value *diskfs_mtime;
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c
index a212a6dc..d8f86b15 100644
--- a/libdiskfs/name-cache.c
+++ b/libdiskfs/name-cache.c
@@ -1,6 +1,6 @@
/* Directory name lookup caching
- Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 2014 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG, & Miles Bader.
This file is part of the GNU Hurd.
@@ -20,178 +20,290 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "priv.h"
+#include <assert.h>
#include <string.h>
-#include <cacheq.h>
-/* Maximum number of names to cache at once */
-#define MAXCACHE 200
+/* The name cache is implemented using a hash table.
-/* Maximum length of file name we bother caching */
-#define CACHE_NAME_LEN 100
+ We use buckets of a fixed size. We approximate the
+ least-frequently used cache algorithm by counting the number of
+ lookups using saturating arithmetic in the two lowest bits of the
+ pointer to the name. Using this strategy we achieve a constant
+ worst-case lookup and insertion time. */
-/* Cache entry */
-struct lookup_cache
-{
- struct cacheq_hdr hdr;
+/* Number of buckets. Must be a power of two. */
+#define CACHE_SIZE 256
+
+/* Entries per bucket. */
+#define BUCKET_SIZE 4
+
+/* A mask for fast binary modulo. */
+#define CACHE_MASK (CACHE_SIZE - 1)
- /* Used to indentify nodes to the fs dependent code. 0 for NODE_CACHE_ID
- means a `negative' entry -- recording that there's definitely no node with
- this name. */
- ino64_t dir_cache_id, node_cache_id;
+/* Cache bucket with BUCKET_SIZE entries.
- /* Name of the node NODE_CACHE_ID in the directory DIR_CACHE_ID. Entries
- with names too long to fit in this buffer aren't cached at all. */
- char name[CACHE_NAME_LEN];
+ The layout of the bucket is chosen so that it will be straight
+ forward to use vector operations in the future. */
+struct cache_bucket
+{
+ /* Name of the node NODE_CACHE_ID in the directory DIR_CACHE_ID. If
+ NULL, the entry is unused. */
+ unsigned long name[BUCKET_SIZE];
+
+ /* The key. */
+ unsigned long key[BUCKET_SIZE];
- /* Strlen of NAME. If this is zero, it's an unused entry. */
- size_t name_len;
+ /* Used to indentify nodes to the fs dependent code. */
+ ino64_t dir_cache_id[BUCKET_SIZE];
- /* XXX */
- int stati;
+ /* 0 for NODE_CACHE_ID means a `negative' entry -- recording that
+ there's definitely no node with this name. */
+ ino64_t node_cache_id[BUCKET_SIZE];
};
-/* The contents of the cache in no particular order */
-static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
+/* The cache. */
+static struct cache_bucket name_cache[CACHE_SIZE];
-static pthread_spinlock_t cache_lock = PTHREAD_SPINLOCK_INITIALIZER;
+/* Protected by this lock. */
+static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Given VALUE, return the char pointer. */
+static inline char *
+charp (unsigned long value)
+{
+ return (char *) (value & ~3L);
+}
-/* Buffer to hold statistics */
-static struct stats
+/* Given VALUE, return the approximation of use frequency. */
+static inline unsigned long
+frequ (unsigned long value)
+{
+ return value & 3;
+}
+
+/* Add an entry in the Ith slot of the given bucket. If there is a
+ value there, remove it first. */
+static inline void
+add_entry (struct cache_bucket *b, int i,
+ const char *name, unsigned long key,
+ ino64_t dir_cache_id, ino64_t node_cache_id)
{
- long pos_hits;
- long neg_hits;
- long miss;
- long fetch_errors;
-} statistics;
+ if (b->name[i])
+ free (charp (b->name[i]));
-#define PARTIAL_THRESH 100
-#define NPARTIALS MAXCACHE / PARTIAL_THRESH
-struct stats partial_stats [NPARTIALS];
+ b->name[i] = (unsigned long) strdup (name);
+ assert ((b->name[i] & 3) == 0);
+ if (b->name[i] == 0)
+ return;
+
+ b->key[i] = key;
+ b->dir_cache_id[i] = dir_cache_id;
+ b->node_cache_id[i] = node_cache_id;
+}
+
+/* Remove the entry in the Ith slot of the given bucket. */
+static inline void
+remove_entry (struct cache_bucket *b, int i)
+{
+ if (b->name[i])
+ free (charp (b->name[i]));
+ b->name[i] = 0;
+}
+/* Check if the entry in the Ith slot of the given bucket is
+ valid. */
+static inline int
+valid_entry (struct cache_bucket *b, int i)
+{
+ return b->name[i] != 0;
+}
-/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the
- cache, return its entry, otherwise 0. CACHE_LOCK must be held. */
-static struct lookup_cache *
-find_cache (struct node *dir, const char *name, size_t name_len)
+/* This is the Murmur3 hash algorithm. */
+
+#define FORCE_INLINE inline __attribute__((always_inline))
+
+inline uint32_t rotl32 ( uint32_t x, int8_t r )
{
- struct lookup_cache *c;
- int i;
+ return (x << r) | (x >> (32 - r));
+}
- /* Search the list. All unused entries are contiguous at the end of the
- list, so we can stop searching when we see the first one. */
- for (i = 0, c = lookup_cache.mru;
- c && c->name_len;
- c = c->hdr.next, i++)
- if (c->name_len == name_len
- && c->dir_cache_id == dir->cache_id
- && c->name[0] == name[0] && strcmp (c->name, name) == 0)
- {
- c->stati = i / 100;
- return c;
- }
+#define ROTL32(x,y) rotl32(x,y)
- return 0;
+/* Block read - if your platform needs to do endian-swapping or can
+ only handle aligned reads, do the conversion here. */
+
+FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
+{
+ return p[i];
}
-
-/* Node NP has just been found in DIR with NAME. If NP is null, that
- means that this name has been confirmed as absent in the directory. */
-void
-diskfs_enter_lookup_cache (struct node *dir, struct node *np, const char *name)
+
+/* Finalization mix - force all bits of a hash block to avalanche. */
+
+FORCE_INLINE uint32_t fmix32 ( uint32_t h )
{
- struct lookup_cache *c;
- size_t name_len = strlen (name);
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
- if (name_len > CACHE_NAME_LEN - 1)
- return;
+ return h;
+}
+
+/* The Murmur3 hash function. */
+void MurmurHash3_x86_32 ( const void * key, int len,
+ uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 4;
+
+ uint32_t h1 = seed;
+
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+
+ /* body */
+
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
+
+ for(int i = -nblocks; i; i++)
+ {
+ uint32_t k1 = getblock32(blocks,i);
+
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1,13);
+ h1 = h1*5+0xe6546b64;
+ }
- pthread_spin_lock (&cache_lock);
+ /* tail */
- if (lookup_cache.length == 0)
- /* There should always be an lru_cache; this being zero means that the
- cache hasn't been initialized yet. Do so. */
- cacheq_set_length (&lookup_cache, MAXCACHE);
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
- /* See if there's an old entry for NAME in DIR. If not, replace the least
- recently used entry. */
- c = find_cache (dir, name, name_len) ?: lookup_cache.lru;
+ uint32_t k1 = 0;
- /* Fill C with the new entry. */
- c->dir_cache_id = dir->cache_id;
- c->node_cache_id = np ? np->cache_id : 0;
- strcpy (c->name, name);
- c->name_len = name_len;
+ switch(len & 3)
+ {
+ case 3: k1 ^= tail[2] << 16;
+ case 2: k1 ^= tail[1] << 8;
+ case 1: k1 ^= tail[0];
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
- /* Now C becomes the MRU entry! */
- cacheq_make_mru (&lookup_cache, c);
+ /* finalization */
- pthread_spin_unlock (&cache_lock);
+ h1 ^= len;
+
+ h1 = fmix32(h1);
+
+ *(uint32_t*)out = h1;
}
-/* Purge all references in the cache to NP as a node inside
- directory DP. */
-void
-diskfs_purge_lookup_cache (struct node *dp, struct node *np)
+/* If there is no best candidate to replace, pick any. We approximate
+ any by picking the slot depicted by REPLACE, and increment REPLACE
+ then. */
+static int replace;
+
+/* Lookup (DIR_CACHE_ID, NAME, KEY) in the cache. If it is found,
+ return 1 and set BUCKET and INDEX to the item. Otherwise, return 0
+ and set BUCKET and INDEX to the slot where the item should be
+ inserted. */
+static inline int
+lookup (ino64_t dir_cache_id, const char *name, unsigned long key,
+ struct cache_bucket **bucket, int *index)
{
- struct lookup_cache *c, *next;
+ struct cache_bucket *b = *bucket = &name_cache[key & CACHE_MASK];
+ unsigned long best = 3;
+ int i;
- pthread_spin_lock (&cache_lock);
- for (c = lookup_cache.mru; c; c = next)
+ for (i = 0; i < BUCKET_SIZE; i++)
{
- /* Save C->hdr.next, since we may move C from this position. */
- next = c->hdr.next;
+ unsigned long f = frequ (b->name[i]);
+
+ if (valid_entry (b, i)
+ && b->key[i] == key
+ && b->dir_cache_id[i] == dir_cache_id
+ && strcmp (charp (b->name[i]), name) == 0)
+ {
+ if (f < 3)
+ b->name[i] += 1;
+
+ *index = i;
+ return 1;
+ }
- if (c->name_len
- && c->dir_cache_id == dp->cache_id
- && c->node_cache_id == np->cache_id)
+ /* Keep track of the replacement candidate. */
+ if (f < best)
{
- c->name_len = 0;
- cacheq_make_lru (&lookup_cache, c); /* Use C as the next free
- entry. */
+ best = f;
+ *index = i;
}
}
- pthread_spin_unlock (&cache_lock);
-}
-
-/* Register a negative hit for an entry in the Nth stat class */
-void
-register_neg_hit (int n)
-{
- int i;
- statistics.neg_hits++;
+ /* If there was no entry with a lower use frequency, just replace
+ any entry. */
+ if (best == 3)
+ {
+ *index = replace;
+ replace = (replace + 1) & (BUCKET_SIZE - 1);
+ }
- for (i = 0; i < n; i++)
- partial_stats[i].miss++;
- for (; i < NPARTIALS; i++)
- partial_stats[i].neg_hits++;
+ return 0;
}
-/* Register a positive hit for an entry in the Nth stat class */
+/* Hash the directory cache_id and the name. */
+static inline unsigned long
+hash (ino64_t dir_cache_id, const char *name)
+{
+ unsigned long h;
+ MurmurHash3_x86_32 (&dir_cache_id, sizeof dir_cache_id, 0, &h);
+ MurmurHash3_x86_32 (name, strlen (name), h, &h);
+ return h;
+}
+
+/* Node NP has just been found in DIR with NAME. If NP is null, that
+ means that this name has been confirmed as absent in the directory. */
void
-register_pos_hit (int n)
+diskfs_enter_lookup_cache (struct node *dir, struct node *np, const char *name)
{
- int i;
-
- statistics.pos_hits++;
-
- for (i = 0; i < n; i++)
- partial_stats[i].miss++;
- for (; i < NPARTIALS; i++)
- partial_stats[i].pos_hits++;
+ unsigned long key = hash (dir->cache_id, name);
+ ino64_t value = np ? np->cache_id : 0;
+ struct cache_bucket *bucket;
+ int i = 0, found;
+
+ pthread_mutex_lock (&cache_lock);
+ found = lookup (dir->cache_id, name, key, &bucket, &i);
+ if (! found)
+ add_entry (bucket, i, name, key, dir->cache_id, value);
+ else
+ if (bucket->node_cache_id[i] != value)
+ bucket->node_cache_id[i] = value;
+
+ pthread_mutex_unlock (&cache_lock);
}
-
-/* Register a miss */
+
+/* Purge all references in the cache to NP as a node inside
+ directory DP. */
void
-register_miss ()
+diskfs_purge_lookup_cache (struct node *dp, struct node *np)
{
int i;
+ struct cache_bucket *b;
- statistics.miss++;
- for (i = 0; i < NPARTIALS; i++)
- partial_stats[i].miss++;
-}
+ pthread_mutex_lock (&cache_lock);
+ for (b = &name_cache[0]; b < &name_cache[CACHE_SIZE]; b++)
+ for (i = 0; i < BUCKET_SIZE; i++)
+ if (valid_entry (b, i)
+ && b->dir_cache_id[i] == dp->cache_id
+ && b->node_cache_id[i] == np->cache_id)
+ remove_entry (b, i);
+ pthread_mutex_unlock (&cache_lock);
+}
/* Scan the cache looking for NAME inside DIR. If we don't know
anything entry at all, then return 0. If the entry is confirmed to
@@ -200,29 +312,28 @@ register_miss ()
struct node *
diskfs_check_lookup_cache (struct node *dir, const char *name)
{
- struct lookup_cache *c;
-
- pthread_spin_lock (&cache_lock);
-
- c = find_cache (dir, name, strlen (name));
- if (c)
+ unsigned long key = hash (dir->cache_id, name);
+ int lookup_parent = name[0] == '.' && name[1] == '.' && name[2] == '\0';
+ struct cache_bucket *bucket;
+ int i, found;
+
+ if (lookup_parent && dir == diskfs_root_node)
+ /* This is outside our file system, return cache miss. */
+ return NULL;
+
+ pthread_mutex_lock (&cache_lock);
+ found = lookup (dir->cache_id, name, key, &bucket, &i);
+ if (found)
{
- int id = c->node_cache_id;
-
- cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
+ ino64_t id = bucket->node_cache_id[i];
+ pthread_mutex_unlock (&cache_lock);
if (id == 0)
/* A negative cache entry. */
- {
- register_neg_hit (c->stati);
- pthread_spin_unlock (&cache_lock);
- return (struct node *)-1;
- }
+ return (struct node *) -1;
else if (id == dir->cache_id)
/* The cached node is the same as DIR. */
{
- register_pos_hit (c->stati);
- pthread_spin_unlock (&cache_lock);
diskfs_nref (dir);
return dir;
}
@@ -232,10 +343,7 @@ diskfs_check_lookup_cache (struct node *dir, const char *name)
struct node *np;
error_t err;
- register_pos_hit (c->stati);
- pthread_spin_unlock (&cache_lock);
-
- if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ if (lookup_parent)
{
pthread_mutex_unlock (&dir->lock);
err = diskfs_cached_lookup (id, &np);
@@ -244,14 +352,18 @@ diskfs_check_lookup_cache (struct node *dir, const char *name)
/* In the window where DP was unlocked, we might
have lost. So check the cache again, and see
if it's still there; if so, then we win. */
- c = find_cache (dir, "..", 2);
- if (!c || c->node_cache_id != id)
+ pthread_mutex_lock (&cache_lock);
+ found = lookup (dir->cache_id, name, key, &bucket, &i);
+ if (! found
+ || ! bucket->node_cache_id[i] != id)
{
+ pthread_mutex_unlock (&cache_lock);
+
/* Lose */
- pthread_mutex_unlock (&np->lock);
- diskfs_nrele (np);
+ diskfs_nput (np);
return 0;
}
+ pthread_mutex_unlock (&cache_lock);
}
else
err = diskfs_cached_lookup (id, &np);
@@ -259,8 +371,6 @@ diskfs_check_lookup_cache (struct node *dir, const char *name)
}
}
- register_miss ();
- pthread_spin_unlock (&cache_lock);
-
+ pthread_mutex_unlock (&cache_lock);
return 0;
}
diff --git a/libdiskfs/node-make.c b/libdiskfs/node-make.c
index 2b6ef2af..ff0cc0d4 100644
--- a/libdiskfs/node-make.c
+++ b/libdiskfs/node-make.c
@@ -19,16 +19,9 @@
#include <fcntl.h>
-/* Create a and return new node structure with DN as its physical disknode.
- The node will have one hard reference and no light references. */
-struct node *
-diskfs_make_node (struct disknode *dn)
+static struct node *
+init_node (struct node *np, struct disknode *dn)
{
- struct node *np = malloc (sizeof (struct node));
-
- if (np == 0)
- return 0;
-
np->dn = dn;
np->dn_set_ctime = 0;
np->dn_set_atime = 0;
@@ -52,3 +45,31 @@ diskfs_make_node (struct disknode *dn)
return np;
}
+
+/* Create a and return new node structure with DN as its physical disknode.
+ The node will have one hard reference and no light references. */
+struct node *
+diskfs_make_node (struct disknode *dn)
+{
+ struct node *np = malloc (sizeof (struct node));
+
+ if (np == 0)
+ return 0;
+
+ return init_node (np, dn);
+}
+
+/* Create a new node structure. Also allocate SIZE bytes for the
+ disknode. The address of the disknode can be obtained using
+ diskfs_node_disknode. The new node will have one hard reference
+ and no light references. */
+struct node *
+diskfs_make_node_alloc (size_t size)
+{
+ struct node *np = malloc (sizeof (struct node) + size);
+
+ if (np == NULL)
+ return NULL;
+
+ return init_node (np, diskfs_node_disknode (np));
+}
diff --git a/libnetfs/init-init.c b/libnetfs/init-init.c
index e98b6562..a088ad51 100644
--- a/libnetfs/init-init.c
+++ b/libnetfs/init-init.c
@@ -21,6 +21,9 @@
#include "netfs.h"
+/* For safe inlining of netfs_node_netnode and netfs_netnode_node. */
+size_t const _netfs_sizeof_struct_node = sizeof (struct node);
+
pthread_spinlock_t netfs_node_refcnt_lock = PTHREAD_SPINLOCK_INITIALIZER;
struct node *netfs_root_node = 0;
diff --git a/libnetfs/make-node.c b/libnetfs/make-node.c
index f20ada18..6bd8109c 100644
--- a/libnetfs/make-node.c
+++ b/libnetfs/make-node.c
@@ -21,13 +21,9 @@
#include "netfs.h"
#include <hurd/fshelp.h>
-struct node *
-netfs_make_node (struct netnode *nn)
+static struct node *
+init_node (struct node *np, struct netnode *nn)
{
- struct node *np = malloc (sizeof (struct node));
- if (! np)
- return NULL;
-
np->nn = nn;
pthread_mutex_init (&np->lock, NULL);
@@ -40,3 +36,24 @@ netfs_make_node (struct netnode *nn)
return np;
}
+
+struct node *
+netfs_make_node (struct netnode *nn)
+{
+ struct node *np = malloc (sizeof (struct node));
+ if (! np)
+ return NULL;
+
+ return init_node (np, nn);
+}
+
+struct node *
+netfs_make_node_alloc (size_t size)
+{
+ struct node *np = malloc (sizeof (struct node) + size);
+
+ if (np == NULL)
+ return NULL;
+
+ return init_node (np, netfs_node_netnode (np));
+}
diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h
index aef4a3dd..fbe2c60d 100644
--- a/libnetfs/netfs.h
+++ b/libnetfs/netfs.h
@@ -372,6 +372,33 @@ extern int netfs_maxsymlinks;
If an error occurs, NULL is returned. */
struct node *netfs_make_node (struct netnode *);
+/* Create a new node structure. Also allocate SIZE bytes for the
+ netnode. The address of the netnode can be obtained using
+ netfs_node_netnode. The new node will have one hard reference and
+ no light references. If an error occurs, NULL is returned. */
+struct node *netfs_make_node_alloc (size_t size);
+
+/* To avoid breaking the ABI whenever sizeof (struct node) changes, we
+ explicitly provide the size. The following two functions will use
+ this value for offset calculations. */
+extern const size_t _netfs_sizeof_struct_node;
+
+/* Return the address of the netnode for NODE. NODE must have been
+ allocated using netfs_make_node_alloc. */
+static inline struct netnode *
+netfs_node_netnode (struct node *node)
+{
+ return (struct netnode *) ((char *) node + _netfs_sizeof_struct_node);
+}
+
+/* Return the address of the node for NETNODE. NETNODE must have been
+ allocated using netfs_make_node_alloc. */
+static inline struct node *
+netfs_netnode_node (struct netnode *netnode)
+{
+ return (struct node *) ((char *) netnode - _netfs_sizeof_struct_node);
+}
+
/* Whenever node->references is to be touched, this lock must be
held. Cf. netfs_nrele, netfs_nput, netfs_nref and netfs_drop_node. */
extern pthread_spinlock_t netfs_node_refcnt_lock;
diff --git a/trans/fakeroot.c b/trans/fakeroot.c
index 4175b552..32a34ec4 100644
--- a/trans/fakeroot.c
+++ b/trans/fakeroot.c
@@ -47,7 +47,6 @@ static auth_t fakeroot_auth_port;
struct netnode
{
- struct node *np; /* our node */
hurd_ihash_locp_t idport_locp;/* easy removal pointer in idport ihash */
mach_port_t idport; /* port from io_identity */
int openmodes; /* O_READ | O_WRITE | O_EXEC */
@@ -64,7 +63,8 @@ struct netnode
pthread_mutex_t idport_ihash_lock = PTHREAD_MUTEX_INITIALIZER;
struct hurd_ihash idport_ihash
- = HURD_IHASH_INITIALIZER (offsetof (struct netnode, idport_locp));
+= HURD_IHASH_INITIALIZER (sizeof (struct node)
+ + offsetof (struct netnode, idport_locp));
/* Make a new virtual node. Always consumes the ports. If
@@ -74,8 +74,9 @@ new_node (file_t file, mach_port_t idport, int locked, int openmodes,
struct node **np)
{
error_t err;
- struct netnode *nn = calloc (1, sizeof *nn);
- if (nn == 0)
+ struct netnode *nn;
+ *np = netfs_make_node_alloc (sizeof *nn);
+ if (*np == 0)
{
mach_port_deallocate (mach_task_self (), file);
if (idport != MACH_PORT_NULL)
@@ -84,6 +85,7 @@ new_node (file_t file, mach_port_t idport, int locked, int openmodes,
pthread_mutex_unlock (&idport_ihash_lock);
return ENOMEM;
}
+ nn = netfs_node_netnode (*np);
nn->file = file;
nn->openmodes = openmodes;
if (idport != MACH_PORT_NULL)
@@ -97,42 +99,33 @@ new_node (file_t file, mach_port_t idport, int locked, int openmodes,
if (err)
{
mach_port_deallocate (mach_task_self (), file);
- free (nn);
+ free (*np);
return err;
}
}
if (!locked)
pthread_mutex_lock (&idport_ihash_lock);
- err = hurd_ihash_add (&idport_ihash, nn->idport, nn);
+ err = hurd_ihash_add (&idport_ihash, nn->idport, *np);
if (err)
goto lose;
- *np = nn->np = netfs_make_node (nn);
- if (*np == 0)
- {
- err = ENOMEM;
- goto lose_hash;
- }
-
pthread_mutex_lock (&(*np)->lock);
pthread_mutex_unlock (&idport_ihash_lock);
return 0;
- lose_hash:
- hurd_ihash_locp_remove (&idport_ihash, nn->idport_locp);
lose:
pthread_mutex_unlock (&idport_ihash_lock);
mach_port_deallocate (mach_task_self (), nn->idport);
mach_port_deallocate (mach_task_self (), file);
- free (nn);
+ free (*np);
return err;
}
static void
set_default_attributes (struct node *np)
{
- np->nn->faked = FAKE_UID | FAKE_GID | FAKE_DEFAULT;
+ netfs_node_netnode (np)->faked = FAKE_UID | FAKE_GID | FAKE_DEFAULT;
np->nn_stat.st_uid = 0;
np->nn_stat.st_gid = 0;
}
@@ -140,9 +133,9 @@ set_default_attributes (struct node *np)
static void
set_faked_attribute (struct node *np, unsigned int faked)
{
- np->nn->faked |= faked;
+ netfs_node_netnode (np)->faked |= faked;
- if (np->nn->faked & FAKE_DEFAULT)
+ if (netfs_node_netnode (np)->faked & FAKE_DEFAULT)
{
/* Now that the node has non-default faked attributes, they have to be
retained for future accesses. Account for the hash table reference.
@@ -153,7 +146,7 @@ set_faked_attribute (struct node *np, unsigned int faked)
easy enough if it's ever needed, although scalability could be
improved. */
netfs_nref (np);
- np->nn->faked &= ~FAKE_DEFAULT;
+ netfs_node_netnode (np)->faked &= ~FAKE_DEFAULT;
}
}
@@ -161,18 +154,15 @@ set_faked_attribute (struct node *np, unsigned int faked)
void
netfs_node_norefs (struct node *np)
{
- assert (np->nn->np == np);
-
pthread_mutex_unlock (&np->lock);
pthread_spin_unlock (&netfs_node_refcnt_lock);
pthread_mutex_lock (&idport_ihash_lock);
- hurd_ihash_locp_remove (&idport_ihash, np->nn->idport_locp);
+ hurd_ihash_locp_remove (&idport_ihash, netfs_node_netnode (np)->idport_locp);
pthread_mutex_unlock (&idport_ihash_lock);
- mach_port_deallocate (mach_task_self (), np->nn->file);
- mach_port_deallocate (mach_task_self (), np->nn->idport);
- free (np->nn);
+ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file);
+ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->idport);
free (np);
pthread_spin_lock (&netfs_node_refcnt_lock);
@@ -255,7 +245,8 @@ error_t
netfs_check_open_permissions (struct iouser *user, struct node *np,
int flags, int newnode)
{
- return check_openmodes (np->nn, flags & (O_RDWR|O_EXEC), MACH_PORT_NULL);
+ return check_openmodes (netfs_node_netnode (np),
+ flags & (O_RDWR|O_EXEC), MACH_PORT_NULL);
}
error_t
@@ -281,12 +272,12 @@ netfs_S_dir_lookup (struct protid *diruser,
dnp = diruser->po->np;
- mach_port_t dir = dnp->nn->file;
+ mach_port_t dir = netfs_node_netnode (dnp)->file;
redo_lookup:
err = dir_lookup (dir, filename,
flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK),
mode, do_retry, retry_name, &file);
- if (dir != dnp->nn->file)
+ if (dir != netfs_node_netnode (dnp)->file)
mach_port_deallocate (mach_task_self (), dir);
if (err)
return err;
@@ -358,13 +349,12 @@ netfs_S_dir_lookup (struct protid *diruser,
refcount lock so that, if a node is found, its reference counter cannot
drop to 0 before we get our own reference. */
pthread_spin_lock (&netfs_node_refcnt_lock);
- struct netnode *nn = hurd_ihash_find (&idport_ihash, idport);
- if (nn != NULL)
+ np = hurd_ihash_find (&idport_ihash, idport);
+ if (np != NULL)
{
- assert (nn->np->nn == nn);
/* We already know about this node. */
- if (nn->np->references == 0)
+ if (np->references == 0)
{
/* But it might be in the process of being released. If so,
unlock the hash table to give the node a chance to actually
@@ -376,7 +366,6 @@ netfs_S_dir_lookup (struct protid *diruser,
}
/* Otherwise, reference it right away. */
- np = nn->np;
np->references++;
pthread_spin_unlock (&netfs_node_refcnt_lock);
@@ -392,7 +381,8 @@ netfs_S_dir_lookup (struct protid *diruser,
pthread_mutex_unlock (&dnp->lock);
}
- err = check_openmodes (np->nn, (flags & (O_RDWR|O_EXEC)), file);
+ err = check_openmodes (netfs_node_netnode (np),
+ (flags & (O_RDWR|O_EXEC)), file);
pthread_mutex_unlock (&idport_ihash_lock);
}
else
@@ -460,17 +450,17 @@ error_t
netfs_validate_stat (struct node *np, struct iouser *cred)
{
struct stat st;
- error_t err = io_stat (np->nn->file, &st);
+ error_t err = io_stat (netfs_node_netnode (np)->file, &st);
if (err)
return err;
- if (np->nn->faked & FAKE_UID)
+ if (netfs_node_netnode (np)->faked & FAKE_UID)
st.st_uid = np->nn_stat.st_uid;
- if (np->nn->faked & FAKE_GID)
+ if (netfs_node_netnode (np)->faked & FAKE_GID)
st.st_gid = np->nn_stat.st_gid;
- if (np->nn->faked & FAKE_AUTHOR)
+ if (netfs_node_netnode (np)->faked & FAKE_AUTHOR)
st.st_author = np->nn_stat.st_author;
- if (np->nn->faked & FAKE_MODE)
+ if (netfs_node_netnode (np)->faked & FAKE_MODE)
st.st_mode = np->nn_stat.st_mode;
np->nn_stat = st;
@@ -540,7 +530,7 @@ netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode)
/* We don't bother with error checking since the fake mode change should
always succeed--worst case a later open will get EACCES. */
- (void) file_chmod (np->nn->file, mode);
+ (void) file_chmod (netfs_node_netnode (np)->file, mode);
set_faked_attribute (np, FAKE_MODE);
np->nn_stat.st_mode = mode;
return 0;
@@ -555,7 +545,7 @@ netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name)
char trans[sizeof _HURD_SYMLINK + namelen];
memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK);
memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen);
- return file_set_translator (np->nn->file,
+ return file_set_translator (netfs_node_netnode (np)->file,
FS_TRANS_EXCL|FS_TRANS_SET,
FS_TRANS_EXCL|FS_TRANS_SET, 0,
trans, sizeof trans,
@@ -574,7 +564,7 @@ netfs_attempt_mkdev (struct iouser *cred, struct node *np,
return ENOMEM;
else
{
- error_t err = file_set_translator (np->nn->file,
+ error_t err = file_set_translator (netfs_node_netnode (np)->file,
FS_TRANS_EXCL|FS_TRANS_SET,
FS_TRANS_EXCL|FS_TRANS_SET, 0,
trans, translen + 1,
@@ -588,7 +578,7 @@ netfs_attempt_mkdev (struct iouser *cred, struct node *np,
error_t
netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
{
- return file_chflags (np->nn->file, flags);
+ return file_chflags (netfs_node_netnode (np)->file, flags);
}
error_t
@@ -614,25 +604,25 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np,
else
m.tv.tv_sec = m.tv.tv_usec = -1;
- return file_utimes (np->nn->file, a.tvt, m.tvt);
+ return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt);
}
error_t
netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size)
{
- return file_set_size (np->nn->file, size);
+ return file_set_size (netfs_node_netnode (np)->file, size);
}
error_t
netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
{
- return file_statfs (np->nn->file, st);
+ return file_statfs (netfs_node_netnode (np)->file, st);
}
error_t
netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
{
- return file_sync (np->nn->file, wait, 0);
+ return file_sync (netfs_node_netnode (np)->file, wait, 0);
}
error_t
@@ -645,7 +635,7 @@ error_t
netfs_attempt_mkdir (struct iouser *user, struct node *dir,
char *name, mode_t mode)
{
- return dir_mkdir (dir->nn->file, name, mode | S_IRWXU);
+ return dir_mkdir (netfs_node_netnode (dir)->file, name, mode | S_IRWXU);
}
@@ -657,7 +647,7 @@ netfs_attempt_mkdir (struct iouser *user, struct node *dir,
error_t
netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
{
- return dir_unlink (dir->nn->file, name);
+ return dir_unlink (netfs_node_netnode (dir)->file, name);
}
error_t
@@ -665,22 +655,22 @@ netfs_attempt_rename (struct iouser *user, struct node *fromdir,
char *fromname, struct node *todir,
char *toname, int excl)
{
- return dir_rename (fromdir->nn->file, fromname,
- todir->nn->file, toname, excl);
+ return dir_rename (netfs_node_netnode (fromdir)->file, fromname,
+ netfs_node_netnode (todir)->file, toname, excl);
}
error_t
netfs_attempt_rmdir (struct iouser *user,
struct node *dir, char *name)
{
- return dir_rmdir (dir->nn->file, name);
+ return dir_rmdir (netfs_node_netnode (dir)->file, name);
}
error_t
netfs_attempt_link (struct iouser *user, struct node *dir,
struct node *file, char *name, int excl)
{
- return dir_link (dir->nn->file, file->nn->file, name, excl);
+ return dir_link (netfs_node_netnode (dir)->file, netfs_node_netnode (file)->file, name, excl);
}
error_t
@@ -688,7 +678,7 @@ netfs_attempt_mkfile (struct iouser *user, struct node *dir,
mode_t mode, struct node **np)
{
file_t newfile;
- error_t err = dir_mkfile (dir->nn->file, O_RDWR|O_EXEC,
+ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC,
real_from_fake_mode (mode), &newfile);
pthread_mutex_unlock (&dir->lock);
if (err == 0)
@@ -704,7 +694,8 @@ netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1];
char *trans = transbuf;
size_t translen = sizeof transbuf;
- error_t err = file_get_translator (np->nn->file, &trans, &translen);
+ error_t err = file_get_translator (netfs_node_netnode (np)->file,
+ &trans, &translen);
if (err == 0)
{
if (translen < sizeof _HURD_SYMLINK
@@ -727,7 +718,8 @@ netfs_attempt_read (struct iouser *cred, struct node *np,
off_t offset, size_t *len, void *data)
{
char *buf = data;
- error_t err = io_read (np->nn->file, &buf, len, offset, *len);
+ error_t err = io_read (netfs_node_netnode (np)->file,
+ &buf, len, offset, *len);
if (err == 0 && buf != data)
{
memcpy (data, buf, *len);
@@ -740,7 +732,7 @@ error_t
netfs_attempt_write (struct iouser *cred, struct node *np,
off_t offset, size_t *len, void *data)
{
- return io_write (np->nn->file, data, *len, offset, len);
+ return io_write (netfs_node_netnode (np)->file, data, *len, offset, len);
}
error_t
@@ -756,7 +748,7 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
mach_msg_type_number_t *datacnt,
vm_size_t bufsize, int *amt)
{
- return dir_readdir (dir->nn->file, data, datacnt,
+ return dir_readdir (netfs_node_netnode (dir)->file, data, datacnt,
entry, nentries, bufsize, amt);
}
@@ -774,7 +766,7 @@ netfs_file_get_storage_info (struct iouser *cred,
mach_msg_type_number_t *data_len)
{
*ports_type = MACH_MSG_TYPE_MOVE_SEND;
- return file_get_storage_info (np->nn->file,
+ return file_get_storage_info (netfs_node_netnode (np)->file,
ports, num_ports,
ints, num_ints,
offsets, num_offsets,
@@ -807,8 +799,9 @@ netfs_S_file_exec (struct protid *user,
return EOPNOTSUPP;
pthread_mutex_lock (&user->po->np->lock);
- err = check_openmodes (user->po->np->nn, O_EXEC, MACH_PORT_NULL);
- file = user->po->np->nn->file;
+ err = check_openmodes (netfs_node_netnode (user->po->np),
+ O_EXEC, MACH_PORT_NULL);
+ file = netfs_node_netnode (user->po->np)->file;
if (!err)
err = mach_port_mod_refs (mach_task_self (),
file, MACH_PORT_RIGHT_SEND, 1);
@@ -818,7 +811,8 @@ netfs_S_file_exec (struct protid *user,
{
/* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to
retry an interrupted call that would have consumed the rights. */
- err = file_exec (user->po->np->nn->file, task, flags, argv, argvlen,
+ err = file_exec (netfs_node_netnode (user->po->np)->file,
+ task, flags, argv, argvlen,
envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
intarray, intarraylen, deallocnames, deallocnameslen,
@@ -850,7 +844,7 @@ netfs_S_io_map (struct protid *user,
*rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND;
pthread_mutex_lock (&user->po->np->lock);
- err = io_map (user->po->np->nn->file, rdobj, wrobj);
+ err = io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj);
pthread_mutex_unlock (&user->po->np->lock);
return err;
}
@@ -867,7 +861,7 @@ netfs_S_io_map_cntl (struct protid *user,
*objtype = MACH_MSG_TYPE_MOVE_SEND;
pthread_mutex_lock (&user->po->np->lock);
- err = io_map_cntl (user->po->np->nn->file, obj);
+ err = io_map_cntl (netfs_node_netnode (user->po->np)->file, obj);
pthread_mutex_unlock (&user->po->np->lock);
return err;
}
@@ -888,7 +882,8 @@ netfs_S_io_identity (struct protid *user,
*idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND;
pthread_mutex_lock (&user->po->np->lock);
- err = io_identity (user->po->np->nn->file, id, fsys, fileno);
+ err = io_identity (netfs_node_netnode (user->po->np)->file,
+ id, fsys, fileno);
pthread_mutex_unlock (&user->po->np->lock);
return err;
}
@@ -903,7 +898,7 @@ netfs_S_##name (struct protid *user) \
return EOPNOTSUPP; \
\
pthread_mutex_lock (&user->po->np->lock); \
- err = name (user->po->np->nn->file); \
+ err = name (netfs_node_netnode (user->po->np)->file); \
pthread_mutex_unlock (&user->po->np->lock); \
return err; \
}
@@ -925,7 +920,7 @@ netfs_S_io_prenotify (struct protid *user,
return EOPNOTSUPP;
pthread_mutex_lock (&user->po->np->lock);
- err = io_prenotify (user->po->np->nn->file, start, stop);
+ err = io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop);
pthread_mutex_unlock (&user->po->np->lock);
return err;
}
@@ -940,7 +935,7 @@ netfs_S_io_postnotify (struct protid *user,
return EOPNOTSUPP;
pthread_mutex_lock (&user->po->np->lock);
- err = io_postnotify (user->po->np->nn->file, start, stop);
+ err = io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop);
pthread_mutex_unlock (&user->po->np->lock);
return err;
}
@@ -983,7 +978,7 @@ netfs_demuxer (mach_msg_header_t *inp,
| MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
MACH_MSGH_BITS_REMOTE (inp->msgh_bits));
inp->msgh_local_port = inp->msgh_remote_port; /* reply port */
- inp->msgh_remote_port = cred->po->np->nn->file;
+ inp->msgh_remote_port = netfs_node_netnode (cred->po->np)->file;
err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);