diff options
17 files changed, 5014 insertions, 0 deletions
diff --git a/debian/patches/0001-ext2fs-use-a-seperate-lock-to-protect-nodehash.patch b/debian/patches/0001-ext2fs-use-a-seperate-lock-to-protect-nodehash.patch new file mode 100644 index 00000000..2291bea9 --- /dev/null +++ b/debian/patches/0001-ext2fs-use-a-seperate-lock-to-protect-nodehash.patch @@ -0,0 +1,260 @@ +From 4166312a45357c2ff11b00219dfb83b7475ac4b1 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 13 May 2014 13:09:15 +0200 +Subject: [PATCH hurd 01/16] ext2fs: use a seperate lock to protect nodehash + +Previously, ext2fs used diskfs_node_refcnt_lock to serialize access to +the nodehash. + +Use a separate lock to protect nodehash. Adjust the reference +counting accordingly. Every node in the nodehash carries a light +reference. When we are asked to give up that light reference, we +reacquire our lock momentarily to check whether someone else +reacquired a reference through the nodehash. + +* ext2fs/inode.c (nodecache_lock): New lock. +(diskfs_cached_lookup): Use a separate lock to protect nodehash. +Adjust the reference counting accordingly. +(ifind): Likewise. +(diskfs_node_iterate): Likewise. +(diskfs_node_norefs): Move the code removing the node from nodehash... +(diskfs_try_dropping_softrefs): ... here, where we check whether +someone reacquired a reference, and if so hold on to our light +reference. +--- + ext2fs/inode.c | 128 +++++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 92 insertions(+), 36 deletions(-) + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 6b8b749..7c8d5a8 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -46,8 +46,19 @@ + #define INOHASH(ino) (((unsigned)(ino))%INOHSZ) + #endif + ++/* The nodehash is a cache of nodes. ++ ++ Access to nodehash and nodehash_nr_items is protected by ++ nodecache_lock. ++ ++ Every node in the nodehash carries a light reference. When we are ++ asked to give up that light reference, we reacquire our lock ++ momentarily to check whether someone else reacquired a reference ++ through the nodehash. */ + static struct node *nodehash[INOHSZ]; + static size_t nodehash_nr_items; ++/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static error_t read_node (struct node *np); + +@@ -62,33 +73,37 @@ inode_init () + nodehash[n] = 0; + } + ++/* Lookup node with inode number INUM. Returns NULL if the node is ++ not found in the node cache. */ ++static struct node * ++lookup (ino_t inum) ++{ ++ struct node *np; ++ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) ++ if (np->cache_id == inum) ++ return np; ++ return NULL; ++} ++ + /* Fetch inode INUM, set *NPP to the node structure; + gain one user reference and lock the node. */ + error_t + diskfs_cached_lookup (ino_t inum, struct node **npp) + { + error_t err; +- struct node *np; ++ struct node *np, *tmp; + struct disknode *dn; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- if (np->cache_id == inum) +- { +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_lock (&np->lock); +- *npp = np; +- return 0; +- } ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ if (np) ++ goto gotit; ++ pthread_rwlock_unlock (&nodecache_lock); + + /* Format specific data for the new node. */ + dn = malloc (sizeof (struct disknode)); + if (! dn) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return ENOMEM; +- } ++ return ENOMEM; + dn->dirents = 0; + dn->dir_idx = 0; + dn->pager = 0; +@@ -102,14 +117,24 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + pthread_mutex_lock (&np->lock); + + /* Put NP in NODEHASH. */ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ tmp = lookup (inum); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = tmp; ++ goto gotit; ++ } ++ + dn->hnext = nodehash[INOHASH(inum)]; + if (dn->hnext) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; ++ diskfs_nref_light (np); + nodehash_nr_items += 1; +- +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + + /* Get the contents of NP off disk. */ + err = read_node (np); +@@ -131,6 +156,13 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + *npp = np; + return 0; + } ++ ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&np->lock); ++ *npp = np; ++ return 0; + } + + /* Lookup node INUM (which must have a reference already) and return it +@@ -140,17 +172,12 @@ ifind (ino_t inum) + { + struct node *np; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- { +- if (np->cache_id != inum) +- continue; ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ pthread_rwlock_unlock (&nodecache_lock); + +- assert (np->references); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return np; +- } +- assert (0); ++ assert (np); ++ return np; + } + + /* The last reference to a node has gone away; drop +@@ -158,11 +185,6 @@ ifind (ino_t inum) + void + diskfs_node_norefs (struct node *np) + { +- *np->dn->hprevp = np->dn->hnext; +- if (np->dn->hnext) +- np->dn->hnext->dn->hprevp = np->dn->hprevp; +- nodehash_nr_items -= 1; +- + if (np->dn->dirents) + free (np->dn->dirents); + assert (!np->dn->pager); +@@ -180,6 +202,36 @@ diskfs_node_norefs (struct node *np) + void + diskfs_try_dropping_softrefs (struct node *np) + { ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (np->dn->hprevp != NULL) ++ { ++ /* Check if someone reacquired a reference through the ++ nodehash. */ ++ unsigned int references; ++ pthread_spin_lock (&diskfs_node_refcnt_lock); ++ references = np->references; ++ pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ ++ /* An additional reference is acquired by libdiskfs across calls ++ to diskfs_try_dropping_softrefs. */ ++ if (references > 1) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_rwlock_unlock (&nodecache_lock); ++ return; ++ } ++ ++ *np->dn->hprevp = np->dn->hnext; ++ if (np->dn->hnext) ++ np->dn->hnext->dn->hprevp = np->dn->hprevp; ++ np->dn->hnext = NULL; ++ np->dn->hprevp = NULL; ++ nodehash_nr_items -= 1; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&nodecache_lock); ++ + drop_pager_softrefs (np); + } + +@@ -556,12 +608,12 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + size_t num_nodes; + struct node *node, **node_list, **p; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_rdlock (&nodecache_lock); + + /* We must copy everything from the hash table into another data structure + to avoid running into any problems with the hash-table being modified + during processing (normally we delegate access to hash-table with +- diskfs_node_refcnt_lock, but we can't hold this while locking the ++ nodecache_lock, but we can't hold this while locking the + individual node locks). */ + num_nodes = nodehash_nr_items; + +@@ -570,7 +622,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + node_list = malloc (num_nodes * sizeof (struct node *)); + if (node_list == NULL) + { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + ext2_debug ("unable to allocate temporary node table"); + return ENOMEM; + } +@@ -580,10 +632,14 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + for (node = nodehash[n]; node; node = node->dn->hnext) + { + *p++ = node; ++ ++ /* We acquire a hard reference for node, but without using ++ diskfs_nref. We do this so that diskfs_new_hardrefs will not ++ get called. */ + node->references++; + } + +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + + p = node_list; + while (num_nodes-- > 0) +-- +2.1.4 + diff --git a/debian/patches/0002-fatfs-use-a-seperate-lock-to-protect-nodehash.patch b/debian/patches/0002-fatfs-use-a-seperate-lock-to-protect-nodehash.patch new file mode 100644 index 00000000..990cf274 --- /dev/null +++ b/debian/patches/0002-fatfs-use-a-seperate-lock-to-protect-nodehash.patch @@ -0,0 +1,304 @@ +From e17366f09a6003dcc95633ce312aa3753f056e28 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 13 May 2014 15:14:53 +0200 +Subject: [PATCH hurd 02/16] fatfs: use a seperate lock to protect nodehash + +Previously, fatfs used diskfs_node_refcnt_lock to serialize access to +the nodehash. + +Use a separate lock to protect nodehash. Adjust the reference +counting accordingly. Every node in the nodehash carries a light +reference. When we are asked to give up that light reference, we +reacquire our lock momentarily to check whether someone else +reacquired a reference through the nodehash. + +* fatfs/inode.c (nodecache_lock): New lock. +(diskfs_cached_lookup): Use a separate lock to protect nodehash. +Adjust the reference counting accordingly. +(ifind): Likewise. +(diskfs_node_iterate): Likewise. +(diskfs_node_norefs): Move the code removing the node from nodehash... +(diskfs_try_dropping_softrefs): ... here, where we check whether +someone reacquired a reference, and if so hold on to our light +reference. +--- + fatfs/inode.c | 147 ++++++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 102 insertions(+), 45 deletions(-) + +diff --git a/fatfs/inode.c b/fatfs/inode.c +index ed6f3f0..1d670f5 100644 +--- a/fatfs/inode.c ++++ b/fatfs/inode.c +@@ -44,8 +44,19 @@ + #define INOHASH(ino) (((unsigned)(ino))%INOHSZ) + #endif + ++/* The nodehash is a cache of nodes. ++ ++ Access to nodehash and nodehash_nr_items is protected by ++ nodecache_lock. ++ ++ Every node in the nodehash carries a light reference. When we are ++ asked to give up that light reference, we reacquire our lock ++ momentarily to check whether someone else reacquired a reference ++ through the nodehash. */ + static struct node *nodehash[INOHSZ]; + static size_t nodehash_nr_items; ++/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static error_t read_node (struct node *np, vm_address_t buf); + +@@ -58,33 +69,38 @@ inode_init () + nodehash[n] = 0; + } + ++/* Lookup node with inode number INUM. Returns NULL if the node is ++ not found in the node cache. */ ++static struct node * ++lookup (ino_t inum) ++{ ++ struct node *np; ++ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) ++ if (np->cache_id == inum) ++ return np; ++ return NULL; ++} ++ + /* Fetch inode INUM, set *NPP to the node structure; gain one user + reference and lock the node. */ + error_t + diskfs_cached_lookup (ino64_t inum, struct node **npp) + { + error_t err; +- struct node *np; ++ struct node *np, *tmp; + struct disknode *dn; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- if (np->cache_id == inum) +- { +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_lock (&np->lock); +- *npp = np; +- return 0; +- } ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ if (np) ++ goto gotit; ++ pthread_rwlock_unlock (&nodecache_lock); + + /* Format specific data for the new node. */ + dn = malloc (sizeof (struct disknode)); + if (! dn) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return ENOMEM; +- } ++ return ENOMEM; ++ + dn->pager = 0; + dn->first = 0; + dn->last = 0; +@@ -102,15 +118,25 @@ diskfs_cached_lookup (ino64_t inum, struct node **npp) + pthread_mutex_lock (&np->lock); + + /* Put NP in NODEHASH. */ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ tmp = lookup (inum); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = tmp; ++ goto gotit; ++ } ++ + dn->hnext = nodehash[INOHASH(inum)]; + if (dn->hnext) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; ++ diskfs_nref_light (np); + nodehash_nr_items += 1; ++ pthread_rwlock_unlock (&nodecache_lock); + +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- + /* Get the contents of NP off disk. */ + err = read_node (np, 0); + +@@ -121,6 +147,13 @@ diskfs_cached_lookup (ino64_t inum, struct node **npp) + *npp = np; + return 0; + } ++ ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&np->lock); ++ *npp = np; ++ return 0; + } + + /* Fetch inode INUM, set *NPP to the node structure; +@@ -133,24 +166,23 @@ diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf) + struct node *np; + struct disknode *dn; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_rdlock (&nodecache_lock); + for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) + if (np->cache_id == inum) + { +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); + pthread_mutex_lock (&np->lock); + *npp = np; + return 0; + } ++ pthread_rwlock_unlock (&nodecache_lock); + + /* Format specific data for the new node. */ + dn = malloc (sizeof (struct disknode)); + if (! dn) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return ENOMEM; +- } ++ return ENOMEM; ++ + dn->pager = 0; + dn->first = 0; + dn->last = 0; +@@ -168,15 +200,16 @@ diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf) + pthread_mutex_lock (&np->lock); + + /* Put NP in NODEHASH. */ ++ pthread_rwlock_wrlock (&nodecache_lock); + dn->hnext = nodehash[INOHASH(inum)]; + if (dn->hnext) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; ++ diskfs_nref_light (np); + nodehash_nr_items += 1; ++ pthread_rwlock_unlock (&nodecache_lock); + +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- + /* Get the contents of NP off disk. */ + err = read_node (np, buf); + +@@ -196,17 +229,12 @@ ifind (ino_t inum) + { + struct node *np; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- { +- if (np->cache_id != inum) +- continue; ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ pthread_rwlock_unlock (&nodecache_lock); + +- assert (np->references); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return np; +- } +- assert (0); ++ assert (np); ++ return np; + } + + /* The last reference to a node has gone away; drop it from the hash +@@ -216,11 +244,6 @@ diskfs_node_norefs (struct node *np) + { + struct cluster_chain *last = np->dn->first; + +- *np->dn->hprevp = np->dn->hnext; +- if (np->dn->hnext) +- np->dn->hnext->dn->hprevp = np->dn->hprevp; +- nodehash_nr_items -= 1; +- + while (last) + { + struct cluster_chain *next = last->next; +@@ -251,6 +274,36 @@ diskfs_node_norefs (struct node *np) + void + diskfs_try_dropping_softrefs (struct node *np) + { ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (np->dn->hprevp != NULL) ++ { ++ /* Check if someone reacquired a reference through the ++ nodehash. */ ++ unsigned int references; ++ pthread_spin_lock (&diskfs_node_refcnt_lock); ++ references = np->references; ++ pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ ++ /* An additional reference is acquired by libdiskfs across calls ++ to diskfs_try_dropping_softrefs. */ ++ if (references > 1) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_rwlock_unlock (&nodecache_lock); ++ return; ++ } ++ ++ *np->dn->hprevp = np->dn->hnext; ++ if (np->dn->hnext) ++ np->dn->hnext->dn->hprevp = np->dn->hprevp; ++ np->dn->hnext = NULL; ++ np->dn->hprevp = NULL; ++ nodehash_nr_items -= 1; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&nodecache_lock); ++ + drop_pager_softrefs (np); + } + +@@ -554,12 +607,12 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + size_t num_nodes; + struct node *node, **node_list, **p; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_rdlock (&nodecache_lock); + + /* We must copy everything from the hash table into another data structure + to avoid running into any problems with the hash-table being modified + during processing (normally we delegate access to hash-table with +- diskfs_node_refcnt_lock, but we can't hold this while locking the ++ nodecache_lock, but we can't hold this while locking the + individual node locks). */ + + num_nodes = nodehash_nr_items; +@@ -570,10 +623,14 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + for (node = nodehash[n]; node; node = node->dn->hnext) + { + *p++ = node; +- node->references++; ++ ++ /* We acquire a hard reference for node, but without using ++ diskfs_nref. We do this so that diskfs_new_hardrefs will not ++ get called. */ ++ node->references++; + } + +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + + p = node_list; + while (num_nodes-- > 0) +-- +2.1.4 + diff --git a/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch b/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch new file mode 100644 index 00000000..005269f8 --- /dev/null +++ b/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch @@ -0,0 +1,310 @@ +From 912151f13737af551d3d3dd2e45faef3bd7c78cb Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 13 May 2014 15:16:31 +0200 +Subject: [PATCH hurd 03/16] isofs: use a seperate lock to protect node_cache + +Previously, isofs used diskfs_node_refcnt_lock to serialize access to +the node_cache. + +Use a separate lock to protect node_cache. Adjust the reference +counting accordingly. Every node in the node_cache carries a light +reference. When we are asked to give up that light reference, we +reacquire our lock momentarily to check whether someone else +reacquired a reference through the node_cache. + +* isofs/inode.c (nodecache_lock): New lock. +(inode_cache_find): Use a separate lock to protect node_cache. +Adjust the reference counting accordingly. +(diskfs_cached_lookup): Likewise. +(load_inode): Likewise. +(cache_inode): Update comment accordingly. +(diskfs_node_iterate): Likewise. +(diskfs_node_norefs): Move the code removing the node from node_cache... +(diskfs_try_dropping_softrefs): ... here, where we check whether +someone reacquired a reference, and if so hold on to our light +reference. +--- + isofs/inode.c | 146 +++++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 105 insertions(+), 41 deletions(-) + +diff --git a/isofs/inode.c b/isofs/inode.c +index 247d8ac..37bf1ac 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -48,35 +48,53 @@ struct node_cache + struct node *np; /* if live */ + }; + ++/* The node_cache is a cache of nodes. ++ ++ Access to node_cache, node_cache_size, and node_cache_alloced is ++ protected by nodecache_lock. ++ ++ Every node in the node_cache carries a light reference. When we ++ are asked to give up that light reference, we reacquire our lock ++ momentarily to check whether someone else reacquired a reference ++ through the node_cache. */ + static int node_cache_size = 0; + static int node_cache_alloced = 0; + struct node_cache *node_cache = 0; ++/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + /* Forward */ + static error_t read_disknode (struct node *, + struct dirrect *, struct rrip_lookup *); + + ++/* Lookup node with id ID. Returns NULL if the node is not found in ++ the node cache. */ ++static struct node * ++lookup (off_t id) ++{ ++ int i; ++ for (i = 0; i < node_cache_size; i++) ++ if (node_cache[i].id == id ++ && node_cache[i].np) ++ return node_cache[i].np; ++ return NULL; ++} ++ + /* See if node with identifier ID is in the cache. If so, return it, +- with one additional reference. diskfs_node_refcnt_lock must be held ++ with one additional reference. nodecache_lock must be held + on entry to the call, and will be released iff the node was found + in the cache. */ + void + inode_cache_find (off_t id, struct node **npp) + { +- int i; +- +- for (i = 0; i < node_cache_size; i++) +- if (node_cache[i].id == id +- && node_cache[i].np) +- { +- *npp = node_cache[i].np; +- (*npp)->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_lock (&(*npp)->lock); +- return; +- } +- *npp = 0; ++ *npp = lookup (id); ++ if (*npp) ++ { ++ diskfs_nref (*npp); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&(*npp)->lock); ++ } + } + + +@@ -92,7 +110,7 @@ use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) + } + + /* Enter NP into the cache. The directory entry we used is DR, the +- cached Rock-Ridge info RR. diskfs_node_refcnt_lock must be held. */ ++ cached Rock-Ridge info RR. nodecache_lock must be held. */ + void + cache_inode (struct node *np, struct dirrect *record, + struct rrip_lookup *rr) +@@ -137,6 +155,7 @@ cache_inode (struct node *np, struct dirrect *record, + c->id = id; + c->dr = record; + c->file_start = np->dn->file_start; ++ diskfs_nref_light (np); + c->np = np; + + /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */ +@@ -155,7 +174,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + to avoid presenting zero cache ID's. */ + id--; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_rdlock (&nodecache_lock); + assert (id < node_cache_size); + + np = node_cache[id].np; +@@ -166,6 +185,8 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + struct rrip_lookup rr; + struct disknode *dn; + ++ pthread_rwlock_unlock (&nodecache_lock); ++ + rrip_lookup (node_cache[id].dr, &rr, 1); + + /* We should never cache the wrong directory entry */ +@@ -174,7 +195,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + dn = malloc (sizeof (struct disknode)); + if (!dn) + { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + release_rrip (&rr); + return ENOMEM; + } +@@ -185,16 +206,26 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + if (!np) + { + free (dn); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + release_rrip (&rr); + return ENOMEM; + } + np->cache_id = id + 1; /* see above for rationale for increment */ + pthread_mutex_lock (&np->lock); ++ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (c->np != NULL) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = c->np; ++ goto gotit; ++ } + c->np = np; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ diskfs_nref_light (np); ++ pthread_rwlock_unlock (&nodecache_lock); + +- err = read_disknode (np, node_cache[id].dr, &rr); ++ err = read_disknode (np, dn->dr, &rr); + if (!err) + *npp = np; + +@@ -203,9 +234,9 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + return err; + } + +- +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); + pthread_mutex_lock (&np->lock); + *npp = np; + return 0; +@@ -307,7 +338,8 @@ load_inode (struct node **npp, struct dirrect *record, + error_t err; + off_t file_start; + struct disknode *dn; +- struct node *np; ++ struct node *np, *tmp; ++ off_t id; + + err = calculate_file_start (record, &file_start, rr); + if (err) +@@ -315,27 +347,23 @@ load_inode (struct node **npp, struct dirrect *record, + if (rr->valid & VALID_CL) + record = rr->realdirent; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- + /* First check the cache */ + if (use_file_start_id (record, rr)) +- inode_cache_find (file_start << store->log2_block_size, npp); ++ id = file_start << store->log2_block_size; + else +- inode_cache_find ((off_t) ((void *) record - (void *) disk_image), npp); ++ id = (off_t) ((void *) record - (void *) disk_image); + ++ pthread_rwlock_rdlock (&nodecache_lock); ++ inode_cache_find (id, npp); + if (*npp) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return 0; +- } ++ return 0; ++ pthread_rwlock_unlock (&nodecache_lock); + + /* Create a new node */ + dn = malloc (sizeof (struct disknode)); + if (!dn) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return ENOMEM; +- } ++ return ENOMEM; ++ + dn->fileinfo = 0; + dn->dr = record; + dn->file_start = file_start; +@@ -344,14 +372,25 @@ load_inode (struct node **npp, struct dirrect *record, + if (!np) + { + free (dn); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); + return ENOMEM; + } + + pthread_mutex_lock (&np->lock); + ++ pthread_rwlock_wrlock (&nodecache_lock); ++ tmp = lookup (id); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ diskfs_nref (tmp); ++ *npp = tmp; ++ pthread_rwlock_unlock (&nodecache_lock); ++ return 0; ++ } ++ + cache_inode (np, record, rr); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&nodecache_lock); + + err = read_disknode (np, record, rr); + *npp = np; +@@ -505,9 +544,6 @@ error_t (*diskfs_read_symlink_hook) (struct node *, char *) + void + diskfs_node_norefs (struct node *np) + { +- assert (node_cache[np->cache_id - 1].np == np); +- node_cache[np->cache_id - 1].np = 0; +- + if (np->dn->translator) + free (np->dn->translator); + +@@ -521,6 +557,34 @@ diskfs_node_norefs (struct node *np) + void + diskfs_try_dropping_softrefs (struct node *np) + { ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (np->cache_id != 0) ++ { ++ assert (node_cache[np->cache_id - 1].np == np); ++ ++ /* Check if someone reacquired a reference through the ++ node_cache. */ ++ unsigned int references; ++ pthread_spin_lock (&diskfs_node_refcnt_lock); ++ references = np->references; ++ pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ ++ /* An additional reference is acquired by libdiskfs across calls ++ to diskfs_try_dropping_softrefs. */ ++ if (references > 1) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_rwlock_unlock (&nodecache_lock); ++ return; ++ } ++ ++ node_cache[np->cache_id - 1].np = 0; ++ np->cache_id = 0; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&nodecache_lock); ++ + drop_pager_softrefs (np); + } + +-- +2.1.4 + diff --git a/debian/patches/0004-tmpfs-use-a-seperate-lock-to-protect-all_nodes.patch b/debian/patches/0004-tmpfs-use-a-seperate-lock-to-protect-all_nodes.patch new file mode 100644 index 00000000..d6d9fd09 --- /dev/null +++ b/debian/patches/0004-tmpfs-use-a-seperate-lock-to-protect-all_nodes.patch @@ -0,0 +1,314 @@ +From ba3560bd19188297a2bc51447b2006ced7d5c615 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 13 May 2014 15:35:42 +0200 +Subject: [PATCH hurd 04/16] tmpfs: use a seperate lock to protect all_nodes + +Previously, tmpfs used diskfs_node_refcnt_lock to serialize access to +the all_nodes and some other related global state related to memory +consumption. + +Use a separate lock to protect all_nodes, and atomic operations to +access the state related to memory consumption. Adjust the reference +counting accordingly. Every node in the all_nodes carries a light +reference. When we are asked to give up that light reference, we +reacquire our lock momentarily to check whether someone else +reacquired a reference through the all_nodes. + +* tmpfs/tmpfs.h (num_files, tmpfs_space_used): Use atomic operations +for these variables. +(adjust_used): Use atomic operations. +(get_used): New convenience function to atomically retrieve +tmpfs_space_used. +* tmpfs/node.c (all_nodes_lock): New lock. +(diskfs_alloc_node): Use a separate lock to protect all_nodes. +Adjust the reference counting accordingly. +(diskfs_free_node): Likewise. +(diskfs_cached_lookup):Likewise. +(diskfs_node_iterate): Likewise. +(diskfs_node_norefs): Do not remove the node from all_nodes. This +actually looks like a mistake, I do not know why they did that here as +well as in diskfs_free_node. +(diskfs_try_dropping_softrefs): Check whether someone reacquired a +reference, and if so hold on to our light reference. +(diskfs_grow): Use atomic operations. +* tmpfs/tmpfs.c (diskfs_set_statfs): Likewise. +--- + tmpfs/node.c | 107 ++++++++++++++++++++++++++++++++++++++++++---------------- + tmpfs/tmpfs.c | 6 ++-- + tmpfs/tmpfs.h | 20 +++++++---- + 3 files changed, 94 insertions(+), 39 deletions(-) + +diff --git a/tmpfs/node.c b/tmpfs/node.c +index 02d7a60..428b6d9 100644 +--- a/tmpfs/node.c ++++ b/tmpfs/node.c +@@ -29,8 +29,19 @@ + unsigned int num_files; + static unsigned int gen; + ++/* all_nodes is a list of all nodes. ++ ++ Access to all_nodes and all_nodes_nr_items is protected by ++ all_nodes_lock. ++ ++ Every node in all_nodes carries a light reference. When we are ++ asked to give up that light reference, we reacquire our lock ++ momentarily to check whether someone else reacquired a ++ reference. */ + struct node *all_nodes; + static size_t all_nodes_nr_items; ++/* all_nodes_lock must be acquired before diskfs_node_refcnt_lock. */ ++pthread_rwlock_t all_nodes_lock = PTHREAD_RWLOCK_INITIALIZER; + + error_t + diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp) +@@ -40,18 +51,17 @@ diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp) + dn = calloc (1, sizeof *dn); + if (dn == 0) + return ENOSPC; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- if (round_page (tmpfs_space_used + sizeof *dn) / vm_page_size ++ ++ if (round_page (get_used () + sizeof *dn) / vm_page_size + > tmpfs_page_limit) + { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&all_nodes_lock); + free (dn); + return ENOSPC; + } + dn->gen = gen++; +- ++num_files; +- tmpfs_space_used += sizeof *dn; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ __atomic_add_fetch (&num_files, 1, __ATOMIC_RELAXED); ++ adjust_used (sizeof *dn); + + dn->type = IFTODT (mode & S_IFMT); + return diskfs_cached_lookup ((ino_t) (uintptr_t) dn, npp); +@@ -75,15 +85,19 @@ diskfs_free_node (struct node *np, mode_t mode) + free (np->dn->u.lnk); + break; + } ++ ++ pthread_rwlock_wrlock (&all_nodes_lock); + *np->dn->hprevp = np->dn->hnext; + if (np->dn->hnext != 0) + np->dn->hnext->dn->hprevp = np->dn->hprevp; + all_nodes_nr_items -= 1; ++ pthread_rwlock_unlock (&all_nodes_lock); ++ + free (np->dn); + np->dn = 0; + +- --num_files; +- tmpfs_space_used -= sizeof *np->dn; ++ __atomic_sub_fetch (&num_files, 1, __ATOMIC_RELAXED); ++ adjust_used (-sizeof *np->dn); + } + + void +@@ -117,14 +131,6 @@ diskfs_node_norefs (struct node *np) + np->dn->u.chr = np->dn_stat.st_rdev; + break; + } +- +- /* Remove this node from the cache list rooted at `all_nodes'. */ +- *np->dn->hprevp = np->dn->hnext; +- if (np->dn->hnext != 0) +- np->dn->hnext->dn->hprevp = np->dn->hprevp; +- all_nodes_nr_items -= 1; +- np->dn->hnext = 0; +- np->dn->hprevp = 0; + } + + free (np); +@@ -167,30 +173,34 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + + assert (npp); + ++ pthread_rwlock_rdlock (&all_nodes_lock); + if (dn->hprevp != 0) /* There is already a node. */ +- { +- np = *dn->hprevp; +- assert (np->dn == dn); +- assert (*dn->hprevp == np); +- +- diskfs_nref (np); +- } ++ goto gotit; + else + /* Create the new node. */ + { + struct stat *st; ++ pthread_rwlock_unlock (&all_nodes_lock); + + np = diskfs_make_node (dn); + np->cache_id = (ino_t) (uintptr_t) dn; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_wrlock (&all_nodes_lock); ++ if (dn->hprevp != NULL) ++ { ++ /* We lost a race. */ ++ diskfs_nrele (np); ++ goto gotit; ++ } ++ + dn->hnext = all_nodes; + if (dn->hnext) + dn->hnext->dn->hprevp = &dn->hnext; + dn->hprevp = &all_nodes; + all_nodes = np; + all_nodes_nr_items += 1; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ diskfs_nref_light (np); ++ pthread_rwlock_unlock (&all_nodes_lock); + + st = &np->dn_stat; + memset (st, 0, sizeof *st); +@@ -220,6 +230,16 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + pthread_mutex_lock (&np->lock); + *npp = np; + return 0; ++ ++ gotit: ++ np = *dn->hprevp; ++ assert (np->dn == dn); ++ assert (*dn->hprevp == np); ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&all_nodes_lock); ++ pthread_mutex_lock (&np->lock); ++ *npp = np; ++ return 0; + } + + error_t +@@ -229,12 +249,12 @@ diskfs_node_iterate (error_t (*fun) (struct node *)) + size_t num_nodes; + struct node *node, **node_list, **p; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_rdlock (&all_nodes_lock); + + /* We must copy everything from the hash table into another data structure + to avoid running into any problems with the hash-table being modified + during processing (normally we delegate access to hash-table with +- diskfs_node_refcnt_lock, but we can't hold this while locking the ++ all_nodes_lock, but we can't hold this while locking the + individual node locks). */ + + num_nodes = all_nodes_nr_items; +@@ -243,10 +263,14 @@ diskfs_node_iterate (error_t (*fun) (struct node *)) + for (node = all_nodes; node != 0; node = node->dn->hnext) + { + *p++ = node; ++ ++ /* We acquire a hard reference for node, but without using ++ diskfs_nref. We do this so that diskfs_new_hardrefs will not ++ get called. */ + node->references++; + } + +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ pthread_rwlock_unlock (&all_nodes_lock); + + p = node_list; + while (num_nodes-- > 0) +@@ -272,6 +296,31 @@ diskfs_node_iterate (error_t (*fun) (struct node *)) + void + diskfs_try_dropping_softrefs (struct node *np) + { ++ pthread_rwlock_wrlock (&all_nodes_lock); ++ if (np->cache_id != 0) ++ { ++ /* Check if someone reacquired a reference. */ ++ unsigned int references; ++ pthread_spin_lock (&diskfs_node_refcnt_lock); ++ references = np->references; ++ pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ ++ /* An additional reference is acquired by libdiskfs across calls ++ to diskfs_try_dropping_softrefs. */ ++ if (references > 1) ++ { ++ /* A reference was reacquired. It's fine, we didn't touch ++ anything yet. */ ++ pthread_rwlock_unlock (&all_nodes_lock); ++ return; ++ } ++ ++ /* Just let go of the weak reference. The node will be removed ++ from all_nodes in diskfs_free_node. */ ++ np->cache_id = 0; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&all_nodes_lock); + } + + /* The user must define this funcction. Node NP has some light +@@ -447,7 +496,7 @@ diskfs_grow (struct node *np, off_t size, struct protid *cred) + + off_t set_size = size; + size = round_page (size); +- if (round_page (tmpfs_space_used + size - np->allocsize) ++ if (round_page (get_used () + size - np->allocsize) + / vm_page_size > tmpfs_page_limit) + return ENOSPC; + +diff --git a/tmpfs/tmpfs.c b/tmpfs/tmpfs.c +index 1b5b374..fd1c9aa 100644 +--- a/tmpfs/tmpfs.c ++++ b/tmpfs/tmpfs.c +@@ -67,10 +67,8 @@ diskfs_set_statfs (struct statfs *st) + st->f_bsize = vm_page_size; + st->f_blocks = tmpfs_page_limit; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- st->f_files = num_files; +- pages = round_page (tmpfs_space_used) / vm_page_size; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ st->f_files = __atomic_load_n (&num_files, __ATOMIC_RELAXED); ++ pages = round_page (get_used ()) / vm_page_size; + + st->f_bfree = pages < tmpfs_page_limit ? tmpfs_page_limit - pages : 0; + st->f_bavail = st->f_bfree; +diff --git a/tmpfs/tmpfs.h b/tmpfs/tmpfs.h +index b3c636d..ad47200 100644 +--- a/tmpfs/tmpfs.h ++++ b/tmpfs/tmpfs.h +@@ -69,17 +69,25 @@ struct tmpfs_dirent + char name[0]; + }; + +-extern unsigned int num_files; +-extern off_t tmpfs_page_limit, tmpfs_space_used; +- ++extern off_t tmpfs_page_limit; + extern mach_port_t default_pager; + ++/* These two must be accessed using atomic operations. */ ++extern unsigned int num_files; ++extern off_t tmpfs_space_used; ++ ++/* Convenience function to adjust tmpfs_space_used. */ + static inline void + adjust_used (off_t change) + { +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- tmpfs_space_used += change; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ __atomic_add_fetch (&num_files, change, __ATOMIC_RELAXED); ++} ++ ++/* Convenience function to get tmpfs_space_used. */ ++static inline off_t ++get_used (void) ++{ ++ return __atomic_load_n (&num_files, __ATOMIC_RELAXED); + } + + #endif +-- +2.1.4 + diff --git a/debian/patches/0005-libdiskfs-lock-less-reference-counting-of-nodes.patch b/debian/patches/0005-libdiskfs-lock-less-reference-counting-of-nodes.patch new file mode 100644 index 00000000..81c28244 --- /dev/null +++ b/debian/patches/0005-libdiskfs-lock-less-reference-counting-of-nodes.patch @@ -0,0 +1,610 @@ +From 90e22ba06f758d140073a0d94fce20adc8932310 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 14 May 2014 11:19:35 +0200 +Subject: [PATCH hurd 05/16] libdiskfs: lock-less reference counting of nodes + +* libdiskfs/diskfs.h (struct node): Use refcounts_t for reference counting. +(diskfs_node_refcnt_lock): Remove. +(diskfs_node_norefs,diskfs_drop_node): Change comments accordingly. +* libdiskfs/init-init.c: Adjust accordingly. +* libdiskfs/node-drop.c: Likewise. +* libdiskfs/node-make.c: Likewise. +* libdiskfs/node-nput.c: Likewise. +* libdiskfs/node-nputl.c: Likewise. +* libdiskfs/node-nref.c: Likewise. +* libdiskfs/node-nrefl.c: Likewise. +* libdiskfs/node-nrele.c: Likewise. +* libdiskfs/node-nrelel.c: Likewise. +* ext2fs/inode.c: Likewise. +* fatfs/inode.c: Likewise. +* isofs/inode.c: Likewise. +* tmpfs/node.c: Likewise. +* doc/hurd.texi: Likewise. +--- + doc/hurd.texi | 11 ++--------- + ext2fs/inode.c | 15 +++++--------- + fatfs/inode.c | 27 ++++++++----------------- + isofs/inode.c | 13 ++++--------- + libdiskfs/diskfs.h | 15 ++++++-------- + libdiskfs/init-init.c | 2 -- + libdiskfs/node-drop.c | 11 +++++------ + libdiskfs/node-make.c | 3 +-- + libdiskfs/node-nput.c | 52 +++++++++++++++++++------------------------------ + libdiskfs/node-nputl.c | 12 ++++-------- + libdiskfs/node-nref.c | 9 +++------ + libdiskfs/node-nrefl.c | 4 +--- + libdiskfs/node-nrele.c | 48 ++++++++++++++++++++++----------------------- + libdiskfs/node-nrelel.c | 9 +++------ + tmpfs/node.c | 15 +++++--------- + 15 files changed, 90 insertions(+), 156 deletions(-) + +diff --git a/doc/hurd.texi b/doc/hurd.texi +index 7e7b5ee..2f36bdc 100644 +--- a/doc/hurd.texi ++++ b/doc/hurd.texi +@@ -3780,10 +3780,6 @@ new thread and (eventually) get rid of the old one; the old thread won't + do any more syncs, regardless. + @end deftypefun + +-@deftypevar spin_lock_t diskfs_node_refcnt_lock +-Pager reference count lock. +-@end deftypevar +- + @deftypevar int diskfs_readonly + Set to zero if the filesystem is currently writable. + @end deftypevar +@@ -3818,9 +3814,7 @@ Every file or directory is a diskfs @dfn{node}. The following functions + help your diskfs callbacks manage nodes and their references: + + @deftypefun void diskfs_drop_node (@w{struct node *@var{np}}) +-Node @var{np} now has no more references; clean all state. The +-@var{diskfs_node_refcnt_lock} must be held, and will be released upon +-return. @var{np} must be locked. ++Node @var{np} now has no more references; clean all state. + @end deftypefun + + @deftypefun void diskfs_node_update (@w{struct node *@var{np}}, @w{int @var{wait}}) +@@ -4236,14 +4230,13 @@ without real users. + @deftypefun void diskfs_try_dropping_softrefs (@w{struct node *@var{np}}) + Node @var{np} has some light references, but has just lost its last hard + references. Take steps so that if any light references can be freed, +-they are. Both @var{diskfs_node_refcnt_lock} and @var{np} are locked. ++they are. @var{np} is locked. + This function will be called after @code{diskfs_lost_hardrefs}. + @end deftypefun + + @deftypefun void diskfs_node_norefs (@w{struct node *@var{np}}) + Node @var{np} has no more references; free local state, including + @code{*@var{np}} if it shouldn't be retained. +-@var{diskfs_node_refcnt_lock} is held. + @end deftypefun + + @deftypefun error_t diskfs_set_hypermetadata (@w{int @var{wait}}, @w{int @var{clean}}) +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 7c8d5a8..2a0c3cf 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -57,7 +57,6 @@ + through the nodehash. */ + static struct node *nodehash[INOHSZ]; + static size_t nodehash_nr_items; +-/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ + static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static error_t read_node (struct node *np); +@@ -207,14 +206,10 @@ diskfs_try_dropping_softrefs (struct node *np) + { + /* Check if someone reacquired a reference through the + nodehash. */ +- unsigned int references; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- references = np->references; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- +- /* An additional reference is acquired by libdiskfs across calls +- to diskfs_try_dropping_softrefs. */ +- if (references > 1) ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) + { + /* A reference was reacquired through a hash table lookup. + It's fine, we didn't touch anything yet. */ +@@ -636,7 +631,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + /* We acquire a hard reference for node, but without using + diskfs_nref. We do this so that diskfs_new_hardrefs will not + get called. */ +- node->references++; ++ refcounts_ref (&node->refcounts, NULL); + } + + pthread_rwlock_unlock (&nodecache_lock); +diff --git a/fatfs/inode.c b/fatfs/inode.c +index 1d670f5..f228618 100644 +--- a/fatfs/inode.c ++++ b/fatfs/inode.c +@@ -55,7 +55,6 @@ + through the nodehash. */ + static struct node *nodehash[INOHSZ]; + static size_t nodehash_nr_items; +-/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ + static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + static error_t read_node (struct node *np, vm_address_t buf); +@@ -254,14 +253,8 @@ 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) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- diskfs_nrele (np->dn->dirnode); +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- } ++ diskfs_nrele (np->dn->dirnode); + + assert (!np->dn->pager); + +@@ -279,14 +272,10 @@ diskfs_try_dropping_softrefs (struct node *np) + { + /* Check if someone reacquired a reference through the + nodehash. */ +- unsigned int references; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- references = np->references; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- +- /* An additional reference is acquired by libdiskfs across calls +- to diskfs_try_dropping_softrefs. */ +- if (references > 1) ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) + { + /* A reference was reacquired through a hash table lookup. + It's fine, we didn't touch anything yet. */ +@@ -392,7 +381,7 @@ read_node (struct node *np, vm_address_t buf) + /* Files in fatfs depend on the directory that hold the file. */ + np->dn->dirnode = dp; + if (dp) +- dp->references++; ++ refcounts_ref (&dp->refcounts, NULL); + + pthread_rwlock_rdlock (&np->dn->dirent_lock); + +@@ -627,7 +616,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + /* We acquire a hard reference for node, but without using + diskfs_nref. We do this so that diskfs_new_hardrefs will not + get called. */ +- node->references++; ++ refcounts_ref (&node->refcounts, NULL); + } + + pthread_rwlock_unlock (&nodecache_lock); +@@ -838,7 +827,7 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) + + /* FIXME: We know that readnode couldn't put this in. */ + np->dn->dirnode = dir; +- dir->references++; ++ refcounts_ref (&dir->refcounts, NULL); + + *node = np; + return 0; +diff --git a/isofs/inode.c b/isofs/inode.c +index 37bf1ac..340bc9c 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -60,7 +60,6 @@ struct node_cache + static int node_cache_size = 0; + static int node_cache_alloced = 0; + struct node_cache *node_cache = 0; +-/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ + static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + /* Forward */ +@@ -564,14 +563,10 @@ diskfs_try_dropping_softrefs (struct node *np) + + /* Check if someone reacquired a reference through the + node_cache. */ +- unsigned int references; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- references = np->references; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- +- /* An additional reference is acquired by libdiskfs across calls +- to diskfs_try_dropping_softrefs. */ +- if (references > 1) ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) + { + /* A reference was reacquired through a hash table lookup. + It's fine, we didn't touch anything yet. */ +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 2818225..535fb39 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -96,8 +96,7 @@ struct node + + pthread_mutex_t lock; + +- int references; /* hard references */ +- int light_references; /* light references */ ++ refcounts_t refcounts; + + mach_port_t sockaddr; /* address for S_IFSOCK shortcut */ + +@@ -198,8 +197,6 @@ extern volatile struct mapped_time_value *diskfs_mtime; + be done by format independent code. */ + extern int diskfs_synchronous; + +-extern pthread_spinlock_t diskfs_node_refcnt_lock; +- + extern int pager_port_type; + + /* Whether the filesystem is currently writable or not. */ +@@ -448,14 +445,15 @@ error_t diskfs_alloc_node (struct node *dp, mode_t mode, struct node **np); + void diskfs_free_node (struct node *np, mode_t mode); + + /* Node NP has no more references; free local state, including *NP +- if it isn't to be retained. diskfs_node_refcnt_lock is held. */ ++ if it isn't to be retained. */ + void diskfs_node_norefs (struct node *np); + + /* The user must define this function. Node NP has some light + references, but has just lost its last hard references. Take steps + so that if any light references can be freed, they are. NP is locked + as is the pager refcount lock. This function will be called after +- diskfs_lost_hardrefs. */ ++ diskfs_lost_hardrefs. An additional light reference is acquired by ++ libdiskfs across calls to this function. */ + void diskfs_try_dropping_softrefs (struct node *np); + + /* The user must define this funcction. Node NP has some light +@@ -611,9 +609,8 @@ void diskfs_spawn_first_thread (ports_demuxer_type demuxer); + diskfs_init_completed once it has a valid proc and auth port. */ + void diskfs_start_bootstrap (); + +-/* Node NP now has no more references; clean all state. The +- _diskfs_node_refcnt_lock must be held, and will be released +- upon return. NP must be locked. */ ++/* Node NP now has no more references; clean all state. NP must be ++ locked. */ + void diskfs_drop_node (struct node *np); + + /* Set on disk fields from NP->dn_stat; update ctime, atime, and mtime +diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c +index ffb99e0..357960b 100644 +--- a/libdiskfs/init-init.c ++++ b/libdiskfs/init-init.c +@@ -41,8 +41,6 @@ int _diskfs_noatime; + + struct hurd_port _diskfs_exec_portcell; + +-pthread_spinlock_t diskfs_node_refcnt_lock = PTHREAD_SPINLOCK_INITIALIZER; +- + pthread_spinlock_t _diskfs_control_lock = PTHREAD_SPINLOCK_INITIALIZER; + int _diskfs_ncontrol_ports; + +diff --git a/libdiskfs/node-drop.c b/libdiskfs/node-drop.c +index 83eb590..455031b 100644 +--- a/libdiskfs/node-drop.c ++++ b/libdiskfs/node-drop.c +@@ -31,9 +31,8 @@ free_modreqs (struct modreq *mr) + } + + +-/* Node NP now has no more references; clean all state. The +- diskfs_node_refcnt_lock must be held, and will be released +- upon return. NP must be locked. */ ++/* Node NP now has no more references; clean all state. NP must be ++ locked. */ + void + diskfs_drop_node (struct node *np) + { +@@ -60,8 +59,7 @@ diskfs_drop_node (struct node *np) + and an nput. The next time through, this routine + will notice that the size is zero, and not have to + do anything. */ +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ refcounts_unsafe_ref (&np->refcounts, NULL); + diskfs_truncate (np, 0); + + /* Force allocsize to zero; if truncate consistently fails this +@@ -93,6 +91,7 @@ diskfs_drop_node (struct node *np) + + assert (!np->sockaddr); + ++ pthread_mutex_unlock(&np->lock); ++ pthread_mutex_destroy(&np->lock); + diskfs_node_norefs (np); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); + } +diff --git a/libdiskfs/node-make.c b/libdiskfs/node-make.c +index ff0cc0d..c7ca3b0 100644 +--- a/libdiskfs/node-make.c ++++ b/libdiskfs/node-make.c +@@ -29,8 +29,7 @@ init_node (struct node *np, struct disknode *dn) + np->dn_stat_dirty = 0; + + pthread_mutex_init (&np->lock, NULL); +- np->references = 1; +- np->light_references = 0; ++ refcounts_init (&np->refcounts, 1, 0); + np->owner = 0; + np->sockaddr = MACH_PORT_NULL; + +diff --git a/libdiskfs/node-nput.c b/libdiskfs/node-nput.c +index 5043ad1..d23c103 100644 +--- a/libdiskfs/node-nput.c ++++ b/libdiskfs/node-nput.c +@@ -26,56 +26,44 @@ + void + diskfs_nput (struct node *np) + { +- int tried_drop_softrefs = 0; ++ struct references result; + +- loop: +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- assert (np->references); +- np->references--; +- if (np->references + np->light_references == 0) +- diskfs_drop_node (np); +- else if (np->references == 0 && !tried_drop_softrefs) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ /* While we call the diskfs_try_dropping_softrefs, we need to hold ++ one reference. We use a weak reference for this purpose, which ++ we acquire by demoting our hard reference to a weak one. */ ++ refcounts_demote (&np->refcounts, &result); + ++ if (result.hard == 0) ++ { + /* This is our cue that something akin to "last process closes file" + in the POSIX.1 sense happened, so make sure any pending node time + updates now happen in a timely fashion. */ + diskfs_set_node_times (np); +- + diskfs_lost_hardrefs (np); + if (!np->dn_stat.st_nlink) + { +- /* There are no links. If there are soft references that +- can be dropped, we can't let them postpone deallocation. +- So attempt to drop them. But that's a user-supplied +- routine, which might result in further recursive calls to +- the ref-counting system. So we have to reacquire our +- reference around the call to forestall disaster. */ +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- + if (np->sockaddr != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), np->sockaddr); + np->sockaddr = MACH_PORT_NULL; + } + ++ /* There are no links. If there are soft references that ++ can be dropped, we can't let them postpone deallocation. ++ So attempt to drop them. But that's a user-supplied ++ routine, which might result in further recursive calls to ++ the ref-counting system. This is not a problem, as we ++ hold a weak reference ourselves. */ + diskfs_try_dropping_softrefs (np); +- +- /* But there's no value in looping forever in this +- routine; only try to drop soft refs once. */ +- tried_drop_softrefs = 1; +- +- /* Now we can drop the reference back... */ +- goto loop; + } + pthread_mutex_unlock (&np->lock); + } ++ ++ /* Finally get rid of our reference. */ ++ refcounts_deref_weak (&np->refcounts, &result); ++ ++ if (result.hard == 0 && result.weak == 0) ++ diskfs_drop_node (np); + else +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_unlock (&np->lock); +- } ++ pthread_mutex_unlock (&np->lock); + } +diff --git a/libdiskfs/node-nputl.c b/libdiskfs/node-nputl.c +index 1959665..8dac16e 100644 +--- a/libdiskfs/node-nputl.c ++++ b/libdiskfs/node-nputl.c +@@ -25,14 +25,10 @@ + void + diskfs_nput_light (struct node *np) + { +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- assert (np->light_references); +- np->light_references--; +- if (np->references + np->light_references == 0) ++ struct references result; ++ refcounts_deref_weak (&np->refcounts, &result); ++ if (result.hard == 0 && result.weak == 0) + diskfs_drop_node (np); + else +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_unlock (&np->lock); +- } ++ pthread_mutex_unlock (&np->lock); + } +diff --git a/libdiskfs/node-nref.c b/libdiskfs/node-nref.c +index 13cea05..766a69c 100644 +--- a/libdiskfs/node-nref.c ++++ b/libdiskfs/node-nref.c +@@ -26,12 +26,9 @@ + void + diskfs_nref (struct node *np) + { +- int new_hardref; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- np->references++; +- new_hardref = (np->references == 1); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- if (new_hardref) ++ struct references result; ++ refcounts_ref (&np->refcounts, &result); ++ if (result.hard == 1) + { + pthread_mutex_lock (&np->lock); + diskfs_new_hardrefs (np); +diff --git a/libdiskfs/node-nrefl.c b/libdiskfs/node-nrefl.c +index 9692247..f7a823d 100644 +--- a/libdiskfs/node-nrefl.c ++++ b/libdiskfs/node-nrefl.c +@@ -24,7 +24,5 @@ + void + diskfs_nref_light (struct node *np) + { +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- np->light_references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ refcounts_ref_weak (&np->refcounts, NULL); + } +diff --git a/libdiskfs/node-nrele.c b/libdiskfs/node-nrele.c +index cc68089..d962846 100644 +--- a/libdiskfs/node-nrele.c ++++ b/libdiskfs/node-nrele.c +@@ -28,38 +28,36 @@ + void + diskfs_nrele (struct node *np) + { +- int tried_drop_softrefs = 0; ++ struct references result; + +- loop: +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- assert (np->references); +- np->references--; +- if (np->references + np->light_references == 0) +- { +- pthread_mutex_lock (&np->lock); +- diskfs_drop_node (np); +- } +- else if (np->references == 0) ++ /* While we call the diskfs_try_dropping_softrefs, we need to hold ++ one reference. We use a weak reference for this purpose, which ++ we acquire by demoting our hard reference to a weak one. */ ++ refcounts_demote (&np->refcounts, &result); ++ ++ if (result.hard == 0) + { + pthread_mutex_lock (&np->lock); +- pthread_spin_unlock (&diskfs_node_refcnt_lock); + diskfs_lost_hardrefs (np); +- if (!np->dn_stat.st_nlink && !tried_drop_softrefs) ++ if (!np->dn_stat.st_nlink) + { +- /* Same issue here as in nput; see that for explanation */ +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- ++ /* There are no links. If there are soft references that ++ can be dropped, we can't let them postpone deallocation. ++ So attempt to drop them. But that's a user-supplied ++ routine, which might result in further recursive calls to ++ the ref-counting system. This is not a problem, as we ++ hold a weak reference ourselves. */ + diskfs_try_dropping_softrefs (np); +- tried_drop_softrefs = 1; +- +- /* Now we can drop the reference back... */ +- pthread_mutex_unlock (&np->lock); +- goto loop; + } + pthread_mutex_unlock (&np->lock); + } +- else +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ ++ /* Finally get rid of our reference. */ ++ refcounts_deref_weak (&np->refcounts, &result); ++ ++ if (result.hard == 0 && result.weak == 0) ++ { ++ pthread_mutex_lock (&np->lock); ++ diskfs_drop_node (np); ++ } + } +diff --git a/libdiskfs/node-nrelel.c b/libdiskfs/node-nrelel.c +index ee53b22..dc4f920 100644 +--- a/libdiskfs/node-nrelel.c ++++ b/libdiskfs/node-nrelel.c +@@ -26,14 +26,11 @@ + void + diskfs_nrele_light (struct node *np) + { +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- assert (np->light_references); +- np->light_references--; +- if (np->references + np->light_references == 0) ++ struct references result; ++ refcounts_deref_weak (&np->refcounts, &result); ++ if (result.hard == 0 && result.weak == 0) + { + pthread_mutex_lock (&np->lock); + diskfs_drop_node (np); + } +- else +- pthread_spin_unlock (&diskfs_node_refcnt_lock); + } +diff --git a/tmpfs/node.c b/tmpfs/node.c +index 428b6d9..2a4489c 100644 +--- a/tmpfs/node.c ++++ b/tmpfs/node.c +@@ -40,7 +40,6 @@ static unsigned int gen; + reference. */ + struct node *all_nodes; + static size_t all_nodes_nr_items; +-/* all_nodes_lock must be acquired before diskfs_node_refcnt_lock. */ + pthread_rwlock_t all_nodes_lock = PTHREAD_RWLOCK_INITIALIZER; + + error_t +@@ -267,7 +266,7 @@ diskfs_node_iterate (error_t (*fun) (struct node *)) + /* We acquire a hard reference for node, but without using + diskfs_nref. We do this so that diskfs_new_hardrefs will not + get called. */ +- node->references++; ++ refcounts_ref (&node->refcounts, NULL); + } + + pthread_rwlock_unlock (&all_nodes_lock); +@@ -300,14 +299,10 @@ diskfs_try_dropping_softrefs (struct node *np) + if (np->cache_id != 0) + { + /* Check if someone reacquired a reference. */ +- unsigned int references; +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- references = np->references; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- +- /* An additional reference is acquired by libdiskfs across calls +- to diskfs_try_dropping_softrefs. */ +- if (references > 1) ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) + { + /* A reference was reacquired. It's fine, we didn't touch + anything yet. */ +-- +2.1.4 + diff --git a/debian/patches/0006-libdiskfs-make-struct-node-more-compact.patch b/debian/patches/0006-libdiskfs-make-struct-node-more-compact.patch new file mode 100644 index 00000000..f3f70c1e --- /dev/null +++ b/debian/patches/0006-libdiskfs-make-struct-node-more-compact.patch @@ -0,0 +1,51 @@ +From 8de411c5ad1f20f52a562f79b08de17187ff1920 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 14 Apr 2015 21:17:19 +0200 +Subject: [PATCH hurd 06/16] libdiskfs: make struct node more compact + +* libdiskfs/diskfs.h (struct node): Turn flags into a bit field. +--- + libdiskfs/diskfs.h | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 535fb39..18df0eb 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -86,13 +86,20 @@ struct node + + io_statbuf_t dn_stat; + ++ /* Flags. */ ++ unsigned int ++ + /* Stat has been modified if one of the following four fields + is nonzero. Also, if one of the dn_set_?time fields is nonzero, + the appropriate dn_stat.st_?tim field needs to be updated. */ +- int dn_set_ctime; +- int dn_set_atime; +- int dn_set_mtime; +- int dn_stat_dirty; ++ dn_set_ctime:1, ++ dn_set_atime:1, ++ dn_set_mtime:1, ++ dn_stat_dirty:1, ++ ++ /* Indicate whether the author is tracking the uid because the ++ on-disk file format does not encode a separate author. */ ++ author_tracks_uid:1; + + pthread_mutex_t lock; + +@@ -117,8 +124,6 @@ struct node + loff_t allocsize; + + ino64_t cache_id; +- +- int author_tracks_uid; + }; + + struct diskfs_control +-- +2.1.4 + diff --git a/debian/patches/0007-libdiskfs-drop-unused-fields-from-struct-node.patch b/debian/patches/0007-libdiskfs-drop-unused-fields-from-struct-node.patch new file mode 100644 index 00000000..b69061d3 --- /dev/null +++ b/debian/patches/0007-libdiskfs-drop-unused-fields-from-struct-node.patch @@ -0,0 +1,27 @@ +From bffaff26a9a1d26be96c8cc1335142ed1d2c810e Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 14 Apr 2015 21:18:31 +0200 +Subject: [PATCH hurd 07/16] libdiskfs: drop unused fields from struct node + +* libdiskfs/diskfs.h (struct node): Drop unused fields from struct +node. +--- + libdiskfs/diskfs.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 18df0eb..7a21dff 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -80,8 +80,6 @@ struct peropen + filesystem. */ + struct node + { +- struct node *next, **prevp; +- + struct disknode *dn; + + io_statbuf_t dn_stat; +-- +2.1.4 + diff --git a/debian/patches/0008-libdiskfs-initialize-flag.patch b/debian/patches/0008-libdiskfs-initialize-flag.patch new file mode 100644 index 00000000..5ccd7f28 --- /dev/null +++ b/debian/patches/0008-libdiskfs-initialize-flag.patch @@ -0,0 +1,25 @@ +From 56b9d90fee439c401abceb93f3f876ef0a7828ad Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 14 Apr 2015 21:24:48 +0200 +Subject: [PATCH hurd 08/16] libdiskfs: initialize flag + +* libdiskfs/node-make.c (init_node): Initialize flag `author_tracks_uid'. +--- + libdiskfs/node-make.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libdiskfs/node-make.c b/libdiskfs/node-make.c +index c7ca3b0..7bc1d85 100644 +--- a/libdiskfs/node-make.c ++++ b/libdiskfs/node-make.c +@@ -27,6 +27,7 @@ init_node (struct node *np, struct disknode *dn) + np->dn_set_atime = 0; + np->dn_set_mtime = 0; + np->dn_stat_dirty = 0; ++ np->author_tracks_uid = 0; + + pthread_mutex_init (&np->lock, NULL); + refcounts_init (&np->refcounts, 1, 0); +-- +2.1.4 + diff --git a/debian/patches/0009-xxx-ext2fs-fat-nodes.patch b/debian/patches/0009-xxx-ext2fs-fat-nodes.patch new file mode 100644 index 00000000..2e16d50b --- /dev/null +++ b/debian/patches/0009-xxx-ext2fs-fat-nodes.patch @@ -0,0 +1,887 @@ +From 0b89ef2730ff59e782ecbdbee39e2a1e368990bf Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 14 Apr 2015 22:37:31 +0200 +Subject: [PATCH hurd 09/16] xxx ext2fs fat nodes + +--- + ext2fs/dir.c | 75 +++++++++++++++++++++++++++++-------------------------- + ext2fs/ext2fs.h | 4 +-- + ext2fs/getblk.c | 63 +++++++++++++++++++++++----------------------- + ext2fs/ialloc.c | 13 +++++----- + ext2fs/inode.c | 67 ++++++++++++++++++++++++------------------------- + ext2fs/pager.c | 52 +++++++++++++++++++------------------- + ext2fs/truncate.c | 16 ++++++------ + 7 files changed, 147 insertions(+), 143 deletions(-) + +diff --git a/ext2fs/dir.c b/ext2fs/dir.c +index 470b7e9..2dfe1d7 100644 +--- a/ext2fs/dir.c ++++ b/ext2fs/dir.c +@@ -202,8 +202,8 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + + diskfs_set_node_atime (dp); + +- /* Start the lookup at DP->dn->dir_idx. */ +- idx = dp->dn->dir_idx; ++ /* Start the lookup at diskfs_node_disknode (DP)->dir_idx. */ ++ idx = diskfs_node_disknode (dp)->dir_idx; + if (idx * DIRBLKSIZ > dp->dn_stat.st_size) + idx = 0; /* just in case */ + blockaddr = buf + idx * DIRBLKSIZ; +@@ -217,7 +217,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + err = dirscanblock (blockaddr, dp, idx, name, namelen, type, ds, &inum); + if (!err) + { +- dp->dn->dir_idx = idx; ++ diskfs_node_disknode (dp)->dir_idx = idx; + break; + } + if (err != ENOENT) +@@ -484,17 +484,17 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, + + /* Because we scanned the entire block, we should write + down how many entries there were. */ +- if (!dp->dn->dirents) ++ if (!diskfs_node_disknode (dp)->dirents) + { +- dp->dn->dirents = malloc ((dp->dn_stat.st_size / DIRBLKSIZ) +- * sizeof (int)); ++ diskfs_node_disknode (dp)->dirents = ++ malloc ((dp->dn_stat.st_size / DIRBLKSIZ) * sizeof (int)); + for (i = 0; i < dp->dn_stat.st_size/DIRBLKSIZ; i++) +- dp->dn->dirents[i] = -1; ++ diskfs_node_disknode (dp)->dirents[i] = -1; + } + /* Make sure the count is correct if there is one now. */ +- assert (dp->dn->dirents[idx] == -1 +- || dp->dn->dirents[idx] == nentries); +- dp->dn->dirents[idx] = nentries; ++ assert (diskfs_node_disknode (dp)->dirents[idx] == -1 ++ || diskfs_node_disknode (dp)->dirents[idx] == nentries); ++ diskfs_node_disknode (dp)->dirents[idx] = nentries; + + return ENOENT; + } +@@ -653,7 +653,7 @@ diskfs_direnter_hard (struct node *dp, const char *name, struct node *np, + memcpy (new->name, name, namelen); + + /* Mark the directory inode has having been written. */ +- dp->dn->info.i_flags &= ~EXT2_BTREE_FL; ++ diskfs_node_disknode (dp)->info.i_flags &= ~EXT2_BTREE_FL; + dp->dn_set_mtime = 1; + + munmap ((caddr_t) ds->mapbuf, ds->mapextent); +@@ -662,33 +662,34 @@ diskfs_direnter_hard (struct node *dp, const char *name, struct node *np, + { + /* If we are keeping count of this block, then keep the count up + to date. */ +- if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1) +- dp->dn->dirents[ds->idx]++; ++ if (diskfs_node_disknode (dp)->dirents ++ && diskfs_node_disknode (dp)->dirents[ds->idx] != -1) ++ diskfs_node_disknode (dp)->dirents[ds->idx]++; + } + else + { + int i; + /* It's cheap, so start a count here even if we aren't counting + anything at all. */ +- if (dp->dn->dirents) ++ if (diskfs_node_disknode (dp)->dirents) + { +- dp->dn->dirents = realloc (dp->dn->dirents, +- (dp->dn_stat.st_size / DIRBLKSIZ +- * sizeof (int))); ++ diskfs_node_disknode (dp)->dirents = ++ realloc (diskfs_node_disknode (dp)->dirents, ++ (dp->dn_stat.st_size / DIRBLKSIZ * sizeof (int))); + for (i = oldsize / DIRBLKSIZ; + i < dp->dn_stat.st_size / DIRBLKSIZ; + i++) +- dp->dn->dirents[i] = -1; ++ diskfs_node_disknode (dp)->dirents[i] = -1; + +- dp->dn->dirents[ds->idx] = 1; ++ diskfs_node_disknode (dp)->dirents[ds->idx] = 1; + } + else + { +- dp->dn->dirents = malloc (dp->dn_stat.st_size / DIRBLKSIZ +- * sizeof (int)); ++ diskfs_node_disknode (dp)->dirents = ++ malloc (dp->dn_stat.st_size / DIRBLKSIZ * sizeof (int)); + for (i = 0; i < dp->dn_stat.st_size / DIRBLKSIZ; i++) +- dp->dn->dirents[i] = -1; +- dp->dn->dirents[ds->idx] = 1; ++ diskfs_node_disknode (dp)->dirents[i] = -1; ++ diskfs_node_disknode (dp)->dirents[ds->idx] = 1; + } + } + +@@ -720,14 +721,15 @@ diskfs_dirremove_hard (struct node *dp, struct dirstat *ds) + } + + dp->dn_set_mtime = 1; +- dp->dn->info.i_flags &= ~EXT2_BTREE_FL; ++ diskfs_node_disknode (dp)->info.i_flags &= ~EXT2_BTREE_FL; + + munmap ((caddr_t) ds->mapbuf, ds->mapextent); + + /* If we are keeping count of this block, then keep the count up + to date. */ +- if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1) +- dp->dn->dirents[ds->idx]--; ++ if (diskfs_node_disknode (dp)->dirents ++ && diskfs_node_disknode (dp)->dirents[ds->idx] != -1) ++ diskfs_node_disknode (dp)->dirents[ds->idx]--; + + diskfs_file_update (dp, diskfs_synchronous); + +@@ -751,7 +753,7 @@ diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds) + + ds->entry->inode = np->cache_id; + dp->dn_set_mtime = 1; +- dp->dn->info.i_flags &= ~EXT2_BTREE_FL; ++ diskfs_node_disknode (dp)->info.i_flags &= ~EXT2_BTREE_FL; + + munmap ((caddr_t) ds->mapbuf, ds->mapextent); + +@@ -831,7 +833,7 @@ count_dirents (struct node *dp, block_t nb, char *buf) + int count = 0; + error_t err; + +- assert (dp->dn->dirents); ++ assert (diskfs_node_disknode (dp)->dirents); + assert ((nb + 1) * DIRBLKSIZ <= dp->dn_stat.st_size); + + err = diskfs_node_rdwr (dp, buf, nb * DIRBLKSIZ, DIRBLKSIZ, 0, 0, &amt); +@@ -848,8 +850,9 @@ count_dirents (struct node *dp, block_t nb, char *buf) + count++; + } + +- assert (dp->dn->dirents[nb] == -1 || dp->dn->dirents[nb] == count); +- dp->dn->dirents[nb] = count; ++ assert (diskfs_node_disknode (dp)->dirents[nb] == -1 ++ || diskfs_node_disknode (dp)->dirents[nb] == count); ++ diskfs_node_disknode (dp)->dirents[nb] = count; + return 0; + } + +@@ -884,11 +887,11 @@ diskfs_get_directs (struct node *dp, + + nblks = dp->dn_stat.st_size/DIRBLKSIZ; + +- if (!dp->dn->dirents) ++ if (!diskfs_node_disknode (dp)->dirents) + { +- dp->dn->dirents = malloc (nblks * sizeof (int)); ++ diskfs_node_disknode (dp)->dirents = malloc (nblks * sizeof (int)); + for (i = 0; i < nblks; i++) +- dp->dn->dirents[i] = -1; ++ diskfs_node_disknode (dp)->dirents[i] = -1; + } + + /* Scan through the entries to find ENTRY. If we encounter +@@ -898,7 +901,7 @@ diskfs_get_directs (struct node *dp, + bufvalid = 0; + for (blkno = 0; blkno < nblks; blkno++) + { +- if (dp->dn->dirents[blkno] == -1) ++ if (diskfs_node_disknode (dp)->dirents[blkno] == -1) + { + err = count_dirents (dp, blkno, buf); + if (err) +@@ -906,11 +909,11 @@ diskfs_get_directs (struct node *dp, + bufvalid = 1; + } + +- if (curentry + dp->dn->dirents[blkno] > entry) ++ if (curentry + diskfs_node_disknode (dp)->dirents[blkno] > entry) + /* ENTRY starts in this block. */ + break; + +- curentry += dp->dn->dirents[blkno]; ++ curentry += diskfs_node_disknode (dp)->dirents[blkno]; + + bufvalid = 0; + } +diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h +index 3422af2..9667b6f 100644 +--- a/ext2fs/ext2fs.h ++++ b/ext2fs/ext2fs.h +@@ -503,7 +503,7 @@ record_indir_poke (struct node *node, void *ptr) + ext2_debug ("(%llu, %p)", node->cache_id, ptr); + assert (disk_cache_block_is_ref (block)); + global_block_modified (block); +- pokel_add (&node->dn->indir_pokel, block_ptr, block_size); ++ pokel_add (&diskfs_node_disknode (node)->indir_pokel, block_ptr, block_size); + } + + /* ---------------------------------------------------------------- */ +@@ -524,7 +524,7 @@ alloc_sync (struct node *np) + if (np) + { + diskfs_node_update (np, 1); +- pokel_sync (&np->dn->indir_pokel, 1); ++ pokel_sync (&diskfs_node_disknode (np)->indir_pokel, 1); + } + diskfs_set_hypermetadata (1, 0); + } +diff --git a/ext2fs/getblk.c b/ext2fs/getblk.c +index d7ddb6a..0d0fab1 100644 +--- a/ext2fs/getblk.c ++++ b/ext2fs/getblk.c +@@ -49,13 +49,13 @@ void + ext2_discard_prealloc (struct node *node) + { + #ifdef EXT2_PREALLOCATE +- if (node->dn->info.i_prealloc_count) ++ if (diskfs_node_disknode (node)->info.i_prealloc_count) + { +- int i = node->dn->info.i_prealloc_count; ++ int i = diskfs_node_disknode (node)->info.i_prealloc_count; + ext2_debug ("discarding %d prealloced blocks for inode %d", + i, node->cache_id); +- node->dn->info.i_prealloc_count = 0; +- ext2_free_blocks (node->dn->info.i_prealloc_block, i); ++ diskfs_node_disknode (node)->info.i_prealloc_count = 0; ++ ext2_free_blocks (diskfs_node_disknode (node)->info.i_prealloc_block, i); + } + #endif + } +@@ -72,12 +72,12 @@ ext2_alloc_block (struct node *node, block_t goal, int zero) + block_t result; + + #ifdef EXT2_PREALLOCATE +- if (node->dn->info.i_prealloc_count && +- (goal == node->dn->info.i_prealloc_block || +- goal + 1 == node->dn->info.i_prealloc_block)) ++ if (diskfs_node_disknode (node)->info.i_prealloc_count && ++ (goal == diskfs_node_disknode (node)->info.i_prealloc_block || ++ goal + 1 == diskfs_node_disknode (node)->info.i_prealloc_block)) + { +- result = node->dn->info.i_prealloc_block++; +- node->dn->info.i_prealloc_count--; ++ result = diskfs_node_disknode (node)->info.i_prealloc_block++; ++ diskfs_node_disknode (node)->info.i_prealloc_count--; + ext2_debug ("preallocation hit (%lu/%lu) => %u", + ++alloc_hits, ++alloc_attempts, result); + } +@@ -95,8 +95,8 @@ ext2_alloc_block (struct node *node, block_t goal, int zero) + EXT2_FEATURE_COMPAT_DIR_PREALLOC)) + ? sblock->s_prealloc_dir_blocks + : 0, +- &node->dn->info.i_prealloc_count, +- &node->dn->info.i_prealloc_block); ++ &diskfs_node_disknode (node)->info.i_prealloc_count, ++ &diskfs_node_disknode (node)->info.i_prealloc_block); + } + #else + result = ext2_new_block (goal, 0, 0); +@@ -124,15 +124,15 @@ inode_getblk (struct node *node, int nr, int create, int zero, + + assert (0 <= nr && nr < EXT2_N_BLOCKS); + +- *result = node->dn->info.i_data[nr]; ++ *result = diskfs_node_disknode (node)->info.i_data[nr]; + if (*result) + return 0; + + if (!create) + return EINVAL; + +- if (node->dn->info.i_next_alloc_block == new_block) +- goal = node->dn->info.i_next_alloc_goal; ++ if (diskfs_node_disknode (node)->info.i_next_alloc_block == new_block) ++ goal = diskfs_node_disknode (node)->info.i_next_alloc_goal; + + #ifdef EXT2FS_DEBUG + hint = goal; +@@ -142,15 +142,16 @@ inode_getblk (struct node *node, int nr, int create, int zero, + { + for (i = nr - 1; i >= 0; i--) + { +- if (node->dn->info.i_data[i]) ++ if (diskfs_node_disknode (node)->info.i_data[i]) + { +- goal = node->dn->info.i_data[i]; ++ goal = diskfs_node_disknode (node)->info.i_data[i]; + break; + } + } + if (!goal) + goal = +- (node->dn->info.i_block_group * EXT2_BLOCKS_PER_GROUP (sblock)) ++ (diskfs_node_disknode (node)->info.i_block_group ++ * EXT2_BLOCKS_PER_GROUP (sblock)) + + sblock->s_first_data_block; + } + +@@ -162,15 +163,15 @@ inode_getblk (struct node *node, int nr, int create, int zero, + if (!*result) + return ENOSPC; + +- node->dn->info.i_data[nr] = *result; ++ diskfs_node_disknode (node)->info.i_data[nr] = *result; + +- node->dn->info.i_next_alloc_block = new_block; +- node->dn->info.i_next_alloc_goal = *result; ++ diskfs_node_disknode (node)->info.i_next_alloc_block = new_block; ++ diskfs_node_disknode (node)->info.i_next_alloc_goal = *result; + node->dn_set_ctime = node->dn_set_mtime = 1; + node->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block; + node->dn_stat_dirty = 1; + +- if (diskfs_synchronous || node->dn->info.i_osync) ++ if (diskfs_synchronous || diskfs_node_disknode (node)->info.i_osync) + diskfs_node_update (node, 1); + + return 0; +@@ -197,8 +198,8 @@ block_getblk (struct node *node, block_t block, int nr, int create, int zero, + return EINVAL; + } + +- if (node->dn->info.i_next_alloc_block == new_block) +- goal = node->dn->info.i_next_alloc_goal; ++ if (diskfs_node_disknode (node)->info.i_next_alloc_block == new_block) ++ goal = diskfs_node_disknode (node)->info.i_next_alloc_goal; + if (!goal) + { + for (i = nr - 1; i >= 0; i--) +@@ -222,13 +223,13 @@ block_getblk (struct node *node, block_t block, int nr, int create, int zero, + + bh[nr] = *result; + +- if (diskfs_synchronous || node->dn->info.i_osync) ++ if (diskfs_synchronous || diskfs_node_disknode (node)->info.i_osync) + sync_global_ptr (bh, 1); + else + record_indir_poke (node, bh); + +- node->dn->info.i_next_alloc_block = new_block; +- node->dn->info.i_next_alloc_goal = *result; ++ diskfs_node_disknode (node)->info.i_next_alloc_block = new_block; ++ diskfs_node_disknode (node)->info.i_next_alloc_goal = *result; + node->dn_set_ctime = node->dn_set_mtime = 1; + node->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block; + node->dn_stat_dirty = 1; +@@ -260,13 +261,13 @@ ext2_getblk (struct node *node, block_t block, int create, block_t *disk_block) + */ + + ext2_debug ("block = %u, next = %u, goal = %u", block, +- node->dn->info.i_next_alloc_block, +- node->dn->info.i_next_alloc_goal); ++ diskfs_node_disknode (node)->info.i_next_alloc_block, ++ diskfs_node_disknode (node)->info.i_next_alloc_goal); + +- if (block == node->dn->info.i_next_alloc_block + 1) ++ if (block == diskfs_node_disknode (node)->info.i_next_alloc_block + 1) + { +- node->dn->info.i_next_alloc_block++; +- node->dn->info.i_next_alloc_goal++; ++ diskfs_node_disknode (node)->info.i_next_alloc_block++; ++ diskfs_node_disknode (node)->info.i_next_alloc_goal++; + } + + b = block; +diff --git a/ext2fs/ialloc.c b/ext2fs/ialloc.c +index 52212d5..7cfc4f3 100644 +--- a/ext2fs/ialloc.c ++++ b/ext2fs/ialloc.c +@@ -316,14 +316,14 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) + } + /* Zero out the block pointers in case there's some noise left on disk. */ + for (block = 0; block < EXT2_N_BLOCKS; block++) +- if (np->dn->info.i_data[block] != 0) ++ if (diskfs_node_disknode (np)->info.i_data[block] != 0) + { +- np->dn->info.i_data[block] = 0; ++ diskfs_node_disknode (np)->info.i_data[block] = 0; + np->dn_set_ctime = 1; + } +- if (np->dn->info_i_translator != 0) ++ if (diskfs_node_disknode (np)->info_i_translator != 0) + { +- np->dn->info_i_translator = 0; ++ diskfs_node_disknode (np)->info_i_translator = 0; + np->dn_set_ctime = 1; + } + st->st_mode &= ~S_IPTRANS; +@@ -335,8 +335,9 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) + } + + /* Propagate initial inode flags from the directory, as Linux does. */ +- np->dn->info.i_flags = +- ext2_mask_flags(mode, dir->dn->info.i_flags & EXT2_FL_INHERITED); ++ diskfs_node_disknode (np)->info.i_flags = ++ ext2_mask_flags(mode, ++ diskfs_node_disknode (dir)->info.i_flags & EXT2_FL_INHERITED); + + st->st_flags = 0; + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 2a0c3cf..7af617c 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -78,7 +78,7 @@ static struct node * + lookup (ino_t inum) + { + struct node *np; +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) ++ for (np = nodehash[INOHASH(inum)]; np; np = diskfs_node_disknode (np)->hnext) + if (np->cache_id == inum) + return np; + return NULL; +@@ -99,20 +99,18 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + goto gotit; + pthread_rwlock_unlock (&nodecache_lock); + ++ /* Create the new node. */ ++ np = diskfs_make_node_alloc (sizeof *dn); ++ dn = diskfs_node_disknode (np); ++ np->cache_id = inum; ++ + /* Format specific data for the new node. */ +- dn = malloc (sizeof (struct disknode)); +- if (! dn) +- return ENOMEM; + dn->dirents = 0; + dn->dir_idx = 0; + dn->pager = 0; + pthread_rwlock_init (&dn->alloc_lock, NULL); + pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache); + +- /* Create the new node. */ +- np = diskfs_make_node (dn); +- np->cache_id = inum; +- + pthread_mutex_lock (&np->lock); + + /* Put NP in NODEHASH. */ +@@ -128,7 +126,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + + dn->hnext = nodehash[INOHASH(inum)]; + if (dn->hnext) +- dn->hnext->dn->hprevp = &dn->hnext; ++ diskfs_node_disknode (dn->hnext)->hprevp = &dn->hnext; + dn->hprevp = &nodehash[INOHASH(inum)]; + nodehash[INOHASH(inum)] = np; + diskfs_nref_light (np); +@@ -184,15 +182,14 @@ ifind (ino_t inum) + void + diskfs_node_norefs (struct node *np) + { +- if (np->dn->dirents) +- free (np->dn->dirents); +- assert (!np->dn->pager); ++ if (diskfs_node_disknode (np)->dirents) ++ free (diskfs_node_disknode (np)->dirents); ++ assert (!diskfs_node_disknode (np)->pager); + + /* Move any pending writes of indirect blocks. */ +- pokel_inherit (&global_pokel, &np->dn->indir_pokel); +- pokel_finalize (&np->dn->indir_pokel); ++ pokel_inherit (&global_pokel, &diskfs_node_disknode (np)->indir_pokel); ++ pokel_finalize (&diskfs_node_disknode (np)->indir_pokel); + +- free (np->dn); + free (np); + } + +@@ -202,7 +199,7 @@ void + diskfs_try_dropping_softrefs (struct node *np) + { + pthread_rwlock_wrlock (&nodecache_lock); +- if (np->dn->hprevp != NULL) ++ if (diskfs_node_disknode (np)->hprevp != NULL) + { + /* Check if someone reacquired a reference through the + nodehash. */ +@@ -217,11 +214,12 @@ diskfs_try_dropping_softrefs (struct node *np) + return; + } + +- *np->dn->hprevp = np->dn->hnext; +- if (np->dn->hnext) +- np->dn->hnext->dn->hprevp = np->dn->hprevp; +- np->dn->hnext = NULL; +- np->dn->hprevp = NULL; ++ *diskfs_node_disknode (np)->hprevp = diskfs_node_disknode (np)->hnext; ++ if (diskfs_node_disknode (np)->hnext) ++ diskfs_node_disknode (diskfs_node_disknode (np)->hnext)->hprevp = ++ diskfs_node_disknode (np)->hprevp; ++ diskfs_node_disknode (np)->hnext = NULL; ++ diskfs_node_disknode (np)->hprevp = NULL; + nodehash_nr_items -= 1; + diskfs_nrele_light (np); + } +@@ -250,7 +248,7 @@ read_node (struct node *np) + { + error_t err; + struct stat *st = &np->dn_stat; +- struct disknode *dn = np->dn; ++ struct disknode *dn = diskfs_node_disknode (np); + struct ext2_inode *di; + struct ext2_inode_info *info = &dn->info; + +@@ -403,7 +401,7 @@ check_high_bits (struct node *np, long l) + kernels". Note that our check refuses to change the values, while + Linux 2.3.42 just silently clears the high bits in an inode it updates, + even if it was updating it for an unrelated reason. */ +- if (np->dn->info.i_dtime != 0) ++ if (diskfs_node_disknode (np)->info.i_dtime != 0) + return 0; + + return ((l & ~0xFFFF) == 0) ? 0 : EINVAL; +@@ -469,12 +467,12 @@ write_node (struct node *np) + + ext2_debug ("(%llu)", np->cache_id); + +- if (np->dn->info.i_prealloc_count) ++ if (diskfs_node_disknode (np)->info.i_prealloc_count) + ext2_discard_prealloc (np); + + if (np->dn_stat_dirty) + { +- struct ext2_inode_info *info = &np->dn->info; ++ struct ext2_inode_info *info = &diskfs_node_disknode (np)->info; + + assert (!diskfs_readonly); + +@@ -560,7 +558,7 @@ write_node (struct node *np) + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + di->i_block[0] = st->st_rdev; + else +- memcpy (di->i_block, np->dn->info.i_data, ++ memcpy (di->i_block, diskfs_node_disknode (np)->info.i_data, + EXT2_N_BLOCKS * sizeof di->i_block[0]); + + diskfs_end_catch_exception (); +@@ -578,7 +576,7 @@ write_node (struct node *np) + error_t + diskfs_node_reload (struct node *node) + { +- struct disknode *dn = node->dn; ++ struct disknode *dn = diskfs_node_disknode (node); + + if (dn->dirents) + { +@@ -624,7 +622,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + + p = node_list; + for (n = 0; n < INOHSZ; n++) +- for (node = nodehash[n]; node; node = node->dn->hnext) ++ for (node = nodehash[n]; node; node = diskfs_node_disknode (node)->hnext) + { + *p++ = node; + +@@ -663,7 +661,7 @@ write_all_disknodes () + + /* Sync the indirect blocks here; they'll all be done before any + inodes. Waiting for them shouldn't be too bad. */ +- pokel_sync (&node->dn->indir_pokel, 1); ++ pokel_sync (&diskfs_node_disknode (node)->indir_pokel, 1); + + diskfs_set_node_times (node); + +@@ -745,7 +743,7 @@ diskfs_set_translator (struct node *np, const char *name, unsigned namelen, + { + /* Allocate block for translator */ + blkno = +- ext2_new_block ((np->dn->info.i_block_group ++ ext2_new_block ((diskfs_node_disknode (np)->info.i_block_group + * EXT2_BLOCKS_PER_GROUP (sblock)) + + sblock->s_first_data_block, + 0, 0, 0); +@@ -757,7 +755,7 @@ diskfs_set_translator (struct node *np, const char *name, unsigned namelen, + } + + di->i_translator = blkno; +- np->dn->info_i_translator = blkno; ++ diskfs_node_disknode (np)->info_i_translator = blkno; + record_global_poke (di); + + np->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block; +@@ -767,7 +765,7 @@ diskfs_set_translator (struct node *np, const char *name, unsigned namelen, + { + /* Clear block for translator going away. */ + di->i_translator = 0; +- np->dn->info_i_translator = 0; ++ diskfs_node_disknode (np)->info_i_translator = 0; + record_global_poke (di); + ext2_free_blocks (blkno, 1); + +@@ -856,7 +854,7 @@ write_symlink (struct node *node, const char *target) + + assert (node->dn_stat.st_blocks == 0); + +- memcpy (node->dn->info.i_data, target, len); ++ memcpy (diskfs_node_disknode (node)->info.i_data, target, len); + node->dn_stat.st_size = len - 1; + node->dn_set_ctime = 1; + node->dn_set_mtime = 1; +@@ -873,7 +871,8 @@ read_symlink (struct node *node, char *target) + + assert (node->dn_stat.st_size < MAX_INODE_SYMLINK); + +- memcpy (target, node->dn->info.i_data, node->dn_stat.st_size); ++ memcpy (target, diskfs_node_disknode (node)->info.i_data, ++ node->dn_stat.st_size); + return 0; + } + +diff --git a/ext2fs/pager.c b/ext2fs/pager.c +index a6c4fbb..b56c923 100644 +--- a/ext2fs/pager.c ++++ b/ext2fs/pager.c +@@ -137,7 +137,7 @@ find_block (struct node *node, vm_offset_t offset, + + if (!*lock) + { +- *lock = &node->dn->alloc_lock; ++ *lock = &diskfs_node_disknode (node)->alloc_lock; + pthread_rwlock_rdlock (*lock); + } + +@@ -279,7 +279,7 @@ file_pager_read_page (struct node *node, vm_offset_t page, + err = do_pending_reads(); + + if (!err && partial && !*writelock) +- node->dn->last_page_partially_writable = 1; ++ diskfs_node_disknode (node)->last_page_partially_writable = 1; + + if (lock) + pthread_rwlock_unlock (lock); +@@ -377,16 +377,16 @@ file_pager_write_page (struct node *node, vm_offset_t offset, void *buf) + { + error_t err = 0; + struct pending_blocks pb; +- pthread_rwlock_t *lock = &node->dn->alloc_lock; ++ pthread_rwlock_t *lock = &diskfs_node_disknode (node)->alloc_lock; + block_t block; + int left = vm_page_size; + + pending_blocks_init (&pb, buf); + +- /* Holding NODE->dn->alloc_lock effectively locks NODE->allocsize, ++ /* Holding diskfs_node_disknode (node)->alloc_lock effectively locks NODE->allocsize, + at least for the cases we care about: pager_unlock_page, + diskfs_grow and diskfs_truncate. */ +- pthread_rwlock_rdlock (&node->dn->alloc_lock); ++ pthread_rwlock_rdlock (&diskfs_node_disknode (node)->alloc_lock); + + if (offset >= node->allocsize) + left = 0; +@@ -411,7 +411,7 @@ file_pager_write_page (struct node *node, vm_offset_t offset, void *buf) + if (!err) + pending_blocks_write (&pb); + +- pthread_rwlock_unlock (&node->dn->alloc_lock); ++ pthread_rwlock_unlock (&diskfs_node_disknode (node)->alloc_lock); + + return err; + } +@@ -583,7 +583,7 @@ pager_unlock_page (struct user_pager_info *pager, vm_offset_t page) + error_t err; + volatile int partial_page; + struct node *node = pager->node; +- struct disknode *dn = node->dn; ++ struct disknode *dn = diskfs_node_disknode (node); + + pthread_rwlock_wrlock (&dn->alloc_lock); + +@@ -656,7 +656,7 @@ diskfs_grow (struct node *node, off_t size, struct protid *cred) + volatile off_t new_size; + volatile block_t end_block; + block_t new_end_block; +- struct disknode *dn = node->dn; ++ struct disknode *dn = diskfs_node_disknode (node); + + pthread_rwlock_wrlock (&dn->alloc_lock); + +@@ -741,7 +741,7 @@ diskfs_file_update (struct node *node, int wait) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = node->dn->pager; ++ pager = diskfs_node_disknode (node)->pager; + if (pager) + ports_port_ref (pager); + pthread_spin_unlock (&node_to_page_lock); +@@ -752,7 +752,7 @@ diskfs_file_update (struct node *node, int wait) + ports_port_deref (pager); + } + +- pokel_sync (&node->dn->indir_pokel, wait); ++ pokel_sync (&diskfs_node_disknode (node)->indir_pokel, wait); + + diskfs_node_update (node, wait); + } +@@ -762,7 +762,7 @@ void + flush_node_pager (struct node *node) + { + struct pager *pager; +- struct disknode *dn = node->dn; ++ struct disknode *dn = diskfs_node_disknode (node); + + pthread_spin_lock (&node_to_page_lock); + pager = dn->pager; +@@ -806,9 +806,9 @@ pager_clear_user_data (struct user_pager_info *upi) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = upi->node->dn->pager; ++ pager = diskfs_node_disknode (upi->node)->pager; + if (pager && pager_get_upi (pager) == upi) +- upi->node->dn->pager = 0; ++ diskfs_node_disknode (upi->node)->pager = 0; + pthread_spin_unlock (&node_to_page_lock); + + diskfs_nrele_light (upi->node); +@@ -1236,7 +1236,7 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot) + pthread_spin_lock (&node_to_page_lock); + do + { +- struct pager *pager = node->dn->pager; ++ struct pager *pager = diskfs_node_disknode (node)->pager; + if (pager) + { + /* Because PAGER is not a real reference, +@@ -1245,9 +1245,9 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot) + and loop. The deallocation will complete separately. */ + right = pager_get_port (pager); + if (right == MACH_PORT_NULL) +- node->dn->pager = 0; +- else +- pager_get_upi (pager)->max_prot |= prot; ++ diskfs_node_disknode (node)->pager = 0; ++ else ++ pager_get_upi (pager)->max_prot |= prot; + } + else + { +@@ -1257,10 +1257,10 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot) + upi->node = node; + upi->max_prot = prot; + diskfs_nref_light (node); +- node->dn->pager = +- pager_create (upi, file_pager_bucket, MAY_CACHE, +- MEMORY_OBJECT_COPY_DELAY, 0); +- if (node->dn->pager == 0) ++ diskfs_node_disknode (node)->pager = ++ pager_create (upi, file_pager_bucket, MAY_CACHE, ++ MEMORY_OBJECT_COPY_DELAY, 0); ++ if (diskfs_node_disknode (node)->pager == 0) + { + diskfs_nrele_light (node); + free (upi); +@@ -1268,8 +1268,8 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot) + return MACH_PORT_NULL; + } + +- right = pager_get_port (node->dn->pager); +- ports_port_deref (node->dn->pager); ++ right = pager_get_port (diskfs_node_disknode (node)->pager); ++ ports_port_deref (diskfs_node_disknode (node)->pager); + } + } + while (right == MACH_PORT_NULL); +@@ -1289,7 +1289,7 @@ drop_pager_softrefs (struct node *node) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = node->dn->pager; ++ pager = diskfs_node_disknode (node)->pager; + if (pager) + ports_port_ref (pager); + pthread_spin_unlock (&node_to_page_lock); +@@ -1311,7 +1311,7 @@ allow_pager_softrefs (struct node *node) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = node->dn->pager; ++ pager = diskfs_node_disknode (node)->pager; + if (pager) + ports_port_ref (pager); + pthread_spin_unlock (&node_to_page_lock); +@@ -1331,7 +1331,7 @@ diskfs_get_filemap_pager_struct (struct node *node) + { + /* This is safe because pager can't be cleared; there must be + an active mapping for this to be called. */ +- return node->dn->pager; ++ return diskfs_node_disknode (node)->pager; + } + + /* Shutdown all the pagers (except the disk pager). */ +diff --git a/ext2fs/truncate.c b/ext2fs/truncate.c +index 63d2295..15e5541 100644 +--- a/ext2fs/truncate.c ++++ b/ext2fs/truncate.c +@@ -100,7 +100,7 @@ free_block_run_finish (struct free_block_run *fbr) + static void + trunc_direct (struct node *node, block_t end, struct free_block_run *fbr) + { +- block_t *blocks = node->dn->info.i_data; ++ block_t *blocks = diskfs_node_disknode (node)->info.i_data; + + ext2_debug ("truncating direct blocks from %d", end); + +@@ -230,7 +230,7 @@ force_delayed_copies (struct node *node, off_t length) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = node->dn->pager; ++ pager = diskfs_node_disknode (node)->pager; + if (pager) + ports_port_ref (pager); + pthread_spin_unlock (&node_to_page_lock); +@@ -260,7 +260,7 @@ enable_delayed_copies (struct node *node) + struct pager *pager; + + pthread_spin_lock (&node_to_page_lock); +- pager = node->dn->pager; ++ pager = diskfs_node_disknode (node)->pager; + if (pager) + ports_port_ref (pager); + pthread_spin_unlock (&node_to_page_lock); +@@ -322,7 +322,7 @@ diskfs_truncate (struct node *node, off_t length) + + force_delayed_copies (node, length); + +- pthread_rwlock_wrlock (&node->dn->alloc_lock); ++ pthread_rwlock_wrlock (&diskfs_node_disknode (node)->alloc_lock); + + /* Update the size on disk; fsck will finish freeing blocks if necessary + should we crash. */ +@@ -335,7 +335,7 @@ diskfs_truncate (struct node *node, off_t length) + if (!err) + { + block_t end = boffs_block (round_block (length)), offs; +- block_t *bptrs = node->dn->info.i_data; ++ block_t *bptrs = diskfs_node_disknode (node)->info.i_data; + struct free_block_run fbr; + + free_block_run_init (&fbr, node); +@@ -355,8 +355,8 @@ diskfs_truncate (struct node *node, off_t length) + + /* Set our last_page_partially_writable to a pessimistic state -- it + won't hurt if is wrong. */ +- node->dn->last_page_partially_writable = +- trunc_page (node->allocsize) != node->allocsize; ++ diskfs_node_disknode (node)->last_page_partially_writable = ++ trunc_page (node->allocsize) != node->allocsize; + + diskfs_end_catch_exception (); + } +@@ -368,7 +368,7 @@ diskfs_truncate (struct node *node, off_t length) + /* Now we can permit delayed copies again. */ + enable_delayed_copies (node); + +- pthread_rwlock_unlock (&node->dn->alloc_lock); ++ pthread_rwlock_unlock (&diskfs_node_disknode (node)->alloc_lock); + + return err; + } +-- +2.1.4 + diff --git a/debian/patches/0010-libdiskfs-implement-a-node-cache.patch b/debian/patches/0010-libdiskfs-implement-a-node-cache.patch new file mode 100644 index 00000000..c0c42926 --- /dev/null +++ b/debian/patches/0010-libdiskfs-implement-a-node-cache.patch @@ -0,0 +1,687 @@ +From 2bb8bfa49d35ab2f7b33587e59c4a9c635642ea0 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 15 Apr 2015 13:17:06 +0200 +Subject: [PATCH hurd 10/16] libdiskfs: implement a node cache + +xxx + +Move the node cache from ext2fs into libdiskfs. + +* ext2fs/dir.c +* ext2fs/ext2fs.c +* ext2fs/ext2fs.h +* ext2fs/inode.c +* libdiskfs/Makefile +* libdiskfs/diskfs.h +* libdiskfs/node-cache.c +--- + ext2fs/dir.c | 4 +- + ext2fs/ext2fs.c | 2 - + ext2fs/ext2fs.h | 9 -- + ext2fs/inode.c | 228 ++++---------------------------------------- + libdiskfs/Makefile | 2 +- + libdiskfs/diskfs.h | 17 ++++ + libdiskfs/node-cache.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 289 insertions(+), 222 deletions(-) + create mode 100644 libdiskfs/node-cache.c + +diff --git a/ext2fs/dir.c b/ext2fs/dir.c +index 2dfe1d7..6cdfba2 100644 +--- a/ext2fs/dir.c ++++ b/ext2fs/dir.c +@@ -306,7 +306,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + + /* Here below are the spec dotdot cases. */ + else if (type == RENAME || type == REMOVE) +- np = ifind (inum); ++ np = diskfs_cached_ifind (inum); + + else if (type == LOOKUP) + { +@@ -359,7 +359,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + diskfs_nput (np); + } + else if (type == RENAME || type == REMOVE) +- /* We just did ifind to get np; that allocates ++ /* We just did diskfs_cached_ifind to get np; that allocates + no new references, so we don't have anything to do */ + ; + else if (type == LOOKUP) +diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c +index beb7cad..d0fdfe7 100644 +--- a/ext2fs/ext2fs.c ++++ b/ext2fs/ext2fs.c +@@ -185,8 +185,6 @@ main (int argc, char **argv) + + map_hypermetadata (); + +- inode_init (); +- + /* Set diskfs_root_node to the root inode. */ + err = diskfs_cached_lookup (EXT2_ROOT_INO, &diskfs_root_node); + if (err) +diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h +index 9667b6f..96d8e9d 100644 +--- a/ext2fs/ext2fs.h ++++ b/ext2fs/ext2fs.h +@@ -159,9 +159,6 @@ struct disknode + each DIRBLKSIZE piece of the directory. */ + int *dirents; + +- /* Links on hash list. */ +- struct node *hnext, **hprevp; +- + /* Lock to lock while fiddling with this inode's block allocation info. */ + pthread_rwlock_t alloc_lock; + +@@ -419,12 +416,6 @@ dino_deref (struct ext2_inode *inode) + + /* Write all active disknodes into the inode pager. */ + void write_all_disknodes (); +- +-/* Lookup node INUM (which must have a reference already) and return it +- without allocating any new references. */ +-struct node *ifind (ino_t inum); +- +-void inode_init (void); + + /* ---------------------------------------------------------------- */ + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 7af617c..22a0c8e 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -39,144 +39,34 @@ + #define UF_IMMUTABLE 0 + #endif + +-#define INOHSZ 8192 +-#if ((INOHSZ&(INOHSZ-1)) == 0) +-#define INOHASH(ino) ((ino)&(INOHSZ-1)) +-#else +-#define INOHASH(ino) (((unsigned)(ino))%INOHSZ) +-#endif +- +-/* The nodehash is a cache of nodes. +- +- Access to nodehash and nodehash_nr_items is protected by +- nodecache_lock. +- +- Every node in the nodehash carries a light reference. When we are +- asked to give up that light reference, we reacquire our lock +- momentarily to check whether someone else reacquired a reference +- through the nodehash. */ +-static struct node *nodehash[INOHSZ]; +-static size_t nodehash_nr_items; +-static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; +- + static error_t read_node (struct node *np); + + pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER; + +-/* Initialize the inode hash table. */ +-void +-inode_init () +-{ +- int n; +- for (n = 0; n < INOHSZ; n++) +- nodehash[n] = 0; +-} +- +-/* Lookup node with inode number INUM. Returns NULL if the node is +- not found in the node cache. */ +-static struct node * +-lookup (ino_t inum) +-{ +- struct node *np; +- for (np = nodehash[INOHASH(inum)]; np; np = diskfs_node_disknode (np)->hnext) +- if (np->cache_id == inum) +- return np; +- return NULL; +-} +- +-/* Fetch inode INUM, set *NPP to the node structure; +- gain one user reference and lock the node. */ ++/* XXX */ + error_t +-diskfs_cached_lookup (ino_t inum, struct node **npp) ++diskfs_user_make_node (struct node **npp) + { +- error_t err; +- struct node *np, *tmp; ++ struct node *np; + struct disknode *dn; + +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- if (np) +- goto gotit; +- pthread_rwlock_unlock (&nodecache_lock); +- + /* Create the new node. */ + np = diskfs_make_node_alloc (sizeof *dn); +- dn = diskfs_node_disknode (np); +- np->cache_id = inum; ++ if (np == NULL) ++ return ENOMEM; + + /* Format specific data for the new node. */ ++ dn = diskfs_node_disknode (np); + dn->dirents = 0; + dn->dir_idx = 0; + dn->pager = 0; + pthread_rwlock_init (&dn->alloc_lock, NULL); + pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache); + +- pthread_mutex_lock (&np->lock); +- +- /* Put NP in NODEHASH. */ +- pthread_rwlock_wrlock (&nodecache_lock); +- tmp = lookup (inum); +- if (tmp) +- { +- /* We lost a race. */ +- diskfs_nput (np); +- np = tmp; +- goto gotit; +- } +- +- dn->hnext = nodehash[INOHASH(inum)]; +- if (dn->hnext) +- diskfs_node_disknode (dn->hnext)->hprevp = &dn->hnext; +- dn->hprevp = &nodehash[INOHASH(inum)]; +- nodehash[INOHASH(inum)] = np; +- diskfs_nref_light (np); +- nodehash_nr_items += 1; +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Get the contents of NP off disk. */ +- err = read_node (np); +- +- if (!diskfs_check_readonly () && !np->dn_stat.st_gen) +- { +- pthread_spin_lock (&generation_lock); +- if (++next_generation < diskfs_mtime->seconds) +- next_generation = diskfs_mtime->seconds; +- np->dn_stat.st_gen = next_generation; +- pthread_spin_unlock (&generation_lock); +- np->dn_set_ctime = 1; +- } +- +- if (err) +- return err; +- else +- { +- *npp = np; +- return 0; +- } +- +- gotit: +- diskfs_nref (np); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&np->lock); + *npp = np; + return 0; + } + +-/* Lookup node INUM (which must have a reference already) and return it +- without allocating any new references. */ +-struct node * +-ifind (ino_t inum) +-{ +- struct node *np; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- pthread_rwlock_unlock (&nodecache_lock); +- +- assert (np); +- return np; +-} +- + /* The last reference to a node has gone away; drop + it from the hash table and clean all state in the dn structure. */ + void +@@ -196,35 +86,8 @@ diskfs_node_norefs (struct node *np) + /* The last hard reference to a node has gone away; arrange to have + all the weak references dropped that can be. */ + void +-diskfs_try_dropping_softrefs (struct node *np) ++diskfs_user_try_dropping_softrefs (struct node *np) + { +- pthread_rwlock_wrlock (&nodecache_lock); +- if (diskfs_node_disknode (np)->hprevp != NULL) +- { +- /* Check if someone reacquired a reference through the +- nodehash. */ +- struct references result; +- refcounts_references (&np->refcounts, &result); +- +- if (result.hard > 0) +- { +- /* A reference was reacquired through a hash table lookup. +- It's fine, we didn't touch anything yet. */ +- pthread_rwlock_unlock (&nodecache_lock); +- return; +- } +- +- *diskfs_node_disknode (np)->hprevp = diskfs_node_disknode (np)->hnext; +- if (diskfs_node_disknode (np)->hnext) +- diskfs_node_disknode (diskfs_node_disknode (np)->hnext)->hprevp = +- diskfs_node_disknode (np)->hprevp; +- diskfs_node_disknode (np)->hnext = NULL; +- diskfs_node_disknode (np)->hprevp = NULL; +- nodehash_nr_items -= 1; +- diskfs_nrele_light (np); +- } +- pthread_rwlock_unlock (&nodecache_lock); +- + drop_pager_softrefs (np); + } + +@@ -243,8 +106,8 @@ diskfs_new_hardrefs (struct node *np) + } + + /* Read stat information out of the ext2_inode. */ +-static error_t +-read_node (struct node *np) ++error_t ++diskfs_user_read_node (struct node *np) + { + error_t err; + struct stat *st = &np->dn_stat; +@@ -384,6 +247,16 @@ read_node (struct node *np) + linux, some devices). */ + np->allocsize = 0; + ++ if (!diskfs_check_readonly () && !np->dn_stat.st_gen) ++ { ++ pthread_spin_lock (&generation_lock); ++ if (++next_generation < diskfs_mtime->seconds) ++ next_generation = diskfs_mtime->seconds; ++ np->dn_stat.st_gen = next_generation; ++ pthread_spin_unlock (&generation_lock); ++ np->dn_set_ctime = 1; ++ } ++ + return 0; + } + +@@ -585,72 +458,11 @@ diskfs_node_reload (struct node *node) + } + pokel_flush (&dn->indir_pokel); + flush_node_pager (node); +- read_node (node); ++ diskfs_user_read_node (node); + + return 0; + } + +-/* For each active node, call FUN. The node is to be locked around the call +- to FUN. If FUN returns non-zero for any node, then immediately stop, and +- return that value. */ +-error_t +-diskfs_node_iterate (error_t (*fun)(struct node *)) +-{ +- error_t err = 0; +- int n; +- size_t num_nodes; +- struct node *node, **node_list, **p; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- +- /* We must copy everything from the hash table into another data structure +- to avoid running into any problems with the hash-table being modified +- during processing (normally we delegate access to hash-table with +- nodecache_lock, but we can't hold this while locking the +- individual node locks). */ +- num_nodes = nodehash_nr_items; +- +- /* TODO This method doesn't scale beyond a few dozen nodes and should be +- replaced. */ +- node_list = malloc (num_nodes * sizeof (struct node *)); +- if (node_list == NULL) +- { +- pthread_rwlock_unlock (&nodecache_lock); +- ext2_debug ("unable to allocate temporary node table"); +- return ENOMEM; +- } +- +- p = node_list; +- for (n = 0; n < INOHSZ; n++) +- for (node = nodehash[n]; node; node = diskfs_node_disknode (node)->hnext) +- { +- *p++ = node; +- +- /* We acquire a hard reference for node, but without using +- diskfs_nref. We do this so that diskfs_new_hardrefs will not +- get called. */ +- refcounts_ref (&node->refcounts, NULL); +- } +- +- pthread_rwlock_unlock (&nodecache_lock); +- +- p = node_list; +- while (num_nodes-- > 0) +- { +- node = *p++; +- if (!err) +- { +- pthread_mutex_lock (&node->lock); +- err = (*fun)(node); +- pthread_mutex_unlock (&node->lock); +- } +- diskfs_nrele (node); +- } +- +- free (node_list); +- return err; +-} +- + /* Write all active disknodes into the ext2_inode pager. */ + void + write_all_disknodes () +diff --git a/libdiskfs/Makefile b/libdiskfs/Makefile +index 996e86a..47b9339 100644 +--- a/libdiskfs/Makefile ++++ b/libdiskfs/Makefile +@@ -41,7 +41,7 @@ OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c dir-renamed.c \ + extern-inline.c \ + node-create.c node-drop.c node-make.c node-rdwr.c node-update.c \ + node-nref.c node-nput.c node-nrele.c node-nrefl.c node-nputl.c \ +- node-nrelel.c \ ++ node-nrelel.c node-cache.c \ + peropen-make.c peropen-rele.c protid-make.c protid-rele.c \ + init-init.c init-startup.c init-first.c init-main.c \ + rdwr-internal.c boot-start.c demuxer.c node-times.c shutdown.c \ +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 7a21dff..22c4aa6 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -80,6 +80,9 @@ struct peropen + filesystem. */ + struct node + { ++ /* Links on hash list. */ ++ struct node *hnext, **hprevp; ++ + struct disknode *dn; + + io_statbuf_t dn_stat; +@@ -1102,4 +1105,18 @@ struct store *diskfs_init_main (struct argp *startup_argp, + /* Make errors go somewhere reasonable. */ + void diskfs_console_stdio (); + ++//XXX ++/* XXX */ ++error_t diskfs_user_make_node (struct node **npp); ++/* Read stat information out of the ext2_inode. */ ++error_t diskfs_user_read_node (struct node *np); ++/* The last hard reference to a node has gone away; arrange to have ++ all the weak references dropped that can be. */ ++void diskfs_user_try_dropping_softrefs (struct node *np); ++ ++/* Lookup node INUM (which must have a reference already) and return it ++ without allocating any new references. */ ++struct node *diskfs_cached_ifind (ino_t inum); ++ ++ + #endif /* hurd/diskfs.h */ +diff --git a/libdiskfs/node-cache.c b/libdiskfs/node-cache.c +new file mode 100644 +index 0000000..58249bf +--- /dev/null ++++ b/libdiskfs/node-cache.c +@@ -0,0 +1,249 @@ ++/* Inode cache. ++ ++ Copyright (C) 1994-2015 Free Software Foundation, Inc. ++ ++ This file is part of the GNU Hurd. ++ ++ The GNU Hurd is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, or (at ++ your option) any later version. ++ ++ The GNU Hurd is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */ ++ ++#include "priv.h" ++ ++#define INOHSZ 8192 ++#if ((INOHSZ&(INOHSZ-1)) == 0) ++#define INOHASH(ino) ((ino)&(INOHSZ-1)) ++#else ++#define INOHASH(ino) (((unsigned)(ino))%INOHSZ) ++#endif ++ ++/* The nodehash is a cache of nodes. ++ ++ Access to nodehash and nodehash_nr_items is protected by ++ nodecache_lock. ++ ++ Every node in the nodehash carries a light reference. When we are ++ asked to give up that light reference, we reacquire our lock ++ momentarily to check whether someone else reacquired a reference ++ through the nodehash. */ ++static struct node *nodehash[INOHSZ]; ++static size_t nodehash_nr_items; ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; ++ ++/* Initialize the inode hash table. */ ++static void __attribute__ ((constructor)) ++nodecache_init () ++{ ++} ++ ++/* Lookup node with inode number INUM. Returns NULL if the node is ++ not found in the node cache. */ ++static struct node * ++lookup (ino_t inum) ++{ ++ struct node *np; ++ for (np = nodehash[INOHASH(inum)]; np; np = np->hnext) ++ if (np->cache_id == inum) ++ return np; ++ return NULL; ++} ++ ++/* Fetch inode INUM, set *NPP to the node structure; ++ gain one user reference and lock the node. */ ++error_t __attribute__ ((weak)) ++diskfs_cached_lookup (ino_t inum, struct node **npp) ++{ ++ error_t err; ++ struct node *np, *tmp; ++ ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ if (np) ++ goto gotit; ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ err = diskfs_user_make_node (&np); ++ if (err) ++ return err; ++ ++ np->cache_id = inum; ++ pthread_mutex_lock (&np->lock); ++ ++ /* Put NP in NODEHASH. */ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ tmp = lookup (inum); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = tmp; ++ goto gotit; ++ } ++ ++ np->hnext = nodehash[INOHASH(inum)]; ++ if (np->hnext) ++ np->hnext->hprevp = &np->hnext; ++ np->hprevp = &nodehash[INOHASH(inum)]; ++ nodehash[INOHASH(inum)] = np; ++ diskfs_nref_light (np); ++ nodehash_nr_items += 1; ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ /* Get the contents of NP off disk. */ ++ err = diskfs_user_read_node (np); ++ if (err) ++ return err; ++ else ++ { ++ *npp = np; ++ return 0; ++ } ++ ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&np->lock); ++ *npp = np; ++ return 0; ++} ++ ++/* Lookup node INUM (which must have a reference already) and return it ++ without allocating any new references. */ ++struct node * ++diskfs_cached_ifind (ino_t inum) ++{ ++ struct node *np; ++ ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ assert (np); ++ return np; ++} ++ ++void __attribute__ ((weak)) ++diskfs_try_dropping_softrefs (struct node *np) ++{ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (np->hprevp != NULL) ++ { ++ /* Check if someone reacquired a reference through the ++ nodehash. */ ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_rwlock_unlock (&nodecache_lock); ++ return; ++ } ++ ++ *np->hprevp = np->hnext; ++ if (np->hnext) ++ np->hnext->hprevp = np->hprevp; ++ np->hnext = NULL; ++ np->hprevp = NULL; ++ nodehash_nr_items -= 1; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ diskfs_user_try_dropping_softrefs (np); ++} ++ ++/* For each active node, call FUN. The node is to be locked around the call ++ to FUN. If FUN returns non-zero for any node, then immediately stop, and ++ return that value. */ ++error_t __attribute__ ((weak)) ++diskfs_node_iterate (error_t (*fun)(struct node *)) ++{ ++ error_t err = 0; ++ int n; ++ size_t num_nodes; ++ struct node *node, **node_list, **p; ++ ++ pthread_rwlock_rdlock (&nodecache_lock); ++ ++ /* We must copy everything from the hash table into another data structure ++ to avoid running into any problems with the hash-table being modified ++ during processing (normally we delegate access to hash-table with ++ nodecache_lock, but we can't hold this while locking the ++ individual node locks). */ ++ /* XXX: Can we? */ ++ num_nodes = nodehash_nr_items; ++ ++ /* TODO This method doesn't scale beyond a few dozen nodes and should be ++ replaced. */ ++ node_list = malloc (num_nodes * sizeof (struct node *)); ++ if (node_list == NULL) ++ { ++ pthread_rwlock_unlock (&nodecache_lock); ++ error (0, 0, "unable to allocate temporary node table"); ++ return ENOMEM; ++ } ++ ++ p = node_list; ++ for (n = 0; n < INOHSZ; n++) ++ for (node = nodehash[n]; node; node = node->hnext) ++ { ++ *p++ = node; ++ ++ /* We acquire a hard reference for node, but without using ++ diskfs_nref. We do this so that diskfs_new_hardrefs will not ++ get called. */ ++ refcounts_ref (&node->refcounts, NULL); ++ } ++ ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ p = node_list; ++ while (num_nodes-- > 0) ++ { ++ node = *p++; ++ if (!err) ++ { ++ pthread_mutex_lock (&node->lock); ++ err = (*fun)(node); ++ pthread_mutex_unlock (&node->lock); ++ } ++ diskfs_nrele (node); ++ } ++ ++ free (node_list); ++ return err; ++} ++ ++/* XXX */ ++error_t __attribute__ ((weak)) ++diskfs_user_make_node (struct node **npp) ++{ ++ assert (! "diskfs_user_make_node not implemented"); ++} ++ ++/* Read stat information out of the ext2_inode. */ ++error_t __attribute__ ((weak)) ++diskfs_user_read_node (struct node *np) ++{ ++ assert (! "diskfs_user_read_node not implemented"); ++} ++ ++/* The last hard reference to a node has gone away; arrange to have ++ all the weak references dropped that can be. */ ++void __attribute__ ((weak)) ++diskfs_user_try_dropping_softrefs (struct node *np) ++{ ++ assert (! "diskfs_user_try_dropping_softrefs not implemented"); ++} ++ +-- +2.1.4 + diff --git a/debian/patches/0011-fixup_isofs.patch b/debian/patches/0011-fixup_isofs.patch new file mode 100644 index 00000000..20091dd1 --- /dev/null +++ b/debian/patches/0011-fixup_isofs.patch @@ -0,0 +1,27 @@ +From 12097a157de0532600aee3c8304aef90c4baed75 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 15 Apr 2015 14:05:34 +0200 +Subject: [PATCH hurd 11/16] fixup_isofs + +--- + isofs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/isofs/inode.c b/isofs/inode.c +index 340bc9c..e79ebdd 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -354,9 +354,9 @@ load_inode (struct node **npp, struct dirrect *record, + + pthread_rwlock_rdlock (&nodecache_lock); + inode_cache_find (id, npp); ++ pthread_rwlock_unlock (&nodecache_lock); + if (*npp) + return 0; +- pthread_rwlock_unlock (&nodecache_lock); + + /* Create a new node */ + dn = malloc (sizeof (struct disknode)); +-- +2.1.4 + diff --git a/debian/patches/0012-fixup_ext2fs.patch b/debian/patches/0012-fixup_ext2fs.patch new file mode 100644 index 00000000..4fbee63c --- /dev/null +++ b/debian/patches/0012-fixup_ext2fs.patch @@ -0,0 +1,25 @@ +From 6bc12095d8aa4b38ceecb3da21491724b189141a Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 15 Apr 2015 14:19:43 +0200 +Subject: [PATCH hurd 12/16] fixup_ext2fs + +--- + ext2fs/inode.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 22a0c8e..ee190fa 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -39,8 +39,6 @@ + #define UF_IMMUTABLE 0 + #endif + +-static error_t read_node (struct node *np); +- + pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER; + + /* XXX */ +-- +2.1.4 + diff --git a/debian/patches/0013-xxx-half-assed-try-to-port-isofs-to-the-node-cache.patch b/debian/patches/0013-xxx-half-assed-try-to-port-isofs-to-the-node-cache.patch new file mode 100644 index 00000000..64cc167e --- /dev/null +++ b/debian/patches/0013-xxx-half-assed-try-to-port-isofs-to-the-node-cache.patch @@ -0,0 +1,356 @@ +From 128449af8811d49a7cd4f8b686ad15e58a5ba19b Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 15 Apr 2015 16:26:31 +0200 +Subject: [PATCH hurd 13/16] xxx half-assed try to port isofs to the node cache + +--- + isofs/inode.c | 88 ++++++++++++++++++++++++++++------------------------------ + isofs/isofs.h | 6 +++- + isofs/lookup.c | 18 +++++++++--- + isofs/main.c | 6 +++- + isofs/rr.c | 4 +++ + 5 files changed, 70 insertions(+), 52 deletions(-) + +diff --git a/isofs/inode.c b/isofs/inode.c +index e79ebdd..16abd86 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -40,8 +40,8 @@ + + struct node_cache + { +- struct dirrect *dr; /* somewhere in disk_image */ +- off_t file_start; /* start of file */ ++ //struct dirrect *dr; /* somewhere in disk_image */ ++ //off_t file_start; /* start of file */ + + off_t id; /* UNIQUE identifier. */ + +@@ -63,8 +63,7 @@ struct node_cache *node_cache = 0; + static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + /* Forward */ +-static error_t read_disknode (struct node *, +- struct dirrect *, struct rrip_lookup *); ++static error_t read_disknode (struct node *); + + + /* Lookup node with id ID. Returns NULL if the node is not found in +@@ -111,21 +110,14 @@ use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) + /* Enter NP into the cache. The directory entry we used is DR, the + cached Rock-Ridge info RR. nodecache_lock must be held. */ + void +-cache_inode (struct node *np, struct dirrect *record, +- struct rrip_lookup *rr) ++cache_inode (ino_t id, struct node *np) + { + int i; + struct node_cache *c = 0; +- off_t id; +- +- if (use_file_start_id (record, rr)) +- id = np->dn->file_start << store->log2_block_size; +- else +- id = (off_t) ((void *) record - (void *) disk_image); + + /* First see if there's already an entry. */ + for (i = 0; i < node_cache_size; i++) +- if (node_cache[i].id == id) ++ if (node_cache[i].id == (off_t) id) + break; + + if (i == node_cache_size) +@@ -151,14 +143,9 @@ cache_inode (struct node *np, struct dirrect *record, + } + + c = &node_cache[i]; +- c->id = id; +- c->dr = record; +- c->file_start = np->dn->file_start; ++ c->id = (off_t) id; + diskfs_nref_light (np); + c->np = np; +- +- /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */ +- np->cache_id = i + 1; + } + + /* Fetch inode with cache id ID; set *NPP to the node structure; +@@ -177,7 +164,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + assert (id < node_cache_size); + + np = node_cache[id].np; +- ++ assert (np); + if (!np) + { + struct node_cache *c = &node_cache[id]; +@@ -186,7 +173,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + + pthread_rwlock_unlock (&nodecache_lock); + +- rrip_lookup (node_cache[id].dr, &rr, 1); ++ //rrip_lookup (node_cache[id].dr, &rr, 1); + + /* We should never cache the wrong directory entry */ + assert (!(rr.valid & VALID_CL)); +@@ -199,8 +186,8 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + return ENOMEM; + } + dn->fileinfo = 0; +- dn->dr = c->dr; +- dn->file_start = c->file_start; ++ //dn->dr = c->dr; ++ //dn->file_start = c->file_start; + np = diskfs_make_node (dn); + if (!np) + { +@@ -224,7 +211,8 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + diskfs_nref_light (np); + pthread_rwlock_unlock (&nodecache_lock); + +- err = read_disknode (np, dn->dr, &rr); ++ dn->rr = rr; ++ err = read_disknode (np); + if (!err) + *npp = np; + +@@ -327,33 +315,38 @@ calculate_file_start (struct dirrect *record, off_t *file_start, + return 0; + } + +- +-/* Load the inode with directory entry RECORD and cached Rock-Ridge +- info RR into NP. The directory entry is at OFFSET in BLOCK. */ ++/* Given RECORD and RR, calculate the cache id. */ + error_t +-load_inode (struct node **npp, struct dirrect *record, +- struct rrip_lookup *rr) ++cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp) + { + error_t err; + off_t file_start; +- struct disknode *dn; +- struct node *np, *tmp; +- off_t id; +- + err = calculate_file_start (record, &file_start, rr); + if (err) + return err; ++ + if (rr->valid & VALID_CL) + record = rr->realdirent; + +- /* First check the cache */ + if (use_file_start_id (record, rr)) +- id = file_start << store->log2_block_size; ++ *idp = file_start << store->log2_block_size; + else +- id = (off_t) ((void *) record - (void *) disk_image); ++ *idp = (off_t) ((void *) record - (void *) disk_image); ++ return 0; ++} ++ ++/* Load the inode with directory entry RECORD and cached Rock-Ridge ++ info RR into NP. The directory entry is at OFFSET in BLOCK. */ ++error_t ++load_inode (ino_t id, struct node **npp, struct dirrect *record, ++ struct rrip_lookup *rr) ++{ ++ error_t err; ++ struct disknode *dn; ++ struct node *np, *tmp; + + pthread_rwlock_rdlock (&nodecache_lock); +- inode_cache_find (id, npp); ++ inode_cache_find ((off_t) id, npp); + pthread_rwlock_unlock (&nodecache_lock); + if (*npp) + return 0; +@@ -363,9 +356,14 @@ load_inode (struct node **npp, struct dirrect *record, + if (!dn) + return ENOMEM; + ++ err = calculate_file_start (record, &dn->file_start, rr); ++ if (err) ++ { ++ free (dn); ++ return err; ++ } + dn->fileinfo = 0; + dn->dr = record; +- dn->file_start = file_start; + + np = diskfs_make_node (dn); + if (!np) +@@ -388,10 +386,10 @@ load_inode (struct node **npp, struct dirrect *record, + return 0; + } + +- cache_inode (np, record, rr); ++ cache_inode (id, np); + pthread_rwlock_unlock (&nodecache_lock); + +- err = read_disknode (np, record, rr); ++ err = read_disknode (np); + *npp = np; + return err; + } +@@ -400,17 +398,15 @@ load_inode (struct node **npp, struct dirrect *record, + /* Read stat information from the directory entry at DR and the + contents of RL. */ + static error_t +-read_disknode (struct node *np, struct dirrect *dr, +- struct rrip_lookup *rl) ++read_disknode (struct node *np) + { + error_t err; + struct stat *st = &np->dn_stat; ++ struct dirrect *dr = np->dn->dr; ++ struct rrip_lookup *rl = &np->dn->rr; + st->st_fstype = FSTYPE_ISO9660; + st->st_fsid = getpid (); +- if (use_file_start_id (dr, rl)) +- st->st_ino = (ino_t) np->dn->file_start << store->log2_block_size; +- else +- st->st_ino = (ino_t) ((void *) dr - (void *) disk_image); ++ st->st_ino = np->cache_id; + st->st_gen = 0; + st->st_rdev = 0; + +diff --git a/isofs/isofs.h b/isofs/isofs.h +index 68a94e9..9aa9608 100644 +--- a/isofs/isofs.h ++++ b/isofs/isofs.h +@@ -34,6 +34,7 @@ + struct disknode + { + struct dirrect *dr; /* Somewhere in disk_image. */ ++ struct rrip_lookup rr; + + off_t file_start; /* In store->block_size units */ + +@@ -87,7 +88,10 @@ void drop_pager_softrefs (struct node *); + void allow_pager_softrefs (struct node *); + void create_disk_pager (void); + +-error_t load_inode (struct node **, struct dirrect *, struct rrip_lookup *); ++/* Given RECORD and RR, calculate the cache id. */ ++error_t cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp); ++ ++error_t load_inode (ino_t, struct node **, struct dirrect *, struct rrip_lookup *); + error_t calculate_file_start (struct dirrect *, off_t *, struct rrip_lookup *); + + char *isodate_915 (char *, struct timespec *); +diff --git a/isofs/lookup.c b/isofs/lookup.c +index e51b9cb..f0bd73b 100644 +--- a/isofs/lookup.c ++++ b/isofs/lookup.c +@@ -76,6 +76,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + void *buf; + void *blockaddr; + struct rrip_lookup rr; ++ ino_t id; + + if ((type == REMOVE) || (type == RENAME)) + assert (npp); +@@ -115,6 +116,10 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + if (err) + return err; + ++ err = cache_id (record, &rr, &id); ++ if (err) ++ return err; ++ + /* Load the inode */ + if (namelen == 2 && name[0] == '.' && name[1] == '.') + { +@@ -125,7 +130,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + /* renames and removes can't get this far. */ + assert (type == LOOKUP); + diskfs_nput (dp); +- err = load_inode (npp, record, &rr); ++ err = load_inode (id, npp, record, &rr); + } + else + { +@@ -133,7 +138,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + we are permanently read-only, so things are necessarily + quiescent. Just be careful to honor the locking order. */ + pthread_mutex_unlock (&dp->lock); +- err = load_inode (npp, record, &rr); ++ err = load_inode (id, npp, record, &rr); + pthread_mutex_lock (&dp->lock); + } + } +@@ -143,9 +148,14 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + diskfs_nref (dp); + } + else +- err = load_inode (npp, record, &rr); ++ err = load_inode (id, npp, record, &rr); ++ ++ (*npp)->dn->dr = record; ++ if ((*npp)->dn->rr.valid) ++ release_rrip (&rr); ++ else ++ (*npp)->dn->rr = rr; + +- release_rrip (&rr); + return err; + } + +diff --git a/isofs/main.c b/isofs/main.c +index 4f531f7..fb111dd 100644 +--- a/isofs/main.c ++++ b/isofs/main.c +@@ -46,6 +46,7 @@ fetch_root () + { + struct rrip_lookup rl; + struct dirrect *dr; ++ ino_t id; + error_t err; + + dr = (struct dirrect *) sblock->root; +@@ -56,8 +57,11 @@ fetch_root () + /* Now rescan the node for real */ + rrip_lookup (dr, &rl, 1); + ++ err = cache_id (dr, &rl, &id); ++ assert_perror (err); ++ + /* And fetch the node. */ +- err = load_inode (&diskfs_root_node, dr, &rl); ++ err = load_inode (id, &diskfs_root_node, dr, &rl); + assert_perror (err); + + pthread_mutex_unlock (&diskfs_root_node->lock); +diff --git a/isofs/rr.c b/isofs/rr.c +index adc95c3..2429fae 100644 +--- a/isofs/rr.c ++++ b/isofs/rr.c +@@ -38,10 +38,13 @@ release_rrip (struct rrip_lookup *rr) + { + if ((rr->valid & VALID_NM) && rr->name) + free (rr->name); ++ rr->name = NULL; + if ((rr->valid & VALID_SL) && rr->target) + free (rr->target); ++ rr->target = NULL; + if ((rr->valid & VALID_TR) && rr->trans) + free (rr->trans); ++ rr->trans = NULL; + } + + +@@ -51,6 +54,7 @@ rrip_work (struct dirrect *dr, struct rrip_lookup *rr, + const char *match_name, size_t match_name_len, + int initializing, int ignorenm) + { ++ // error (0, 0, "rrip_work %p %p %s %d %d %d", dr, rr, match_name, match_name_len, initializing, ignorenm); + void *bp, *terminus; + void *slbuf, *nmbuf; + size_t slbufsize, nmbufsize; +-- +2.1.4 + diff --git a/debian/patches/0014-libdiskfs-xxx-lookup-context.patch b/debian/patches/0014-libdiskfs-xxx-lookup-context.patch new file mode 100644 index 00000000..bb6510f2 --- /dev/null +++ b/debian/patches/0014-libdiskfs-xxx-lookup-context.patch @@ -0,0 +1,133 @@ +From e41191579f7330b93d0a35c175a804423c5c60e5 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Thu, 16 Apr 2015 15:25:15 +0200 +Subject: [PATCH hurd 14/16] libdiskfs: xxx lookup context + +* ext2fs/inode.c +* libdiskfs/diskfs.h +* libdiskfs/node-cache.c +--- + ext2fs/inode.c | 6 +++--- + libdiskfs/diskfs.h | 11 +++++++++-- + libdiskfs/node-cache.c | 17 +++++++++++++---- + 3 files changed, 25 insertions(+), 9 deletions(-) + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index ee190fa..93d686a 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -43,7 +43,7 @@ pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER; + + /* XXX */ + error_t +-diskfs_user_make_node (struct node **npp) ++diskfs_user_make_node (struct node **npp, struct lookup_context *ctx) + { + struct node *np; + struct disknode *dn; +@@ -105,7 +105,7 @@ diskfs_new_hardrefs (struct node *np) + + /* Read stat information out of the ext2_inode. */ + error_t +-diskfs_user_read_node (struct node *np) ++diskfs_user_read_node (struct node *np, struct lookup_context *ctx) + { + error_t err; + struct stat *st = &np->dn_stat; +@@ -456,7 +456,7 @@ diskfs_node_reload (struct node *node) + } + pokel_flush (&dn->indir_pokel); + flush_node_pager (node); +- diskfs_user_read_node (node); ++ diskfs_user_read_node (node, NULL); + + return 0; + } +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 22c4aa6..f7872ff 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -1106,10 +1106,14 @@ struct store *diskfs_init_main (struct argp *startup_argp, + void diskfs_console_stdio (); + + //XXX ++ ++/* XXX */ ++struct lookup_context; ++ + /* XXX */ +-error_t diskfs_user_make_node (struct node **npp); ++error_t diskfs_user_make_node (struct node **npp, struct lookup_context *ctx); + /* Read stat information out of the ext2_inode. */ +-error_t diskfs_user_read_node (struct node *np); ++error_t diskfs_user_read_node (struct node *np, struct lookup_context *ctx); + /* The last hard reference to a node has gone away; arrange to have + all the weak references dropped that can be. */ + void diskfs_user_try_dropping_softrefs (struct node *np); +@@ -1118,5 +1122,8 @@ void diskfs_user_try_dropping_softrefs (struct node *np); + without allocating any new references. */ + struct node *diskfs_cached_ifind (ino_t inum); + ++error_t diskfs_cached_lookup_context (ino_t inum, struct node **npp, ++ struct lookup_context *ctx); ++ + + #endif /* hurd/diskfs.h */ +diff --git a/libdiskfs/node-cache.c b/libdiskfs/node-cache.c +index 58249bf..bad2bac 100644 +--- a/libdiskfs/node-cache.c ++++ b/libdiskfs/node-cache.c +@@ -62,6 +62,15 @@ lookup (ino_t inum) + error_t __attribute__ ((weak)) + diskfs_cached_lookup (ino_t inum, struct node **npp) + { ++ return diskfs_cached_lookup_context (inum, npp, NULL); ++} ++ ++/* Fetch inode INUM, set *NPP to the node structure; ++ gain one user reference and lock the node. */ ++error_t ++diskfs_cached_lookup_context (ino_t inum, struct node **npp, ++ struct lookup_context *ctx) ++{ + error_t err; + struct node *np, *tmp; + +@@ -71,7 +80,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + goto gotit; + pthread_rwlock_unlock (&nodecache_lock); + +- err = diskfs_user_make_node (&np); ++ err = diskfs_user_make_node (&np, ctx); + if (err) + return err; + +@@ -99,7 +108,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp) + pthread_rwlock_unlock (&nodecache_lock); + + /* Get the contents of NP off disk. */ +- err = diskfs_user_read_node (np); ++ err = diskfs_user_read_node (np, ctx); + if (err) + return err; + else +@@ -227,14 +236,14 @@ diskfs_node_iterate (error_t (*fun)(struct node *)) + + /* XXX */ + error_t __attribute__ ((weak)) +-diskfs_user_make_node (struct node **npp) ++diskfs_user_make_node (struct node **npp, struct lookup_context *ctx) + { + assert (! "diskfs_user_make_node not implemented"); + } + + /* Read stat information out of the ext2_inode. */ + error_t __attribute__ ((weak)) +-diskfs_user_read_node (struct node *np) ++diskfs_user_read_node (struct node *np, struct lookup_context *ctx) + { + assert (! "diskfs_user_read_node not implemented"); + } +-- +2.1.4 + diff --git a/debian/patches/0015-fixup_isofs.patch b/debian/patches/0015-fixup_isofs.patch new file mode 100644 index 00000000..603461f7 --- /dev/null +++ b/debian/patches/0015-fixup_isofs.patch @@ -0,0 +1,522 @@ +From 028e9e1b224d2e1b1cb48aa40e22fc03fcc11927 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Thu, 16 Apr 2015 15:36:01 +0200 +Subject: [PATCH hurd 15/16] fixup_isofs + +--- + isofs/inode.c | 296 +++++---------------------------------------------------- + isofs/isofs.h | 9 +- + isofs/lookup.c | 20 ++-- + isofs/main.c | 13 ++- + 4 files changed, 43 insertions(+), 295 deletions(-) + +diff --git a/isofs/inode.c b/isofs/inode.c +index 16abd86..5163df5 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -31,71 +31,6 @@ + record for symlinks and zero length files, and file_start otherwise. + Only for hard links to zero length files we get extra inodes. */ + +-#define INOHSZ 512 +-#if ((INOHSZ&(INOHSZ-1)) == 0) +-#define INOHASH(ino) ((ino>>8)&(INOHSZ-1)) +-#else +-#define INOHASH(ino) (((unsigned)(ino>>8))%INOHSZ) +-#endif +- +-struct node_cache +-{ +- //struct dirrect *dr; /* somewhere in disk_image */ +- //off_t file_start; /* start of file */ +- +- off_t id; /* UNIQUE identifier. */ +- +- struct node *np; /* if live */ +-}; +- +-/* The node_cache is a cache of nodes. +- +- Access to node_cache, node_cache_size, and node_cache_alloced is +- protected by nodecache_lock. +- +- Every node in the node_cache carries a light reference. When we +- are asked to give up that light reference, we reacquire our lock +- momentarily to check whether someone else reacquired a reference +- through the node_cache. */ +-static int node_cache_size = 0; +-static int node_cache_alloced = 0; +-struct node_cache *node_cache = 0; +-static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; +- +-/* Forward */ +-static error_t read_disknode (struct node *); +- +- +-/* Lookup node with id ID. Returns NULL if the node is not found in +- the node cache. */ +-static struct node * +-lookup (off_t id) +-{ +- int i; +- for (i = 0; i < node_cache_size; i++) +- if (node_cache[i].id == id +- && node_cache[i].np) +- return node_cache[i].np; +- return NULL; +-} +- +-/* See if node with identifier ID is in the cache. If so, return it, +- with one additional reference. nodecache_lock must be held +- on entry to the call, and will be released iff the node was found +- in the cache. */ +-void +-inode_cache_find (off_t id, struct node **npp) +-{ +- *npp = lookup (id); +- if (*npp) +- { +- diskfs_nref (*npp); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&(*npp)->lock); +- } +-} +- +- + /* Determine if we use file_start or struct dirrect * as node id. */ + int + use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) +@@ -107,129 +42,34 @@ use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) + return 1; + } + +-/* Enter NP into the cache. The directory entry we used is DR, the +- cached Rock-Ridge info RR. nodecache_lock must be held. */ +-void +-cache_inode (ino_t id, struct node *np) +-{ +- int i; +- struct node_cache *c = 0; +- +- /* First see if there's already an entry. */ +- for (i = 0; i < node_cache_size; i++) +- if (node_cache[i].id == (off_t) id) +- break; +- +- if (i == node_cache_size) +- { +- if (node_cache_size >= node_cache_alloced) +- { +- if (!node_cache_alloced) +- { +- /* Initialize */ +- node_cache_alloced = 10; +- node_cache = malloc (sizeof (struct node_cache) * 10); +- } +- else +- { +- node_cache_alloced *= 2; +- node_cache = realloc (node_cache, +- sizeof (struct node_cache) +- * node_cache_alloced); +- } +- assert (node_cache); +- } +- node_cache_size++; +- } +- +- c = &node_cache[i]; +- c->id = (off_t) id; +- diskfs_nref_light (np); +- c->np = np; +-} +- +-/* Fetch inode with cache id ID; set *NPP to the node structure; +- gain one user reference and lock the node. */ ++/* XXX */ + error_t +-diskfs_cached_lookup (ino_t id, struct node **npp) ++diskfs_user_make_node (struct node **npp, struct lookup_context *ctx) + { +- struct node *np; + error_t err; ++ struct node *np; ++ struct disknode *dn; + +- /* Cache ID's are incremented when presented to diskfs +- to avoid presenting zero cache ID's. */ +- id--; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- assert (id < node_cache_size); ++ /* Create the new node. */ ++ np = diskfs_make_node_alloc (sizeof *dn); ++ if (np == NULL) ++ return ENOMEM; + +- np = node_cache[id].np; +- assert (np); +- if (!np) ++ /* Format specific data for the new node. */ ++ dn = diskfs_node_disknode (np); ++ dn->fileinfo = 0; ++ dn->dr = ctx->dr; ++ err = calculate_file_start (ctx->dr, &dn->file_start, &ctx->rr); ++ if (err) + { +- struct node_cache *c = &node_cache[id]; +- struct rrip_lookup rr; +- struct disknode *dn; +- +- pthread_rwlock_unlock (&nodecache_lock); +- +- //rrip_lookup (node_cache[id].dr, &rr, 1); +- +- /* We should never cache the wrong directory entry */ +- assert (!(rr.valid & VALID_CL)); +- +- dn = malloc (sizeof (struct disknode)); +- if (!dn) +- { +- pthread_rwlock_unlock (&nodecache_lock); +- release_rrip (&rr); +- return ENOMEM; +- } +- dn->fileinfo = 0; +- //dn->dr = c->dr; +- //dn->file_start = c->file_start; +- np = diskfs_make_node (dn); +- if (!np) +- { +- free (dn); +- pthread_rwlock_unlock (&nodecache_lock); +- release_rrip (&rr); +- return ENOMEM; +- } +- np->cache_id = id + 1; /* see above for rationale for increment */ +- pthread_mutex_lock (&np->lock); +- +- pthread_rwlock_wrlock (&nodecache_lock); +- if (c->np != NULL) +- { +- /* We lost a race. */ +- diskfs_nput (np); +- np = c->np; +- goto gotit; +- } +- c->np = np; +- diskfs_nref_light (np); +- pthread_rwlock_unlock (&nodecache_lock); +- +- dn->rr = rr; +- err = read_disknode (np); +- if (!err) +- *npp = np; +- +- release_rrip (&rr); +- ++ diskfs_nrele (np); + return err; + } + +- gotit: +- diskfs_nref (np); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&np->lock); + *npp = np; + return 0; + } + +- + /* Return Epoch-based time from a seven byte according to 9.1.5 */ + char * + isodate_915 (char *c, struct timespec *ts) +@@ -303,6 +143,9 @@ calculate_file_start (struct dirrect *record, off_t *file_start, + *file_start = rr->realfilestart; + else + { ++ if (record == NULL) ++ return ENOENT; ++ + err = diskfs_catch_exception (); + if (err) + return err; +@@ -335,75 +178,15 @@ cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp) + return 0; + } + +-/* Load the inode with directory entry RECORD and cached Rock-Ridge +- info RR into NP. The directory entry is at OFFSET in BLOCK. */ +-error_t +-load_inode (ino_t id, struct node **npp, struct dirrect *record, +- struct rrip_lookup *rr) +-{ +- error_t err; +- struct disknode *dn; +- struct node *np, *tmp; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- inode_cache_find ((off_t) id, npp); +- pthread_rwlock_unlock (&nodecache_lock); +- if (*npp) +- return 0; +- +- /* Create a new node */ +- dn = malloc (sizeof (struct disknode)); +- if (!dn) +- return ENOMEM; +- +- err = calculate_file_start (record, &dn->file_start, rr); +- if (err) +- { +- free (dn); +- return err; +- } +- dn->fileinfo = 0; +- dn->dr = record; +- +- np = diskfs_make_node (dn); +- if (!np) +- { +- free (dn); +- return ENOMEM; +- } +- +- pthread_mutex_lock (&np->lock); +- +- pthread_rwlock_wrlock (&nodecache_lock); +- tmp = lookup (id); +- if (tmp) +- { +- /* We lost a race. */ +- diskfs_nput (np); +- diskfs_nref (tmp); +- *npp = tmp; +- pthread_rwlock_unlock (&nodecache_lock); +- return 0; +- } +- +- cache_inode (id, np); +- pthread_rwlock_unlock (&nodecache_lock); +- +- err = read_disknode (np); +- *npp = np; +- return err; +-} +- +- + /* Read stat information from the directory entry at DR and the + contents of RL. */ +-static error_t +-read_disknode (struct node *np) ++error_t ++diskfs_user_read_node (struct node *np, struct lookup_context *ctx) + { + error_t err; + struct stat *st = &np->dn_stat; +- struct dirrect *dr = np->dn->dr; +- struct rrip_lookup *rl = &np->dn->rr; ++ struct dirrect *dr = ctx->dr; ++ struct rrip_lookup *rl = &ctx->rr; + st->st_fstype = FSTYPE_ISO9660; + st->st_fsid = getpid (); + st->st_ino = np->cache_id; +@@ -543,39 +326,14 @@ diskfs_node_norefs (struct node *np) + free (np->dn->translator); + + assert (!np->dn->fileinfo); +- free (np->dn); + free (np); + } + + /* The last hard reference to a node has gone away; arrange to have + all the weak references dropped that can be. */ + void +-diskfs_try_dropping_softrefs (struct node *np) ++diskfs_user_try_dropping_softrefs (struct node *np) + { +- pthread_rwlock_wrlock (&nodecache_lock); +- if (np->cache_id != 0) +- { +- assert (node_cache[np->cache_id - 1].np == np); +- +- /* Check if someone reacquired a reference through the +- node_cache. */ +- struct references result; +- refcounts_references (&np->refcounts, &result); +- +- if (result.hard > 0) +- { +- /* A reference was reacquired through a hash table lookup. +- It's fine, we didn't touch anything yet. */ +- pthread_rwlock_unlock (&nodecache_lock); +- return; +- } +- +- node_cache[np->cache_id - 1].np = 0; +- np->cache_id = 0; +- diskfs_nrele_light (np); +- } +- pthread_rwlock_unlock (&nodecache_lock); +- + drop_pager_softrefs (np); + } + +@@ -636,14 +394,6 @@ diskfs_validate_author_change (struct node *np, uid_t author) + return EROFS; + } + +-error_t +-diskfs_node_iterate (error_t (*fun)(struct node *)) +-{ +- /* We never actually have to do anything, because this function +- is only used for things that have to do with read-write media. */ +- return 0; +-} +- + void + diskfs_write_disknode (struct node *np, int wait) + { +diff --git a/isofs/isofs.h b/isofs/isofs.h +index 9aa9608..7362220 100644 +--- a/isofs/isofs.h ++++ b/isofs/isofs.h +@@ -34,7 +34,6 @@ + struct disknode + { + struct dirrect *dr; /* Somewhere in disk_image. */ +- struct rrip_lookup rr; + + off_t file_start; /* In store->block_size units */ + +@@ -57,6 +56,12 @@ struct user_pager_info + struct pager *p; + }; + ++struct lookup_context ++{ ++ struct dirrect *dr; ++ struct rrip_lookup rr; ++}; ++ + /* The physical media */ + extern struct store *store; + +@@ -91,7 +96,7 @@ void create_disk_pager (void); + /* Given RECORD and RR, calculate the cache id. */ + error_t cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp); + +-error_t load_inode (ino_t, struct node **, struct dirrect *, struct rrip_lookup *); ++error_t load_inode (struct node **, struct dirrect *, struct rrip_lookup *); + error_t calculate_file_start (struct dirrect *, off_t *, struct rrip_lookup *); + + char *isodate_915 (char *, struct timespec *); +diff --git a/isofs/lookup.c b/isofs/lookup.c +index f0bd73b..f375212 100644 +--- a/isofs/lookup.c ++++ b/isofs/lookup.c +@@ -70,12 +70,11 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + struct node **npp, struct dirstat *ds, struct protid *cred) + { + error_t err = 0; +- struct dirrect *record; ++ struct lookup_context ctx; + int namelen; + int spec_dotdot; + void *buf; + void *blockaddr; +- struct rrip_lookup rr; + ino_t id; + + if ((type == REMOVE) || (type == RENAME)) +@@ -100,7 +99,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + blockaddr < buf + dp->dn_stat.st_size; + blockaddr += logical_sector_size) + { +- err = dirscanblock (blockaddr, name, namelen, &record, &rr); ++ err = dirscanblock (blockaddr, name, namelen, &ctx.dr, &ctx.rr); + + if (!err) + break; +@@ -116,7 +115,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + if (err) + return err; + +- err = cache_id (record, &rr, &id); ++ err = cache_id (ctx.dr, &ctx.rr, &id); + if (err) + return err; + +@@ -130,7 +129,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + /* renames and removes can't get this far. */ + assert (type == LOOKUP); + diskfs_nput (dp); +- err = load_inode (id, npp, record, &rr); ++ err = diskfs_cached_lookup_context (id, npp, &ctx); + } + else + { +@@ -138,7 +137,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + we are permanently read-only, so things are necessarily + quiescent. Just be careful to honor the locking order. */ + pthread_mutex_unlock (&dp->lock); +- err = load_inode (id, npp, record, &rr); ++ err = diskfs_cached_lookup_context (id, npp, &ctx); + pthread_mutex_lock (&dp->lock); + } + } +@@ -148,14 +147,9 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + diskfs_nref (dp); + } + else +- err = load_inode (id, npp, record, &rr); +- +- (*npp)->dn->dr = record; +- if ((*npp)->dn->rr.valid) +- release_rrip (&rr); +- else +- (*npp)->dn->rr = rr; ++ err = diskfs_cached_lookup_context (id, npp, &ctx); + ++ release_rrip (&ctx.rr); + return err; + } + +diff --git a/isofs/main.c b/isofs/main.c +index fb111dd..95c90fe 100644 +--- a/isofs/main.c ++++ b/isofs/main.c +@@ -44,24 +44,23 @@ int diskfs_maxsymlinks = 8; + static void + fetch_root () + { +- struct rrip_lookup rl; +- struct dirrect *dr; ++ struct lookup_context ctx; + ino_t id; + error_t err; + +- dr = (struct dirrect *) sblock->root; ++ ctx.dr = (struct dirrect *) sblock->root; + + /* First check for SUSP and all relevant extensions */ +- rrip_initialize (dr); ++ rrip_initialize (ctx.dr); + + /* Now rescan the node for real */ +- rrip_lookup (dr, &rl, 1); ++ rrip_lookup (ctx.dr, &ctx.rr, 1); + +- err = cache_id (dr, &rl, &id); ++ err = cache_id (ctx.dr, &ctx.rr, &id); + assert_perror (err); + + /* And fetch the node. */ +- err = load_inode (id, &diskfs_root_node, dr, &rl); ++ err = diskfs_cached_lookup_context (id, &diskfs_root_node, &ctx); + assert_perror (err); + + pthread_mutex_unlock (&diskfs_root_node->lock); +-- +2.1.4 + diff --git a/debian/patches/0016-xxx-fatfs.patch b/debian/patches/0016-xxx-fatfs.patch new file mode 100644 index 00000000..c8a25de3 --- /dev/null +++ b/debian/patches/0016-xxx-fatfs.patch @@ -0,0 +1,460 @@ +From b3f0189145afa4efe38335043213b89e72ff99f3 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Thu, 16 Apr 2015 16:12:05 +0200 +Subject: [PATCH hurd 16/16] xxx fatfs + +--- + fatfs/dir.c | 6 +- + fatfs/fatfs.h | 14 ++- + fatfs/inode.c | 284 +++++----------------------------------------------------- + 3 files changed, 37 insertions(+), 267 deletions(-) + +diff --git a/fatfs/dir.c b/fatfs/dir.c +index 5a38c63..9eea74c 100644 +--- a/fatfs/dir.c ++++ b/fatfs/dir.c +@@ -342,7 +342,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + + /* Here below are the spec dotdot cases. */ + else if (type == RENAME || type == REMOVE) +- np = ifind (inum); ++ np = diskfs_cached_ifind (inum); + + else if (type == LOOKUP) + { +@@ -395,7 +395,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + diskfs_nput (np); + } + else if (type == RENAME || type == REMOVE) +- /* We just did ifind to get np; that allocates ++ /* We just did diskfs_cached_ifind to get np; that allocates + no new references, so we don't have anything to do. */ + ; + else if (type == LOOKUP) +@@ -732,7 +732,7 @@ diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds) + assert (err != EINVAL); + + /* Lookup the node, we already have a reference. */ +- oldnp = ifind (inode); ++ oldnp = diskfs_cached_ifind (inode); + + assert (ds->type == RENAME); + assert (ds->stat == HERE_TIS); +diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h +index 9d38546..be4ad42 100644 +--- a/fatfs/fatfs.h ++++ b/fatfs/fatfs.h +@@ -71,6 +71,18 @@ struct disknode + int dir_idx; + }; + ++struct lookup_context ++{ ++ /* The inode as returned by virtual inode management routines. */ ++ inode_t inode; ++ ++ /* xxx */ ++ vm_address_t buf; ++ ++ /* xxx */ ++ struct node *dir; ++}; ++ + struct user_pager_info + { + struct node *node; +@@ -117,8 +129,6 @@ void flush_node_pager (struct node *node); + + void write_all_disknodes (); + +-struct node *ifind (ino_t inum); +- + error_t fat_get_next_cluster (cluster_t cluster, cluster_t *next_cluster); + void fat_to_unix_filename (const char *, char *); + +diff --git a/fatfs/inode.c b/fatfs/inode.c +index f228618..8b41238 100644 +--- a/fatfs/inode.c ++++ b/fatfs/inode.c +@@ -37,69 +37,20 @@ + #define UF_IMMUTABLE 0 + #endif + +-#define INOHSZ 512 +-#if ((INOHSZ&(INOHSZ-1)) == 0) +-#define INOHASH(ino) ((ino)&(INOHSZ-1)) +-#else +-#define INOHASH(ino) (((unsigned)(ino))%INOHSZ) +-#endif +- +-/* The nodehash is a cache of nodes. +- +- Access to nodehash and nodehash_nr_items is protected by +- nodecache_lock. +- +- Every node in the nodehash carries a light reference. When we are +- asked to give up that light reference, we reacquire our lock +- momentarily to check whether someone else reacquired a reference +- through the nodehash. */ +-static struct node *nodehash[INOHSZ]; +-static size_t nodehash_nr_items; +-static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; +- +-static error_t read_node (struct node *np, vm_address_t buf); +- +-/* Initialize the inode hash table. */ +-void +-inode_init () +-{ +- int n; +- for (n = 0; n < INOHSZ; n++) +- nodehash[n] = 0; +-} +- +-/* Lookup node with inode number INUM. Returns NULL if the node is +- not found in the node cache. */ +-static struct node * +-lookup (ino_t inum) +-{ +- struct node *np; +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- if (np->cache_id == inum) +- return np; +- return NULL; +-} +- +-/* Fetch inode INUM, set *NPP to the node structure; gain one user +- reference and lock the node. */ ++/* XXX */ + error_t +-diskfs_cached_lookup (ino64_t inum, struct node **npp) ++diskfs_user_make_node (struct node **npp, struct lookup_context *ctx) + { +- error_t err; +- struct node *np, *tmp; ++ struct node *np; + struct disknode *dn; + +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- if (np) +- goto gotit; +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Format specific data for the new node. */ +- dn = malloc (sizeof (struct disknode)); +- if (! dn) ++ /* Create the new node. */ ++ np = diskfs_make_node_alloc (sizeof *dn); ++ if (np == NULL) + return ENOMEM; + ++ /* Format specific data for the new node. */ ++ dn = diskfs_node_disknode (np); + dn->pager = 0; + dn->first = 0; + dn->last = 0; +@@ -108,50 +59,9 @@ diskfs_cached_lookup (ino64_t inum, struct node **npp) + dn->chain_extension_lock = PTHREAD_SPINLOCK_INITIALIZER; + pthread_rwlock_init (&dn->alloc_lock, NULL); + pthread_rwlock_init (&dn->dirent_lock, NULL); +- +- /* Create the new node. */ +- np = diskfs_make_node (dn); +- np->cache_id = inum; +- np->dn->inode = vi_lookup(inum); + +- pthread_mutex_lock (&np->lock); +- +- /* Put NP in NODEHASH. */ +- pthread_rwlock_wrlock (&nodecache_lock); +- tmp = lookup (inum); +- if (tmp) +- { +- /* We lost a race. */ +- diskfs_nput (np); +- np = tmp; +- goto gotit; +- } +- +- dn->hnext = nodehash[INOHASH(inum)]; +- if (dn->hnext) +- dn->hnext->dn->hprevp = &dn->hnext; +- dn->hprevp = &nodehash[INOHASH(inum)]; +- nodehash[INOHASH(inum)] = np; +- diskfs_nref_light (np); +- nodehash_nr_items += 1; +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Get the contents of NP off disk. */ +- err = read_node (np, 0); +- +- if (err) +- return err; +- else +- { +- *npp = np; +- return 0; +- } +- +- gotit: +- diskfs_nref (np); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&np->lock); +- *npp = np; ++ np->dn->inode = ctx->inode; ++ np->dn->dirnode = ctx->dir; + return 0; + } + +@@ -162,78 +72,8 @@ error_t + diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf) + { + error_t err; +- struct node *np; +- struct disknode *dn; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext) +- if (np->cache_id == inum) +- { +- diskfs_nref (np); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&np->lock); +- *npp = np; +- return 0; +- } +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Format specific data for the new node. */ +- dn = malloc (sizeof (struct disknode)); +- if (! dn) +- return ENOMEM; +- +- dn->pager = 0; +- dn->first = 0; +- dn->last = 0; +- dn->length_of_chain = 0; +- dn->chain_complete = 0; +- dn->chain_extension_lock = PTHREAD_SPINLOCK_INITIALIZER; +- pthread_rwlock_init (&dn->alloc_lock, NULL); +- pthread_rwlock_init (&dn->dirent_lock, NULL); +- +- /* Create the new node. */ +- np = diskfs_make_node (dn); +- np->cache_id = inum; +- np->dn->inode = vi_lookup(inum); +- +- pthread_mutex_lock (&np->lock); +- +- /* Put NP in NODEHASH. */ +- pthread_rwlock_wrlock (&nodecache_lock); +- dn->hnext = nodehash[INOHASH(inum)]; +- if (dn->hnext) +- dn->hnext->dn->hprevp = &dn->hnext; +- dn->hprevp = &nodehash[INOHASH(inum)]; +- nodehash[INOHASH(inum)] = np; +- diskfs_nref_light (np); +- nodehash_nr_items += 1; +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Get the contents of NP off disk. */ +- err = read_node (np, buf); +- +- if (err) +- return err; +- else +- { +- *npp = np; +- return 0; +- } +-} +- +-/* Lookup node INUM (which must have a reference already) and return +- it without allocating any new references. */ +-struct node * +-ifind (ino_t inum) +-{ +- struct node *np; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- pthread_rwlock_unlock (&nodecache_lock); +- +- assert (np); +- return np; ++ struct lookup_context ctx = { buf: buf }; ++ return diskfs_cached_lookup_context (inum, npp, &ctx); + } + + /* The last reference to a node has gone away; drop it from the hash +@@ -258,41 +98,14 @@ diskfs_node_norefs (struct node *np) + + assert (!np->dn->pager); + +- free (np->dn); + free (np); + } + + /* The last hard reference to a node has gone away; arrange to have + all the weak references dropped that can be. */ + void +-diskfs_try_dropping_softrefs (struct node *np) ++diskfs_user_try_dropping_softrefs (struct node *np) + { +- pthread_rwlock_wrlock (&nodecache_lock); +- if (np->dn->hprevp != NULL) +- { +- /* Check if someone reacquired a reference through the +- nodehash. */ +- struct references result; +- refcounts_references (&np->refcounts, &result); +- +- if (result.hard > 0) +- { +- /* A reference was reacquired through a hash table lookup. +- It's fine, we didn't touch anything yet. */ +- pthread_rwlock_unlock (&nodecache_lock); +- return; +- } +- +- *np->dn->hprevp = np->dn->hnext; +- if (np->dn->hnext) +- np->dn->hnext->dn->hprevp = np->dn->hprevp; +- np->dn->hnext = NULL; +- np->dn->hprevp = NULL; +- nodehash_nr_items -= 1; +- diskfs_nrele_light (np); +- } +- pthread_rwlock_unlock (&nodecache_lock); +- + drop_pager_softrefs (np); + } + +@@ -311,8 +124,8 @@ diskfs_new_hardrefs (struct node *np) + } + + /* Read stat information out of the directory entry. */ +-static error_t +-read_node (struct node *np, vm_address_t buf) ++error_t ++diskfs_user_read_node (struct node *np, struct lookup_context *ctx) + { + /* XXX This needs careful investigation. */ + error_t err; +@@ -323,6 +136,7 @@ read_node (struct node *np, vm_address_t buf) + struct vi_key vk = vi_key(np->dn->inode); + vm_prot_t prot = VM_PROT_READ; + memory_object_t memobj; ++ vm_address_t buf = ctx->buf; + vm_size_t buflen = 0; + int our_buf = 0; + +@@ -359,7 +173,7 @@ read_node (struct node *np, vm_address_t buf) + /* FIXME: We know intimately that the parent dir is locked + by libdiskfs. The only case it is not locked is for NFS + (fsys_getfile) and we disabled that. */ +- dp = ifind (vk.dir_inode); ++ dp = diskfs_cached_ifind (vk.dir_inode); + assert (dp); + + /* Map in the directory contents. */ +@@ -572,7 +386,7 @@ error_t + diskfs_node_reload (struct node *node) + { + struct cluster_chain *last = node->dn->first; +- ++ static struct lookup_context ctx = { buf: 0 }; + while (last) + { + struct cluster_chain *next = last->next; +@@ -580,61 +394,8 @@ diskfs_node_reload (struct node *node) + last = next; + } + flush_node_pager (node); +- read_node (node, 0); + +- return 0; +-} +- +-/* For each active node, call FUN. The node is to be locked around the call +- to FUN. If FUN returns non-zero for any node, then immediately stop, and +- return that value. */ +-error_t +-diskfs_node_iterate (error_t (*fun)(struct node *)) +-{ +- error_t err = 0; +- int n; +- size_t num_nodes; +- struct node *node, **node_list, **p; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- +- /* We must copy everything from the hash table into another data structure +- to avoid running into any problems with the hash-table being modified +- during processing (normally we delegate access to hash-table with +- nodecache_lock, but we can't hold this while locking the +- individual node locks). */ +- +- num_nodes = nodehash_nr_items; +- +- node_list = alloca (num_nodes * sizeof (struct node *)); +- p = node_list; +- for (n = 0; n < INOHSZ; n++) +- for (node = nodehash[n]; node; node = node->dn->hnext) +- { +- *p++ = node; +- +- /* We acquire a hard reference for node, but without using +- diskfs_nref. We do this so that diskfs_new_hardrefs will not +- get called. */ +- refcounts_ref (&node->refcounts, NULL); +- } +- +- pthread_rwlock_unlock (&nodecache_lock); +- +- p = node_list; +- while (num_nodes-- > 0) +- { +- node = *p++; +- if (!err) +- { +- pthread_mutex_lock (&node->lock); +- err = (*fun)(node); +- pthread_mutex_unlock (&node->lock); +- } +- diskfs_nrele (node); +- } +- +- return err; ++ return diskfs_user_read_node (node, &ctx); + } + + /* Write all active disknodes into the ext2_inode pager. */ +@@ -812,7 +573,8 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) + ino_t inum; + inode_t inode; + struct node *np; +- ++ struct lookup_context ctx = { dir: dir }; ++ + assert (!diskfs_readonly); + + /* FIXME: We use a magic key here that signals read_node that we are +@@ -821,12 +583,10 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) + if (err) + return err; + +- err = diskfs_cached_lookup (inum, &np); ++ err = diskfs_cached_lookup_context (inum, &np, &ctx); + if (err) + return err; + +- /* FIXME: We know that readnode couldn't put this in. */ +- np->dn->dirnode = dir; + refcounts_ref (&dir->refcounts, NULL); + + *node = np; +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 79656c5d..0256c9e8 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -45,3 +45,19 @@ merge-me-0002-startup-faster-reboots.patch thomas_term.patch ajoin.patch proc_disable_new_task_notifications.patch +0001-ext2fs-use-a-seperate-lock-to-protect-nodehash.patch +0002-fatfs-use-a-seperate-lock-to-protect-nodehash.patch +0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch +0004-tmpfs-use-a-seperate-lock-to-protect-all_nodes.patch +0005-libdiskfs-lock-less-reference-counting-of-nodes.patch +0006-libdiskfs-make-struct-node-more-compact.patch +0007-libdiskfs-drop-unused-fields-from-struct-node.patch +0008-libdiskfs-initialize-flag.patch +0009-xxx-ext2fs-fat-nodes.patch +0010-libdiskfs-implement-a-node-cache.patch +0011-fixup_isofs.patch +0012-fixup_ext2fs.patch +0013-xxx-half-assed-try-to-port-isofs-to-the-node-cache.patch +0014-libdiskfs-xxx-lookup-context.patch +0015-fixup_isofs.patch +0016-xxx-fatfs.patch |