diff options
-rw-r--r-- | Documentation/filesystems/caching/backend-api.txt | 26 | ||||
-rw-r--r-- | Documentation/filesystems/caching/operations.txt | 2 | ||||
-rw-r--r-- | fs/cachefiles/rdwr.c | 31 | ||||
-rw-r--r-- | fs/fscache/object.c | 2 | ||||
-rw-r--r-- | fs/fscache/operation.c | 91 | ||||
-rw-r--r-- | fs/fscache/page.c | 25 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 37 |
7 files changed, 164 insertions, 50 deletions
diff --git a/Documentation/filesystems/caching/backend-api.txt b/Documentation/filesystems/caching/backend-api.txt index 382d52cdaf2d..f4769b9399df 100644 --- a/Documentation/filesystems/caching/backend-api.txt +++ b/Documentation/filesystems/caching/backend-api.txt | |||
@@ -419,7 +419,10 @@ performed on the denizens of the cache. These are held in a structure of type: | |||
419 | 419 | ||
420 | If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS | 420 | If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS |
421 | returned if possible or fscache_end_io() called with a suitable error | 421 | returned if possible or fscache_end_io() called with a suitable error |
422 | code.. | 422 | code. |
423 | |||
424 | fscache_put_retrieval() should be called after a page or pages are dealt | ||
425 | with. This will complete the operation when all pages are dealt with. | ||
423 | 426 | ||
424 | 427 | ||
425 | (*) Request pages be read from cache [mandatory]: | 428 | (*) Request pages be read from cache [mandatory]: |
@@ -526,6 +529,27 @@ FS-Cache provides some utilities that a cache backend may make use of: | |||
526 | error value should be 0 if successful and an error otherwise. | 529 | error value should be 0 if successful and an error otherwise. |
527 | 530 | ||
528 | 531 | ||
532 | (*) Record that one or more pages being retrieved or allocated have been dealt | ||
533 | with: | ||
534 | |||
535 | void fscache_retrieval_complete(struct fscache_retrieval *op, | ||
536 | int n_pages); | ||
537 | |||
538 | This is called to record the fact that one or more pages have been dealt | ||
539 | with and are no longer the concern of this operation. When the number of | ||
540 | pages remaining in the operation reaches 0, the operation will be | ||
541 | completed. | ||
542 | |||
543 | |||
544 | (*) Record operation completion: | ||
545 | |||
546 | void fscache_op_complete(struct fscache_operation *op); | ||
547 | |||
548 | This is called to record the completion of an operation. This deducts | ||
549 | this operation from the parent object's run state, potentially permitting | ||
550 | one or more pending operations to start running. | ||
551 | |||
552 | |||
529 | (*) Set highest store limit: | 553 | (*) Set highest store limit: |
530 | 554 | ||
531 | void fscache_set_store_limit(struct fscache_object *object, | 555 | void fscache_set_store_limit(struct fscache_object *object, |
diff --git a/Documentation/filesystems/caching/operations.txt b/Documentation/filesystems/caching/operations.txt index b6b070c57cbf..bee2a5f93d60 100644 --- a/Documentation/filesystems/caching/operations.txt +++ b/Documentation/filesystems/caching/operations.txt | |||
@@ -174,7 +174,7 @@ Operations are used through the following procedure: | |||
174 | necessary (the object might have died whilst the thread was waiting). | 174 | necessary (the object might have died whilst the thread was waiting). |
175 | 175 | ||
176 | When it has finished doing its processing, it should call | 176 | When it has finished doing its processing, it should call |
177 | fscache_put_operation() on it. | 177 | fscache_op_complete() and fscache_put_operation() on it. |
178 | 178 | ||
179 | (4) The operation holds an effective lock upon the object, preventing other | 179 | (4) The operation holds an effective lock upon the object, preventing other |
180 | exclusive ops conflicting until it is released. The operation can be | 180 | exclusive ops conflicting until it is released. The operation can be |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index bf123d9c3206..93a0815e0498 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -197,6 +197,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
197 | 197 | ||
198 | fscache_end_io(op, monitor->netfs_page, error); | 198 | fscache_end_io(op, monitor->netfs_page, error); |
199 | page_cache_release(monitor->netfs_page); | 199 | page_cache_release(monitor->netfs_page); |
200 | fscache_retrieval_complete(op, 1); | ||
200 | fscache_put_retrieval(op); | 201 | fscache_put_retrieval(op); |
201 | kfree(monitor); | 202 | kfree(monitor); |
202 | 203 | ||
@@ -339,6 +340,7 @@ backing_page_already_uptodate: | |||
339 | 340 | ||
340 | copy_highpage(netpage, backpage); | 341 | copy_highpage(netpage, backpage); |
341 | fscache_end_io(op, netpage, 0); | 342 | fscache_end_io(op, netpage, 0); |
343 | fscache_retrieval_complete(op, 1); | ||
342 | 344 | ||
343 | success: | 345 | success: |
344 | _debug("success"); | 346 | _debug("success"); |
@@ -360,6 +362,7 @@ read_error: | |||
360 | goto out; | 362 | goto out; |
361 | io_error: | 363 | io_error: |
362 | cachefiles_io_error_obj(object, "Page read error on backing file"); | 364 | cachefiles_io_error_obj(object, "Page read error on backing file"); |
365 | fscache_retrieval_complete(op, 1); | ||
363 | ret = -ENOBUFS; | 366 | ret = -ENOBUFS; |
364 | goto out; | 367 | goto out; |
365 | 368 | ||
@@ -369,6 +372,7 @@ nomem_monitor: | |||
369 | fscache_put_retrieval(monitor->op); | 372 | fscache_put_retrieval(monitor->op); |
370 | kfree(monitor); | 373 | kfree(monitor); |
371 | nomem: | 374 | nomem: |
375 | fscache_retrieval_complete(op, 1); | ||
372 | _leave(" = -ENOMEM"); | 376 | _leave(" = -ENOMEM"); |
373 | return -ENOMEM; | 377 | return -ENOMEM; |
374 | } | 378 | } |
@@ -407,7 +411,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
407 | _enter("{%p},{%lx},,,", object, page->index); | 411 | _enter("{%p},{%lx},,,", object, page->index); |
408 | 412 | ||
409 | if (!object->backer) | 413 | if (!object->backer) |
410 | return -ENOBUFS; | 414 | goto enobufs; |
411 | 415 | ||
412 | inode = object->backer->d_inode; | 416 | inode = object->backer->d_inode; |
413 | ASSERT(S_ISREG(inode->i_mode)); | 417 | ASSERT(S_ISREG(inode->i_mode)); |
@@ -416,7 +420,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
416 | 420 | ||
417 | /* calculate the shift required to use bmap */ | 421 | /* calculate the shift required to use bmap */ |
418 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 422 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
419 | return -ENOBUFS; | 423 | goto enobufs; |
420 | 424 | ||
421 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 425 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
422 | 426 | ||
@@ -448,13 +452,19 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
448 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { | 452 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { |
449 | /* there's space in the cache we can use */ | 453 | /* there's space in the cache we can use */ |
450 | fscache_mark_page_cached(op, page); | 454 | fscache_mark_page_cached(op, page); |
455 | fscache_retrieval_complete(op, 1); | ||
451 | ret = -ENODATA; | 456 | ret = -ENODATA; |
452 | } else { | 457 | } else { |
453 | ret = -ENOBUFS; | 458 | goto enobufs; |
454 | } | 459 | } |
455 | 460 | ||
456 | _leave(" = %d", ret); | 461 | _leave(" = %d", ret); |
457 | return ret; | 462 | return ret; |
463 | |||
464 | enobufs: | ||
465 | fscache_retrieval_complete(op, 1); | ||
466 | _leave(" = -ENOBUFS"); | ||
467 | return -ENOBUFS; | ||
458 | } | 468 | } |
459 | 469 | ||
460 | /* | 470 | /* |
@@ -632,6 +642,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
632 | 642 | ||
633 | /* the netpage is unlocked and marked up to date here */ | 643 | /* the netpage is unlocked and marked up to date here */ |
634 | fscache_end_io(op, netpage, 0); | 644 | fscache_end_io(op, netpage, 0); |
645 | fscache_retrieval_complete(op, 1); | ||
635 | page_cache_release(netpage); | 646 | page_cache_release(netpage); |
636 | netpage = NULL; | 647 | netpage = NULL; |
637 | continue; | 648 | continue; |
@@ -659,6 +670,7 @@ out: | |||
659 | list_for_each_entry_safe(netpage, _n, list, lru) { | 670 | list_for_each_entry_safe(netpage, _n, list, lru) { |
660 | list_del(&netpage->lru); | 671 | list_del(&netpage->lru); |
661 | page_cache_release(netpage); | 672 | page_cache_release(netpage); |
673 | fscache_retrieval_complete(op, 1); | ||
662 | } | 674 | } |
663 | 675 | ||
664 | _leave(" = %d", ret); | 676 | _leave(" = %d", ret); |
@@ -707,7 +719,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
707 | *nr_pages); | 719 | *nr_pages); |
708 | 720 | ||
709 | if (!object->backer) | 721 | if (!object->backer) |
710 | return -ENOBUFS; | 722 | goto all_enobufs; |
711 | 723 | ||
712 | space = 1; | 724 | space = 1; |
713 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) | 725 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) |
@@ -720,7 +732,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
720 | 732 | ||
721 | /* calculate the shift required to use bmap */ | 733 | /* calculate the shift required to use bmap */ |
722 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 734 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
723 | return -ENOBUFS; | 735 | goto all_enobufs; |
724 | 736 | ||
725 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 737 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
726 | 738 | ||
@@ -760,7 +772,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
760 | nrbackpages++; | 772 | nrbackpages++; |
761 | } else if (space && pagevec_add(&pagevec, page) == 0) { | 773 | } else if (space && pagevec_add(&pagevec, page) == 0) { |
762 | fscache_mark_pages_cached(op, &pagevec); | 774 | fscache_mark_pages_cached(op, &pagevec); |
775 | fscache_retrieval_complete(op, 1); | ||
763 | ret = -ENODATA; | 776 | ret = -ENODATA; |
777 | } else { | ||
778 | fscache_retrieval_complete(op, 1); | ||
764 | } | 779 | } |
765 | } | 780 | } |
766 | 781 | ||
@@ -781,6 +796,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
781 | _leave(" = %d [nr=%u%s]", | 796 | _leave(" = %d [nr=%u%s]", |
782 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); | 797 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); |
783 | return ret; | 798 | return ret; |
799 | |||
800 | all_enobufs: | ||
801 | fscache_retrieval_complete(op, *nr_pages); | ||
802 | return -ENOBUFS; | ||
784 | } | 803 | } |
785 | 804 | ||
786 | /* | 805 | /* |
@@ -815,6 +834,7 @@ int cachefiles_allocate_page(struct fscache_retrieval *op, | |||
815 | else | 834 | else |
816 | ret = -ENOBUFS; | 835 | ret = -ENOBUFS; |
817 | 836 | ||
837 | fscache_retrieval_complete(op, 1); | ||
818 | _leave(" = %d", ret); | 838 | _leave(" = %d", ret); |
819 | return ret; | 839 | return ret; |
820 | } | 840 | } |
@@ -864,6 +884,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op, | |||
864 | ret = -ENOBUFS; | 884 | ret = -ENOBUFS; |
865 | } | 885 | } |
866 | 886 | ||
887 | fscache_retrieval_complete(op, *nr_pages); | ||
867 | _leave(" = %d", ret); | 888 | _leave(" = %d", ret); |
868 | return ret; | 889 | return ret; |
869 | } | 890 | } |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index b6b897c550ac..773bc798a416 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -587,8 +587,6 @@ static void fscache_object_available(struct fscache_object *object) | |||
587 | if (object->n_in_progress == 0) { | 587 | if (object->n_in_progress == 0) { |
588 | if (object->n_ops > 0) { | 588 | if (object->n_ops > 0) { |
589 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); | 589 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); |
590 | ASSERTIF(object->n_ops > object->n_obj_ops, | ||
591 | !list_empty(&object->pending_ops)); | ||
592 | fscache_start_operations(object); | 590 | fscache_start_operations(object); |
593 | } else { | 591 | } else { |
594 | ASSERT(list_empty(&object->pending_ops)); | 592 | ASSERT(list_empty(&object->pending_ops)); |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index c857ab824d6e..748f9553c2cb 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
37 | ASSERT(op->processor != NULL); | 37 | ASSERT(op->processor != NULL); |
38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
40 | 41 | ||
41 | fscache_stat(&fscache_n_op_enqueue); | 42 | fscache_stat(&fscache_n_op_enqueue); |
42 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
@@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
64 | static void fscache_run_op(struct fscache_object *object, | 65 | static void fscache_run_op(struct fscache_object *object, |
65 | struct fscache_operation *op) | 66 | struct fscache_operation *op) |
66 | { | 67 | { |
68 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
69 | |||
70 | op->state = FSCACHE_OP_ST_IN_PROGRESS; | ||
67 | object->n_in_progress++; | 71 | object->n_in_progress++; |
68 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 72 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
69 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 73 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
@@ -80,22 +84,23 @@ static void fscache_run_op(struct fscache_object *object, | |||
80 | int fscache_submit_exclusive_op(struct fscache_object *object, | 84 | int fscache_submit_exclusive_op(struct fscache_object *object, |
81 | struct fscache_operation *op) | 85 | struct fscache_operation *op) |
82 | { | 86 | { |
83 | int ret; | ||
84 | |||
85 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 87 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
86 | 88 | ||
89 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
90 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
91 | |||
87 | spin_lock(&object->lock); | 92 | spin_lock(&object->lock); |
88 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 93 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
89 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 94 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
90 | ASSERT(list_empty(&op->pend_link)); | 95 | ASSERT(list_empty(&op->pend_link)); |
91 | 96 | ||
92 | ret = -ENOBUFS; | 97 | op->state = FSCACHE_OP_ST_PENDING; |
93 | if (fscache_object_is_active(object)) { | 98 | if (fscache_object_is_active(object)) { |
94 | op->object = object; | 99 | op->object = object; |
95 | object->n_ops++; | 100 | object->n_ops++; |
96 | object->n_exclusive++; /* reads and writes must wait */ | 101 | object->n_exclusive++; /* reads and writes must wait */ |
97 | 102 | ||
98 | if (object->n_ops > 1) { | 103 | if (object->n_in_progress > 0) { |
99 | atomic_inc(&op->usage); | 104 | atomic_inc(&op->usage); |
100 | list_add_tail(&op->pend_link, &object->pending_ops); | 105 | list_add_tail(&op->pend_link, &object->pending_ops); |
101 | fscache_stat(&fscache_n_op_pend); | 106 | fscache_stat(&fscache_n_op_pend); |
@@ -111,7 +116,6 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
111 | 116 | ||
112 | /* need to issue a new write op after this */ | 117 | /* need to issue a new write op after this */ |
113 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 118 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
114 | ret = 0; | ||
115 | } else if (object->state == FSCACHE_OBJECT_CREATING) { | 119 | } else if (object->state == FSCACHE_OBJECT_CREATING) { |
116 | op->object = object; | 120 | op->object = object; |
117 | object->n_ops++; | 121 | object->n_ops++; |
@@ -119,14 +123,13 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
119 | atomic_inc(&op->usage); | 123 | atomic_inc(&op->usage); |
120 | list_add_tail(&op->pend_link, &object->pending_ops); | 124 | list_add_tail(&op->pend_link, &object->pending_ops); |
121 | fscache_stat(&fscache_n_op_pend); | 125 | fscache_stat(&fscache_n_op_pend); |
122 | ret = 0; | ||
123 | } else { | 126 | } else { |
124 | /* not allowed to submit ops in any other state */ | 127 | /* not allowed to submit ops in any other state */ |
125 | BUG(); | 128 | BUG(); |
126 | } | 129 | } |
127 | 130 | ||
128 | spin_unlock(&object->lock); | 131 | spin_unlock(&object->lock); |
129 | return ret; | 132 | return 0; |
130 | } | 133 | } |
131 | 134 | ||
132 | /* | 135 | /* |
@@ -186,6 +189,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
186 | _enter("{OBJ%x OP%x},{%u}", | 189 | _enter("{OBJ%x OP%x},{%u}", |
187 | object->debug_id, op->debug_id, atomic_read(&op->usage)); | 190 | object->debug_id, op->debug_id, atomic_read(&op->usage)); |
188 | 191 | ||
192 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
189 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 193 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
190 | 194 | ||
191 | spin_lock(&object->lock); | 195 | spin_lock(&object->lock); |
@@ -196,6 +200,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
196 | ostate = object->state; | 200 | ostate = object->state; |
197 | smp_rmb(); | 201 | smp_rmb(); |
198 | 202 | ||
203 | op->state = FSCACHE_OP_ST_PENDING; | ||
199 | if (fscache_object_is_active(object)) { | 204 | if (fscache_object_is_active(object)) { |
200 | op->object = object; | 205 | op->object = object; |
201 | object->n_ops++; | 206 | object->n_ops++; |
@@ -225,12 +230,15 @@ int fscache_submit_op(struct fscache_object *object, | |||
225 | object->state == FSCACHE_OBJECT_LC_DYING || | 230 | object->state == FSCACHE_OBJECT_LC_DYING || |
226 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | 231 | object->state == FSCACHE_OBJECT_WITHDRAWING) { |
227 | fscache_stat(&fscache_n_op_rejected); | 232 | fscache_stat(&fscache_n_op_rejected); |
233 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
228 | ret = -ENOBUFS; | 234 | ret = -ENOBUFS; |
229 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 235 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
230 | fscache_report_unexpected_submission(object, op, ostate); | 236 | fscache_report_unexpected_submission(object, op, ostate); |
231 | ASSERT(!fscache_object_is_active(object)); | 237 | ASSERT(!fscache_object_is_active(object)); |
238 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
232 | ret = -ENOBUFS; | 239 | ret = -ENOBUFS; |
233 | } else { | 240 | } else { |
241 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
234 | ret = -ENOBUFS; | 242 | ret = -ENOBUFS; |
235 | } | 243 | } |
236 | 244 | ||
@@ -290,13 +298,18 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
290 | 298 | ||
291 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | 299 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); |
292 | 300 | ||
301 | ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING); | ||
302 | ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED); | ||
303 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
304 | |||
293 | spin_lock(&object->lock); | 305 | spin_lock(&object->lock); |
294 | 306 | ||
295 | ret = -EBUSY; | 307 | ret = -EBUSY; |
296 | if (!list_empty(&op->pend_link)) { | 308 | if (op->state == FSCACHE_OP_ST_PENDING) { |
309 | ASSERT(!list_empty(&op->pend_link)); | ||
297 | fscache_stat(&fscache_n_op_cancelled); | 310 | fscache_stat(&fscache_n_op_cancelled); |
298 | list_del_init(&op->pend_link); | 311 | list_del_init(&op->pend_link); |
299 | object->n_ops--; | 312 | op->state = FSCACHE_OP_ST_CANCELLED; |
300 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | 313 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) |
301 | object->n_exclusive--; | 314 | object->n_exclusive--; |
302 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 315 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
@@ -311,6 +324,37 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
311 | } | 324 | } |
312 | 325 | ||
313 | /* | 326 | /* |
327 | * Record the completion of an in-progress operation. | ||
328 | */ | ||
329 | void fscache_op_complete(struct fscache_operation *op) | ||
330 | { | ||
331 | struct fscache_object *object = op->object; | ||
332 | |||
333 | _enter("OBJ%x", object->debug_id); | ||
334 | |||
335 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
336 | ASSERTCMP(object->n_in_progress, >, 0); | ||
337 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
338 | object->n_exclusive, >, 0); | ||
339 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
340 | object->n_in_progress, ==, 1); | ||
341 | |||
342 | spin_lock(&object->lock); | ||
343 | |||
344 | op->state = FSCACHE_OP_ST_COMPLETE; | ||
345 | |||
346 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
347 | object->n_exclusive--; | ||
348 | object->n_in_progress--; | ||
349 | if (object->n_in_progress == 0) | ||
350 | fscache_start_operations(object); | ||
351 | |||
352 | spin_unlock(&object->lock); | ||
353 | _leave(""); | ||
354 | } | ||
355 | EXPORT_SYMBOL(fscache_op_complete); | ||
356 | |||
357 | /* | ||
314 | * release an operation | 358 | * release an operation |
315 | * - queues pending ops if this is the last in-progress op | 359 | * - queues pending ops if this is the last in-progress op |
316 | */ | 360 | */ |
@@ -328,8 +372,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
328 | return; | 372 | return; |
329 | 373 | ||
330 | _debug("PUT OP"); | 374 | _debug("PUT OP"); |
331 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 375 | ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE, |
332 | BUG(); | 376 | op->state, ==, FSCACHE_OP_ST_CANCELLED); |
377 | op->state = FSCACHE_OP_ST_DEAD; | ||
333 | 378 | ||
334 | fscache_stat(&fscache_n_op_release); | 379 | fscache_stat(&fscache_n_op_release); |
335 | 380 | ||
@@ -365,16 +410,6 @@ void fscache_put_operation(struct fscache_operation *op) | |||
365 | return; | 410 | return; |
366 | } | 411 | } |
367 | 412 | ||
368 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
369 | ASSERTCMP(object->n_exclusive, >, 0); | ||
370 | object->n_exclusive--; | ||
371 | } | ||
372 | |||
373 | ASSERTCMP(object->n_in_progress, >, 0); | ||
374 | object->n_in_progress--; | ||
375 | if (object->n_in_progress == 0) | ||
376 | fscache_start_operations(object); | ||
377 | |||
378 | ASSERTCMP(object->n_ops, >, 0); | 413 | ASSERTCMP(object->n_ops, >, 0); |
379 | object->n_ops--; | 414 | object->n_ops--; |
380 | if (object->n_ops == 0) | 415 | if (object->n_ops == 0) |
@@ -413,23 +448,14 @@ void fscache_operation_gc(struct work_struct *work) | |||
413 | spin_unlock(&cache->op_gc_list_lock); | 448 | spin_unlock(&cache->op_gc_list_lock); |
414 | 449 | ||
415 | object = op->object; | 450 | object = op->object; |
451 | spin_lock(&object->lock); | ||
416 | 452 | ||
417 | _debug("GC DEFERRED REL OBJ%x OP%x", | 453 | _debug("GC DEFERRED REL OBJ%x OP%x", |
418 | object->debug_id, op->debug_id); | 454 | object->debug_id, op->debug_id); |
419 | fscache_stat(&fscache_n_op_gc); | 455 | fscache_stat(&fscache_n_op_gc); |
420 | 456 | ||
421 | ASSERTCMP(atomic_read(&op->usage), ==, 0); | 457 | ASSERTCMP(atomic_read(&op->usage), ==, 0); |
422 | 458 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD); | |
423 | spin_lock(&object->lock); | ||
424 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
425 | ASSERTCMP(object->n_exclusive, >, 0); | ||
426 | object->n_exclusive--; | ||
427 | } | ||
428 | |||
429 | ASSERTCMP(object->n_in_progress, >, 0); | ||
430 | object->n_in_progress--; | ||
431 | if (object->n_in_progress == 0) | ||
432 | fscache_start_operations(object); | ||
433 | 459 | ||
434 | ASSERTCMP(object->n_ops, >, 0); | 460 | ASSERTCMP(object->n_ops, >, 0); |
435 | object->n_ops--; | 461 | object->n_ops--; |
@@ -437,6 +463,7 @@ void fscache_operation_gc(struct work_struct *work) | |||
437 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); | 463 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); |
438 | 464 | ||
439 | spin_unlock(&object->lock); | 465 | spin_unlock(&object->lock); |
466 | kfree(op); | ||
440 | 467 | ||
441 | } while (count++ < 20); | 468 | } while (count++ < 20); |
442 | 469 | ||
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 248a12e22532..b38b13d2a555 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -162,6 +162,7 @@ static void fscache_attr_changed_op(struct fscache_operation *op) | |||
162 | fscache_abort_object(object); | 162 | fscache_abort_object(object); |
163 | } | 163 | } |
164 | 164 | ||
165 | fscache_op_complete(op); | ||
165 | _leave(""); | 166 | _leave(""); |
166 | } | 167 | } |
167 | 168 | ||
@@ -223,6 +224,8 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) | |||
223 | 224 | ||
224 | _enter("{OP%x}", op->op.debug_id); | 225 | _enter("{OP%x}", op->op.debug_id); |
225 | 226 | ||
227 | ASSERTCMP(op->n_pages, ==, 0); | ||
228 | |||
226 | fscache_hist(fscache_retrieval_histogram, op->start_time); | 229 | fscache_hist(fscache_retrieval_histogram, op->start_time); |
227 | if (op->context) | 230 | if (op->context) |
228 | fscache_put_context(op->op.object->cookie, op->context); | 231 | fscache_put_context(op->op.object->cookie, op->context); |
@@ -320,6 +323,11 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | |||
320 | _debug("<<< GO"); | 323 | _debug("<<< GO"); |
321 | 324 | ||
322 | check_if_dead: | 325 | check_if_dead: |
326 | if (op->op.state == FSCACHE_OP_ST_CANCELLED) { | ||
327 | fscache_stat(stat_object_dead); | ||
328 | _leave(" = -ENOBUFS [cancelled]"); | ||
329 | return -ENOBUFS; | ||
330 | } | ||
323 | if (unlikely(fscache_object_is_dead(object))) { | 331 | if (unlikely(fscache_object_is_dead(object))) { |
324 | fscache_stat(stat_object_dead); | 332 | fscache_stat(stat_object_dead); |
325 | return -ENOBUFS; | 333 | return -ENOBUFS; |
@@ -364,6 +372,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
364 | _leave(" = -ENOMEM"); | 372 | _leave(" = -ENOMEM"); |
365 | return -ENOMEM; | 373 | return -ENOMEM; |
366 | } | 374 | } |
375 | op->n_pages = 1; | ||
367 | 376 | ||
368 | spin_lock(&cookie->lock); | 377 | spin_lock(&cookie->lock); |
369 | 378 | ||
@@ -375,10 +384,10 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
375 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 384 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); |
376 | 385 | ||
377 | atomic_inc(&object->n_reads); | 386 | atomic_inc(&object->n_reads); |
378 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 387 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
379 | 388 | ||
380 | if (fscache_submit_op(object, &op->op) < 0) | 389 | if (fscache_submit_op(object, &op->op) < 0) |
381 | goto nobufs_unlock; | 390 | goto nobufs_unlock_dec; |
382 | spin_unlock(&cookie->lock); | 391 | spin_unlock(&cookie->lock); |
383 | 392 | ||
384 | fscache_stat(&fscache_n_retrieval_ops); | 393 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -425,6 +434,8 @@ error: | |||
425 | _leave(" = %d", ret); | 434 | _leave(" = %d", ret); |
426 | return ret; | 435 | return ret; |
427 | 436 | ||
437 | nobufs_unlock_dec: | ||
438 | atomic_dec(&object->n_reads); | ||
428 | nobufs_unlock: | 439 | nobufs_unlock: |
429 | spin_unlock(&cookie->lock); | 440 | spin_unlock(&cookie->lock); |
430 | kfree(op); | 441 | kfree(op); |
@@ -482,6 +493,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
482 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 493 | op = fscache_alloc_retrieval(mapping, end_io_func, context); |
483 | if (!op) | 494 | if (!op) |
484 | return -ENOMEM; | 495 | return -ENOMEM; |
496 | op->n_pages = *nr_pages; | ||
485 | 497 | ||
486 | spin_lock(&cookie->lock); | 498 | spin_lock(&cookie->lock); |
487 | 499 | ||
@@ -491,10 +503,10 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
491 | struct fscache_object, cookie_link); | 503 | struct fscache_object, cookie_link); |
492 | 504 | ||
493 | atomic_inc(&object->n_reads); | 505 | atomic_inc(&object->n_reads); |
494 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 506 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
495 | 507 | ||
496 | if (fscache_submit_op(object, &op->op) < 0) | 508 | if (fscache_submit_op(object, &op->op) < 0) |
497 | goto nobufs_unlock; | 509 | goto nobufs_unlock_dec; |
498 | spin_unlock(&cookie->lock); | 510 | spin_unlock(&cookie->lock); |
499 | 511 | ||
500 | fscache_stat(&fscache_n_retrieval_ops); | 512 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -541,6 +553,8 @@ error: | |||
541 | _leave(" = %d", ret); | 553 | _leave(" = %d", ret); |
542 | return ret; | 554 | return ret; |
543 | 555 | ||
556 | nobufs_unlock_dec: | ||
557 | atomic_dec(&object->n_reads); | ||
544 | nobufs_unlock: | 558 | nobufs_unlock: |
545 | spin_unlock(&cookie->lock); | 559 | spin_unlock(&cookie->lock); |
546 | kfree(op); | 560 | kfree(op); |
@@ -583,6 +597,7 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
583 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 597 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); |
584 | if (!op) | 598 | if (!op) |
585 | return -ENOMEM; | 599 | return -ENOMEM; |
600 | op->n_pages = 1; | ||
586 | 601 | ||
587 | spin_lock(&cookie->lock); | 602 | spin_lock(&cookie->lock); |
588 | 603 | ||
@@ -696,6 +711,7 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
696 | fscache_end_page_write(object, page); | 711 | fscache_end_page_write(object, page); |
697 | if (ret < 0) { | 712 | if (ret < 0) { |
698 | fscache_abort_object(object); | 713 | fscache_abort_object(object); |
714 | fscache_op_complete(&op->op); | ||
699 | } else { | 715 | } else { |
700 | fscache_enqueue_operation(&op->op); | 716 | fscache_enqueue_operation(&op->op); |
701 | } | 717 | } |
@@ -710,6 +726,7 @@ superseded: | |||
710 | spin_unlock(&cookie->stores_lock); | 726 | spin_unlock(&cookie->stores_lock); |
711 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 727 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
712 | spin_unlock(&object->lock); | 728 | spin_unlock(&object->lock); |
729 | fscache_op_complete(&op->op); | ||
713 | _leave(""); | 730 | _leave(""); |
714 | } | 731 | } |
715 | 732 | ||
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index e3d6d939d959..f5facd1d333f 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -75,6 +75,16 @@ extern wait_queue_head_t fscache_cache_cleared_wq; | |||
75 | typedef void (*fscache_operation_release_t)(struct fscache_operation *op); | 75 | typedef void (*fscache_operation_release_t)(struct fscache_operation *op); |
76 | typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); | 76 | typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); |
77 | 77 | ||
78 | enum fscache_operation_state { | ||
79 | FSCACHE_OP_ST_BLANK, /* Op is not yet submitted */ | ||
80 | FSCACHE_OP_ST_INITIALISED, /* Op is initialised */ | ||
81 | FSCACHE_OP_ST_PENDING, /* Op is blocked from running */ | ||
82 | FSCACHE_OP_ST_IN_PROGRESS, /* Op is in progress */ | ||
83 | FSCACHE_OP_ST_COMPLETE, /* Op is complete */ | ||
84 | FSCACHE_OP_ST_CANCELLED, /* Op has been cancelled */ | ||
85 | FSCACHE_OP_ST_DEAD /* Op is now dead */ | ||
86 | }; | ||
87 | |||
78 | struct fscache_operation { | 88 | struct fscache_operation { |
79 | struct work_struct work; /* record for async ops */ | 89 | struct work_struct work; /* record for async ops */ |
80 | struct list_head pend_link; /* link in object->pending_ops */ | 90 | struct list_head pend_link; /* link in object->pending_ops */ |
@@ -86,10 +96,10 @@ struct fscache_operation { | |||
86 | #define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */ | 96 | #define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */ |
87 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ | 97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ |
88 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ | 98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ |
89 | #define FSCACHE_OP_DEAD 6 /* op is now dead */ | 99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ |
90 | #define FSCACHE_OP_DEC_READ_CNT 7 /* decrement object->n_reads on destruction */ | 100 | #define FSCACHE_OP_KEEP_FLAGS 0x0070 /* flags to keep when repurposing an op */ |
91 | #define FSCACHE_OP_KEEP_FLAGS 0xc0 /* flags to keep when repurposing an op */ | ||
92 | 101 | ||
102 | enum fscache_operation_state state; | ||
93 | atomic_t usage; | 103 | atomic_t usage; |
94 | unsigned debug_id; /* debugging ID */ | 104 | unsigned debug_id; /* debugging ID */ |
95 | 105 | ||
@@ -106,6 +116,7 @@ extern atomic_t fscache_op_debug_id; | |||
106 | extern void fscache_op_work_func(struct work_struct *work); | 116 | extern void fscache_op_work_func(struct work_struct *work); |
107 | 117 | ||
108 | extern void fscache_enqueue_operation(struct fscache_operation *); | 118 | extern void fscache_enqueue_operation(struct fscache_operation *); |
119 | extern void fscache_op_complete(struct fscache_operation *); | ||
109 | extern void fscache_put_operation(struct fscache_operation *); | 120 | extern void fscache_put_operation(struct fscache_operation *); |
110 | 121 | ||
111 | /** | 122 | /** |
@@ -122,6 +133,7 @@ static inline void fscache_operation_init(struct fscache_operation *op, | |||
122 | { | 133 | { |
123 | INIT_WORK(&op->work, fscache_op_work_func); | 134 | INIT_WORK(&op->work, fscache_op_work_func); |
124 | atomic_set(&op->usage, 1); | 135 | atomic_set(&op->usage, 1); |
136 | op->state = FSCACHE_OP_ST_INITIALISED; | ||
125 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); | 137 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); |
126 | op->processor = processor; | 138 | op->processor = processor; |
127 | op->release = release; | 139 | op->release = release; |
@@ -138,6 +150,7 @@ struct fscache_retrieval { | |||
138 | void *context; /* netfs read context (pinned) */ | 150 | void *context; /* netfs read context (pinned) */ |
139 | struct list_head to_do; /* list of things to be done by the backend */ | 151 | struct list_head to_do; /* list of things to be done by the backend */ |
140 | unsigned long start_time; /* time at which retrieval started */ | 152 | unsigned long start_time; /* time at which retrieval started */ |
153 | unsigned n_pages; /* number of pages to be retrieved */ | ||
141 | }; | 154 | }; |
142 | 155 | ||
143 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, | 156 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, |
@@ -174,8 +187,22 @@ static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op) | |||
174 | } | 187 | } |
175 | 188 | ||
176 | /** | 189 | /** |
190 | * fscache_retrieval_complete - Record (partial) completion of a retrieval | ||
191 | * @op: The retrieval operation affected | ||
192 | * @n_pages: The number of pages to account for | ||
193 | */ | ||
194 | static inline void fscache_retrieval_complete(struct fscache_retrieval *op, | ||
195 | int n_pages) | ||
196 | { | ||
197 | op->n_pages -= n_pages; | ||
198 | if (op->n_pages <= 0) | ||
199 | fscache_op_complete(&op->op); | ||
200 | } | ||
201 | |||
202 | /** | ||
177 | * fscache_put_retrieval - Drop a reference to a retrieval operation | 203 | * fscache_put_retrieval - Drop a reference to a retrieval operation |
178 | * @op: The retrieval operation affected | 204 | * @op: The retrieval operation affected |
205 | * @n_pages: The number of pages to account for | ||
179 | * | 206 | * |
180 | * Drop a reference to a retrieval operation. | 207 | * Drop a reference to a retrieval operation. |
181 | */ | 208 | */ |
@@ -333,10 +360,10 @@ struct fscache_object { | |||
333 | 360 | ||
334 | int debug_id; /* debugging ID */ | 361 | int debug_id; /* debugging ID */ |
335 | int n_children; /* number of child objects */ | 362 | int n_children; /* number of child objects */ |
336 | int n_ops; /* number of ops outstanding on object */ | 363 | int n_ops; /* number of extant ops on object */ |
337 | int n_obj_ops; /* number of object ops outstanding on object */ | 364 | int n_obj_ops; /* number of object ops outstanding on object */ |
338 | int n_in_progress; /* number of ops in progress */ | 365 | int n_in_progress; /* number of ops in progress */ |
339 | int n_exclusive; /* number of exclusive ops queued */ | 366 | int n_exclusive; /* number of exclusive ops queued or in progress */ |
340 | atomic_t n_reads; /* number of read ops in progress */ | 367 | atomic_t n_reads; /* number of read ops in progress */ |
341 | spinlock_t lock; /* state and operations lock */ | 368 | spinlock_t lock; /* state and operations lock */ |
342 | 369 | ||