aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-11-19 13:11:19 -0500
committerDavid Howells <dhowells@redhat.com>2009-11-19 13:11:19 -0500
commit5753c441889253e4323eee85f791a1d64cf08196 (patch)
tree55a0de053d0593d96e99710f978277df668412d1
parentb34df792b4e9e311db47fad27949095d0629c197 (diff)
FS-Cache: Permit cache retrieval ops to be interrupted in the initial wait phase
Permit the operations to retrieve data from the cache or to allocate space in the cache for future writes to be interrupted whilst they're waiting for permission for the operation to proceed. Typically this wait occurs whilst the cache object is being looked up on disk in the background. If an interruption occurs, and the operation has not yet been given the go-ahead to run, the operation is dequeued and cancelled, and control returns to the read operation of the netfs routine with none of the requested pages having been read or in any way marked as known by the cache. This means that the initial wait is done interruptibly rather than uninterruptibly. In addition, extra stats values are made available to show the number of ops cancelled and the number of cache space allocations interrupted. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--Documentation/filesystems/caching/fscache.txt2
-rw-r--r--fs/fscache/internal.h3
-rw-r--r--fs/fscache/operation.c82
-rw-r--r--fs/fscache/page.c55
-rw-r--r--fs/fscache/stats.c12
5 files changed, 115 insertions, 39 deletions
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt
index b6c32c080ab1..0a77868f4977 100644
--- a/Documentation/filesystems/caching/fscache.txt
+++ b/Documentation/filesystems/caching/fscache.txt
@@ -250,6 +250,7 @@ proc files.
250 ok=N Number of successful alloc reqs 250 ok=N Number of successful alloc reqs
251 wt=N Number of alloc reqs that waited on lookup completion 251 wt=N Number of alloc reqs that waited on lookup completion
252 nbf=N Number of alloc reqs rejected -ENOBUFS 252 nbf=N Number of alloc reqs rejected -ENOBUFS
253 int=N Number of alloc reqs aborted -ERESTARTSYS
253 ops=N Number of alloc reqs submitted 254 ops=N Number of alloc reqs submitted
254 owt=N Number of alloc reqs waited for CPU time 255 owt=N Number of alloc reqs waited for CPU time
255 Retrvls n=N Number of retrieval (read) requests seen 256 Retrvls n=N Number of retrieval (read) requests seen
@@ -271,6 +272,7 @@ proc files.
271 Ops pend=N Number of times async ops added to pending queues 272 Ops pend=N Number of times async ops added to pending queues
272 run=N Number of times async ops given CPU time 273 run=N Number of times async ops given CPU time
273 enq=N Number of times async ops queued for processing 274 enq=N Number of times async ops queued for processing
275 can=N Number of async ops cancelled
274 dfr=N Number of async ops queued for deferred release 276 dfr=N Number of async ops queued for deferred release
275 rel=N Number of async ops released 277 rel=N Number of async ops released
276 gc=N Number of deferred-release async ops garbage collected 278 gc=N Number of deferred-release async ops garbage collected
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index b85cc8906818..50324ad2b194 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -112,6 +112,7 @@ extern int fscache_submit_exclusive_op(struct fscache_object *,
112 struct fscache_operation *); 112 struct fscache_operation *);
113extern int fscache_submit_op(struct fscache_object *, 113extern int fscache_submit_op(struct fscache_object *,
114 struct fscache_operation *); 114 struct fscache_operation *);
115extern int fscache_cancel_op(struct fscache_operation *);
115extern void fscache_abort_object(struct fscache_object *); 116extern void fscache_abort_object(struct fscache_object *);
116extern void fscache_start_operations(struct fscache_object *); 117extern void fscache_start_operations(struct fscache_object *);
117extern void fscache_operation_gc(struct work_struct *); 118extern void fscache_operation_gc(struct work_struct *);
@@ -140,6 +141,7 @@ extern atomic_t fscache_n_op_enqueue;
140extern atomic_t fscache_n_op_deferred_release; 141extern atomic_t fscache_n_op_deferred_release;
141extern atomic_t fscache_n_op_release; 142extern atomic_t fscache_n_op_release;
142extern atomic_t fscache_n_op_gc; 143extern atomic_t fscache_n_op_gc;
144extern atomic_t fscache_n_op_cancelled;
143 145
144extern atomic_t fscache_n_attr_changed; 146extern atomic_t fscache_n_attr_changed;
145extern atomic_t fscache_n_attr_changed_ok; 147extern atomic_t fscache_n_attr_changed_ok;
@@ -151,6 +153,7 @@ extern atomic_t fscache_n_allocs;
151extern atomic_t fscache_n_allocs_ok; 153extern atomic_t fscache_n_allocs_ok;
152extern atomic_t fscache_n_allocs_wait; 154extern atomic_t fscache_n_allocs_wait;
153extern atomic_t fscache_n_allocs_nobufs; 155extern atomic_t fscache_n_allocs_nobufs;
156extern atomic_t fscache_n_allocs_intr;
154extern atomic_t fscache_n_alloc_ops; 157extern atomic_t fscache_n_alloc_ops;
155extern atomic_t fscache_n_alloc_op_waits; 158extern atomic_t fscache_n_alloc_op_waits;
156 159
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index 09e43b6e822f..296492efb81b 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -34,32 +34,31 @@ void fscache_enqueue_operation(struct fscache_operation *op)
34 34
35 fscache_set_op_state(op, "EnQ"); 35 fscache_set_op_state(op, "EnQ");
36 36
37 ASSERT(list_empty(&op->pend_link));
37 ASSERT(op->processor != NULL); 38 ASSERT(op->processor != NULL);
38 ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); 39 ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);
39 ASSERTCMP(atomic_read(&op->usage), >, 0); 40 ASSERTCMP(atomic_read(&op->usage), >, 0);
40 41
41 if (list_empty(&op->pend_link)) { 42 fscache_stat(&fscache_n_op_enqueue);
42 switch (op->flags & FSCACHE_OP_TYPE) { 43 switch (op->flags & FSCACHE_OP_TYPE) {
43 case FSCACHE_OP_FAST: 44 case FSCACHE_OP_FAST:
44 _debug("queue fast"); 45 _debug("queue fast");
45 atomic_inc(&op->usage); 46 atomic_inc(&op->usage);
46 if (!schedule_work(&op->fast_work)) 47 if (!schedule_work(&op->fast_work))
47 fscache_put_operation(op); 48 fscache_put_operation(op);
48 break; 49 break;
49 case FSCACHE_OP_SLOW: 50 case FSCACHE_OP_SLOW:
50 _debug("queue slow"); 51 _debug("queue slow");
51 slow_work_enqueue(&op->slow_work); 52 slow_work_enqueue(&op->slow_work);
52 break; 53 break;
53 case FSCACHE_OP_MYTHREAD: 54 case FSCACHE_OP_MYTHREAD:
54 _debug("queue for caller's attention"); 55 _debug("queue for caller's attention");
55 break; 56 break;
56 default: 57 default:
57 printk(KERN_ERR "FS-Cache: Unexpected op type %lx", 58 printk(KERN_ERR "FS-Cache: Unexpected op type %lx",
58 op->flags); 59 op->flags);
59 BUG(); 60 BUG();
60 break; 61 break;
61 }
62 fscache_stat(&fscache_n_op_enqueue);
63 } 62 }
64} 63}
65EXPORT_SYMBOL(fscache_enqueue_operation); 64EXPORT_SYMBOL(fscache_enqueue_operation);
@@ -97,6 +96,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
97 spin_lock(&object->lock); 96 spin_lock(&object->lock);
98 ASSERTCMP(object->n_ops, >=, object->n_in_progress); 97 ASSERTCMP(object->n_ops, >=, object->n_in_progress);
99 ASSERTCMP(object->n_ops, >=, object->n_exclusive); 98 ASSERTCMP(object->n_ops, >=, object->n_exclusive);
99 ASSERT(list_empty(&op->pend_link));
100 100
101 ret = -ENOBUFS; 101 ret = -ENOBUFS;
102 if (fscache_object_is_active(object)) { 102 if (fscache_object_is_active(object)) {
@@ -202,6 +202,7 @@ int fscache_submit_op(struct fscache_object *object,
202 spin_lock(&object->lock); 202 spin_lock(&object->lock);
203 ASSERTCMP(object->n_ops, >=, object->n_in_progress); 203 ASSERTCMP(object->n_ops, >=, object->n_in_progress);
204 ASSERTCMP(object->n_ops, >=, object->n_exclusive); 204 ASSERTCMP(object->n_ops, >=, object->n_exclusive);
205 ASSERT(list_empty(&op->pend_link));
205 206
206 ostate = object->state; 207 ostate = object->state;
207 smp_rmb(); 208 smp_rmb();
@@ -273,12 +274,7 @@ void fscache_start_operations(struct fscache_object *object)
273 stop = true; 274 stop = true;
274 } 275 }
275 list_del_init(&op->pend_link); 276 list_del_init(&op->pend_link);
276 object->n_in_progress++; 277 fscache_run_op(object, op);
277
278 if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
279 wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
280 if (op->processor)
281 fscache_enqueue_operation(op);
282 278
283 /* the pending queue was holding a ref on the object */ 279 /* the pending queue was holding a ref on the object */
284 fscache_put_operation(op); 280 fscache_put_operation(op);
@@ -291,6 +287,36 @@ void fscache_start_operations(struct fscache_object *object)
291} 287}
292 288
293/* 289/*
290 * cancel an operation that's pending on an object
291 */
292int fscache_cancel_op(struct fscache_operation *op)
293{
294 struct fscache_object *object = op->object;
295 int ret;
296
297 _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id);
298
299 spin_lock(&object->lock);
300
301 ret = -EBUSY;
302 if (!list_empty(&op->pend_link)) {
303 fscache_stat(&fscache_n_op_cancelled);
304 list_del_init(&op->pend_link);
305 object->n_ops--;
306 if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
307 object->n_exclusive--;
308 if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
309 wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
310 fscache_put_operation(op);
311 ret = 0;
312 }
313
314 spin_unlock(&object->lock);
315 _leave(" = %d", ret);
316 return ret;
317}
318
319/*
294 * release an operation 320 * release an operation
295 * - queues pending ops if this is the last in-progress op 321 * - queues pending ops if this is the last in-progress op
296 */ 322 */
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 250dfd34c07b..e6f2e61133a1 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -295,8 +295,20 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
295 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { 295 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
296 _debug(">>> WT"); 296 _debug(">>> WT");
297 fscache_stat(&fscache_n_retrieval_op_waits); 297 fscache_stat(&fscache_n_retrieval_op_waits);
298 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, 298 if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
299 fscache_wait_bit, TASK_UNINTERRUPTIBLE); 299 fscache_wait_bit_interruptible,
300 TASK_INTERRUPTIBLE) < 0) {
301 ret = fscache_cancel_op(&op->op);
302 if (ret == 0) {
303 ret = -ERESTARTSYS;
304 goto error;
305 }
306
307 /* it's been removed from the pending queue by another
308 * party, so we should get to run shortly */
309 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
310 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
311 }
300 _debug("<<< GO"); 312 _debug("<<< GO");
301 } 313 }
302 314
@@ -313,6 +325,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
313 fscache_stat_d(&fscache_n_cop_read_or_alloc_page); 325 fscache_stat_d(&fscache_n_cop_read_or_alloc_page);
314 } 326 }
315 327
328error:
316 if (ret == -ENOMEM) 329 if (ret == -ENOMEM)
317 fscache_stat(&fscache_n_retrievals_nomem); 330 fscache_stat(&fscache_n_retrievals_nomem);
318 else if (ret == -ERESTARTSYS) 331 else if (ret == -ERESTARTSYS)
@@ -412,8 +425,20 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
412 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { 425 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
413 _debug(">>> WT"); 426 _debug(">>> WT");
414 fscache_stat(&fscache_n_retrieval_op_waits); 427 fscache_stat(&fscache_n_retrieval_op_waits);
415 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, 428 if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
416 fscache_wait_bit, TASK_UNINTERRUPTIBLE); 429 fscache_wait_bit_interruptible,
430 TASK_INTERRUPTIBLE) < 0) {
431 ret = fscache_cancel_op(&op->op);
432 if (ret == 0) {
433 ret = -ERESTARTSYS;
434 goto error;
435 }
436
437 /* it's been removed from the pending queue by another
438 * party, so we should get to run shortly */
439 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
440 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
441 }
417 _debug("<<< GO"); 442 _debug("<<< GO");
418 } 443 }
419 444
@@ -430,6 +455,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
430 fscache_stat_d(&fscache_n_cop_read_or_alloc_pages); 455 fscache_stat_d(&fscache_n_cop_read_or_alloc_pages);
431 } 456 }
432 457
458error:
433 if (ret == -ENOMEM) 459 if (ret == -ENOMEM)
434 fscache_stat(&fscache_n_retrievals_nomem); 460 fscache_stat(&fscache_n_retrievals_nomem);
435 else if (ret == -ERESTARTSYS) 461 else if (ret == -ERESTARTSYS)
@@ -505,8 +531,20 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
505 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { 531 if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) {
506 _debug(">>> WT"); 532 _debug(">>> WT");
507 fscache_stat(&fscache_n_alloc_op_waits); 533 fscache_stat(&fscache_n_alloc_op_waits);
508 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, 534 if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
509 fscache_wait_bit, TASK_UNINTERRUPTIBLE); 535 fscache_wait_bit_interruptible,
536 TASK_INTERRUPTIBLE) < 0) {
537 ret = fscache_cancel_op(&op->op);
538 if (ret == 0) {
539 ret = -ERESTARTSYS;
540 goto error;
541 }
542
543 /* it's been removed from the pending queue by another
544 * party, so we should get to run shortly */
545 wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
546 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
547 }
510 _debug("<<< GO"); 548 _debug("<<< GO");
511 } 549 }
512 550
@@ -515,7 +553,10 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
515 ret = object->cache->ops->allocate_page(op, page, gfp); 553 ret = object->cache->ops->allocate_page(op, page, gfp);
516 fscache_stat_d(&fscache_n_cop_allocate_page); 554 fscache_stat_d(&fscache_n_cop_allocate_page);
517 555
518 if (ret < 0) 556error:
557 if (ret == -ERESTARTSYS)
558 fscache_stat(&fscache_n_allocs_intr);
559 else if (ret < 0)
519 fscache_stat(&fscache_n_allocs_nobufs); 560 fscache_stat(&fscache_n_allocs_nobufs);
520 else 561 else
521 fscache_stat(&fscache_n_allocs_ok); 562 fscache_stat(&fscache_n_allocs_ok);
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c
index 20233fb44bfd..4c07439d1307 100644
--- a/fs/fscache/stats.c
+++ b/fs/fscache/stats.c
@@ -25,6 +25,7 @@ atomic_t fscache_n_op_requeue;
25atomic_t fscache_n_op_deferred_release; 25atomic_t fscache_n_op_deferred_release;
26atomic_t fscache_n_op_release; 26atomic_t fscache_n_op_release;
27atomic_t fscache_n_op_gc; 27atomic_t fscache_n_op_gc;
28atomic_t fscache_n_op_cancelled;
28 29
29atomic_t fscache_n_attr_changed; 30atomic_t fscache_n_attr_changed;
30atomic_t fscache_n_attr_changed_ok; 31atomic_t fscache_n_attr_changed_ok;
@@ -36,6 +37,7 @@ atomic_t fscache_n_allocs;
36atomic_t fscache_n_allocs_ok; 37atomic_t fscache_n_allocs_ok;
37atomic_t fscache_n_allocs_wait; 38atomic_t fscache_n_allocs_wait;
38atomic_t fscache_n_allocs_nobufs; 39atomic_t fscache_n_allocs_nobufs;
40atomic_t fscache_n_allocs_intr;
39atomic_t fscache_n_alloc_ops; 41atomic_t fscache_n_alloc_ops;
40atomic_t fscache_n_alloc_op_waits; 42atomic_t fscache_n_alloc_op_waits;
41 43
@@ -169,11 +171,12 @@ static int fscache_stats_show(struct seq_file *m, void *v)
169 atomic_read(&fscache_n_attr_changed_nomem), 171 atomic_read(&fscache_n_attr_changed_nomem),
170 atomic_read(&fscache_n_attr_changed_calls)); 172 atomic_read(&fscache_n_attr_changed_calls));
171 173
172 seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u\n", 174 seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u int=%u\n",
173 atomic_read(&fscache_n_allocs), 175 atomic_read(&fscache_n_allocs),
174 atomic_read(&fscache_n_allocs_ok), 176 atomic_read(&fscache_n_allocs_ok),
175 atomic_read(&fscache_n_allocs_wait), 177 atomic_read(&fscache_n_allocs_wait),
176 atomic_read(&fscache_n_allocs_nobufs)); 178 atomic_read(&fscache_n_allocs_nobufs),
179 atomic_read(&fscache_n_allocs_intr));
177 seq_printf(m, "Allocs : ops=%u owt=%u\n", 180 seq_printf(m, "Allocs : ops=%u owt=%u\n",
178 atomic_read(&fscache_n_alloc_ops), 181 atomic_read(&fscache_n_alloc_ops),
179 atomic_read(&fscache_n_alloc_op_waits)); 182 atomic_read(&fscache_n_alloc_op_waits));
@@ -201,10 +204,11 @@ static int fscache_stats_show(struct seq_file *m, void *v)
201 atomic_read(&fscache_n_store_ops), 204 atomic_read(&fscache_n_store_ops),
202 atomic_read(&fscache_n_store_calls)); 205 atomic_read(&fscache_n_store_calls));
203 206
204 seq_printf(m, "Ops : pend=%u run=%u enq=%u\n", 207 seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u\n",
205 atomic_read(&fscache_n_op_pend), 208 atomic_read(&fscache_n_op_pend),
206 atomic_read(&fscache_n_op_run), 209 atomic_read(&fscache_n_op_run),
207 atomic_read(&fscache_n_op_enqueue)); 210 atomic_read(&fscache_n_op_enqueue),
211 atomic_read(&fscache_n_op_cancelled));
208 seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", 212 seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n",
209 atomic_read(&fscache_n_op_deferred_release), 213 atomic_read(&fscache_n_op_deferred_release),
210 atomic_read(&fscache_n_op_release), 214 atomic_read(&fscache_n_op_release),