1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
From 00bd1a54e878c29ad56c539484c57bf9cf9f5b51 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 2/2] 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 f187a73..984ae4c 100644
--- a/libdiskfs/node-cache.c
+++ b/libdiskfs/node-cache.c
@@ -176,61 +176,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
|