From 350d08ed953cfe2c3592cf9822725a2976937ac1 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Fri, 20 Nov 2015 12:45:28 +0100 Subject: [PATCH hurd] xxx fix node iteration --- libdiskfs/diskfs.h | 8 +++---- libdiskfs/node-cache.c | 63 ++++++++++++++++---------------------------------- 2 files changed, 24 insertions(+), 47 deletions(-) diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h index 106aeb0..51bb79f 100644 --- a/libdiskfs/diskfs.h +++ b/libdiskfs/diskfs.h @@ -521,10 +521,10 @@ void diskfs_write_disknode (struct node *np, int wait); void diskfs_file_update (struct node *np, int wait); /* The user must define this function unless she wants to use the node - cache. See the section `Node cache' below. 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. */ + cache. See the section `Node cache' below. For each active node, + call FUN. The node is to be locked around the call to FUN. FUN + must be idempotent. 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 *)); /* The user must define this function. Sync all the pagers and any diff --git a/libdiskfs/node-cache.c b/libdiskfs/node-cache.c index ee7e6fd..4016779 100644 --- a/libdiskfs/node-cache.c +++ b/libdiskfs/node-cache.c @@ -170,61 +170,38 @@ diskfs_try_dropping_softrefs (struct node *np) 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. */ +/* For each active node, call FUN. FUN must be idempotent. 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; - size_t num_nodes; - struct node *node, **node_list, **p; + struct node *node; + /* XXX */ + restart: 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 = nodecache.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); - return ENOMEM; - } - - p = node_list; HURD_IHASH_ITERATE (&nodecache, i) { - *p++ = node = i; - - /* 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); + node = i; + + if (pthread_mutex_trylock (&node->lock)) + { + /* Failed to acquire the lock. Release the cache lock and + restart iteration. */ + pthread_rwlock_unlock (&nodecache_lock); + goto restart; + } + err = (*fun)(node); + pthread_mutex_unlock (&node->lock); + if (err) + break; } - 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); - } + pthread_rwlock_unlock (&nodecache_lock); - free (node_list); return err; } -- 2.1.4