aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fscache/stats.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-11-19 13:11:25 -0500
committerDavid Howells <dhowells@redhat.com>2009-11-19 13:11:25 -0500
commit1bccf513ac49d44604ba1cddcc29f5886e70f1b6 (patch)
tree096ba75a3d02018c5f6e1857aaf1d41471733850 /fs/fscache/stats.c
parent6897e3df8fc37bd4a58bbcdef8306da7fc175584 (diff)
FS-Cache: Fix lock misorder in fscache_write_op()
FS-Cache has two structs internally for keeping track of the internal state of a cached file: the fscache_cookie struct, which represents the netfs's state, and fscache_object struct, which represents the cache's state. Each has a pointer that points to the other (when both are in existence), and each has a spinlock for pointer maintenance. Since netfs operations approach these structures from the cookie side, they get the cookie lock first, then the object lock. Cache operations, on the other hand, approach from the object side, and get the object lock first. It is not then permitted for a cache operation to get the cookie lock whilst it is holding the object lock lest deadlock occur; instead, it must do one of two things: (1) increment the cookie usage counter, drop the object lock and then get both locks in order, or (2) simply hold the object lock as certain parts of the cookie may not be altered whilst the object lock is held. It is also not permitted to follow either pointer without holding the lock at the end you start with. To break the pointers between the cookie and the object, both locks must be held. fscache_write_op(), however, violates the locking rules: It attempts to get the cookie lock without (a) checking that the cookie pointer is a valid pointer, and (b) holding the object lock to protect the cookie pointer whilst it follows it. This is so that it can access the pending page store tree without interference from __fscache_write_page(). This is fixed by splitting the cookie lock, such that the page store tracking tree is protected by its own lock, and checking that the cookie pointer is non-NULL before we attempt to follow it whilst holding the object lock. The new lock is subordinate to both the cookie lock and the object lock, and so should be taken after those. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/fscache/stats.c')
-rw-r--r--fs/fscache/stats.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c
index 4c07439d1307..1d53ea68409e 100644
--- a/fs/fscache/stats.c
+++ b/fs/fscache/stats.c
@@ -58,6 +58,9 @@ atomic_t fscache_n_stores_nobufs;
58atomic_t fscache_n_stores_oom; 58atomic_t fscache_n_stores_oom;
59atomic_t fscache_n_store_ops; 59atomic_t fscache_n_store_ops;
60atomic_t fscache_n_store_calls; 60atomic_t fscache_n_store_calls;
61atomic_t fscache_n_store_pages;
62atomic_t fscache_n_store_radix_deletes;
63atomic_t fscache_n_store_pages_over_limit;
61 64
62atomic_t fscache_n_marks; 65atomic_t fscache_n_marks;
63atomic_t fscache_n_uncaches; 66atomic_t fscache_n_uncaches;
@@ -200,9 +203,12 @@ static int fscache_stats_show(struct seq_file *m, void *v)
200 atomic_read(&fscache_n_stores_again), 203 atomic_read(&fscache_n_stores_again),
201 atomic_read(&fscache_n_stores_nobufs), 204 atomic_read(&fscache_n_stores_nobufs),
202 atomic_read(&fscache_n_stores_oom)); 205 atomic_read(&fscache_n_stores_oom));
203 seq_printf(m, "Stores : ops=%u run=%u\n", 206 seq_printf(m, "Stores : ops=%u run=%u pgs=%u rxd=%u olm=%u\n",
204 atomic_read(&fscache_n_store_ops), 207 atomic_read(&fscache_n_store_ops),
205 atomic_read(&fscache_n_store_calls)); 208 atomic_read(&fscache_n_store_calls),
209 atomic_read(&fscache_n_store_pages),
210 atomic_read(&fscache_n_store_radix_deletes),
211 atomic_read(&fscache_n_store_pages_over_limit));
206 212
207 seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u\n", 213 seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u\n",
208 atomic_read(&fscache_n_op_pend), 214 atomic_read(&fscache_n_op_pend),