diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/9p/cache.c | 14 | ||||
| -rw-r--r-- | fs/afs/file.c | 15 | ||||
| -rw-r--r-- | fs/cachefiles/interface.c | 32 | ||||
| -rw-r--r-- | fs/cachefiles/namei.c | 187 | ||||
| -rw-r--r-- | fs/cachefiles/rdwr.c | 128 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 2 | ||||
| -rw-r--r-- | fs/fscache/Kconfig | 7 | ||||
| -rw-r--r-- | fs/fscache/Makefile | 1 | ||||
| -rw-r--r-- | fs/fscache/cache.c | 5 | ||||
| -rw-r--r-- | fs/fscache/cookie.c | 26 | ||||
| -rw-r--r-- | fs/fscache/internal.h | 56 | ||||
| -rw-r--r-- | fs/fscache/main.c | 6 | ||||
| -rw-r--r-- | fs/fscache/object-list.c | 432 | ||||
| -rw-r--r-- | fs/fscache/object.c | 104 | ||||
| -rw-r--r-- | fs/fscache/operation.c | 120 | ||||
| -rw-r--r-- | fs/fscache/page.c | 273 | ||||
| -rw-r--r-- | fs/fscache/proc.c | 13 | ||||
| -rw-r--r-- | fs/fscache/stats.c | 94 | ||||
| -rw-r--r-- | fs/gfs2/main.c | 4 | ||||
| -rw-r--r-- | fs/gfs2/recovery.c | 2 | ||||
| -rw-r--r-- | fs/jffs2/read.c | 9 | ||||
| -rw-r--r-- | fs/nfs/fscache.c | 10 |
22 files changed, 1328 insertions, 212 deletions
diff --git a/fs/9p/cache.c b/fs/9p/cache.c index 51c94e26a346..bcc5357a9069 100644 --- a/fs/9p/cache.c +++ b/fs/9p/cache.c | |||
| @@ -343,18 +343,7 @@ int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) | |||
| 343 | 343 | ||
| 344 | BUG_ON(!vcookie->fscache); | 344 | BUG_ON(!vcookie->fscache); |
| 345 | 345 | ||
| 346 | if (PageFsCache(page)) { | 346 | return fscache_maybe_release_page(vnode->cache, page, gfp); |
| 347 | if (fscache_check_page_write(vcookie->fscache, page)) { | ||
| 348 | if (!(gfp & __GFP_WAIT)) | ||
| 349 | return 0; | ||
| 350 | fscache_wait_on_page_write(vcookie->fscache, page); | ||
| 351 | } | ||
| 352 | |||
| 353 | fscache_uncache_page(vcookie->fscache, page); | ||
| 354 | ClearPageFsCache(page); | ||
| 355 | } | ||
| 356 | |||
| 357 | return 1; | ||
| 358 | } | 347 | } |
| 359 | 348 | ||
| 360 | void __v9fs_fscache_invalidate_page(struct page *page) | 349 | void __v9fs_fscache_invalidate_page(struct page *page) |
| @@ -368,7 +357,6 @@ void __v9fs_fscache_invalidate_page(struct page *page) | |||
| 368 | fscache_wait_on_page_write(vcookie->fscache, page); | 357 | fscache_wait_on_page_write(vcookie->fscache, page); |
| 369 | BUG_ON(!PageLocked(page)); | 358 | BUG_ON(!PageLocked(page)); |
| 370 | fscache_uncache_page(vcookie->fscache, page); | 359 | fscache_uncache_page(vcookie->fscache, page); |
| 371 | ClearPageFsCache(page); | ||
| 372 | } | 360 | } |
| 373 | } | 361 | } |
| 374 | 362 | ||
diff --git a/fs/afs/file.c b/fs/afs/file.c index 681c2a7b013f..39b301662f22 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
| @@ -315,7 +315,6 @@ static void afs_invalidatepage(struct page *page, unsigned long offset) | |||
| 315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | 315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
| 316 | fscache_wait_on_page_write(vnode->cache, page); | 316 | fscache_wait_on_page_write(vnode->cache, page); |
| 317 | fscache_uncache_page(vnode->cache, page); | 317 | fscache_uncache_page(vnode->cache, page); |
| 318 | ClearPageFsCache(page); | ||
| 319 | } | 318 | } |
| 320 | #endif | 319 | #endif |
| 321 | 320 | ||
| @@ -349,17 +348,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) | |||
| 349 | /* deny if page is being written to the cache and the caller hasn't | 348 | /* deny if page is being written to the cache and the caller hasn't |
| 350 | * elected to wait */ | 349 | * elected to wait */ |
| 351 | #ifdef CONFIG_AFS_FSCACHE | 350 | #ifdef CONFIG_AFS_FSCACHE |
| 352 | if (PageFsCache(page)) { | 351 | if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { |
| 353 | if (fscache_check_page_write(vnode->cache, page)) { | 352 | _leave(" = F [cache busy]"); |
| 354 | if (!(gfp_flags & __GFP_WAIT)) { | 353 | return 0; |
| 355 | _leave(" = F [cache busy]"); | ||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | fscache_wait_on_page_write(vnode->cache, page); | ||
| 359 | } | ||
| 360 | |||
| 361 | fscache_uncache_page(vnode->cache, page); | ||
| 362 | ClearPageFsCache(page); | ||
| 363 | } | 354 | } |
| 364 | #endif | 355 | #endif |
| 365 | 356 | ||
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 431accd475a7..27089311fbea 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
| @@ -114,8 +114,9 @@ nomem_lookup_data: | |||
| 114 | 114 | ||
| 115 | /* | 115 | /* |
| 116 | * attempt to look up the nominated node in this cache | 116 | * attempt to look up the nominated node in this cache |
| 117 | * - return -ETIMEDOUT to be scheduled again | ||
| 117 | */ | 118 | */ |
| 118 | static void cachefiles_lookup_object(struct fscache_object *_object) | 119 | static int cachefiles_lookup_object(struct fscache_object *_object) |
| 119 | { | 120 | { |
| 120 | struct cachefiles_lookup_data *lookup_data; | 121 | struct cachefiles_lookup_data *lookup_data; |
| 121 | struct cachefiles_object *parent, *object; | 122 | struct cachefiles_object *parent, *object; |
| @@ -145,13 +146,15 @@ static void cachefiles_lookup_object(struct fscache_object *_object) | |||
| 145 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) | 146 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) |
| 146 | cachefiles_attr_changed(&object->fscache); | 147 | cachefiles_attr_changed(&object->fscache); |
| 147 | 148 | ||
| 148 | if (ret < 0) { | 149 | if (ret < 0 && ret != -ETIMEDOUT) { |
| 149 | printk(KERN_WARNING "CacheFiles: Lookup failed error %d\n", | 150 | if (ret != -ENOBUFS) |
| 150 | ret); | 151 | printk(KERN_WARNING |
| 152 | "CacheFiles: Lookup failed error %d\n", ret); | ||
| 151 | fscache_object_lookup_error(&object->fscache); | 153 | fscache_object_lookup_error(&object->fscache); |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | _leave(" [%d]", ret); | 156 | _leave(" [%d]", ret); |
| 157 | return ret; | ||
| 155 | } | 158 | } |
| 156 | 159 | ||
| 157 | /* | 160 | /* |
| @@ -331,6 +334,7 @@ static void cachefiles_put_object(struct fscache_object *_object) | |||
| 331 | } | 334 | } |
| 332 | 335 | ||
| 333 | cache = object->fscache.cache; | 336 | cache = object->fscache.cache; |
| 337 | fscache_object_destroy(&object->fscache); | ||
| 334 | kmem_cache_free(cachefiles_object_jar, object); | 338 | kmem_cache_free(cachefiles_object_jar, object); |
| 335 | fscache_object_destroyed(cache); | 339 | fscache_object_destroyed(cache); |
| 336 | } | 340 | } |
| @@ -403,12 +407,26 @@ static int cachefiles_attr_changed(struct fscache_object *_object) | |||
| 403 | if (oi_size == ni_size) | 407 | if (oi_size == ni_size) |
| 404 | return 0; | 408 | return 0; |
| 405 | 409 | ||
| 406 | newattrs.ia_size = ni_size; | ||
| 407 | newattrs.ia_valid = ATTR_SIZE; | ||
| 408 | |||
| 409 | cachefiles_begin_secure(cache, &saved_cred); | 410 | cachefiles_begin_secure(cache, &saved_cred); |
| 410 | mutex_lock(&object->backer->d_inode->i_mutex); | 411 | mutex_lock(&object->backer->d_inode->i_mutex); |
| 412 | |||
| 413 | /* if there's an extension to a partial page at the end of the backing | ||
| 414 | * file, we need to discard the partial page so that we pick up new | ||
| 415 | * data after it */ | ||
| 416 | if (oi_size & ~PAGE_MASK && ni_size > oi_size) { | ||
| 417 | _debug("discard tail %llx", oi_size); | ||
| 418 | newattrs.ia_valid = ATTR_SIZE; | ||
| 419 | newattrs.ia_size = oi_size & PAGE_MASK; | ||
| 420 | ret = notify_change(object->backer, &newattrs); | ||
| 421 | if (ret < 0) | ||
| 422 | goto truncate_failed; | ||
| 423 | } | ||
| 424 | |||
| 425 | newattrs.ia_valid = ATTR_SIZE; | ||
| 426 | newattrs.ia_size = ni_size; | ||
| 411 | ret = notify_change(object->backer, &newattrs); | 427 | ret = notify_change(object->backer, &newattrs); |
| 428 | |||
| 429 | truncate_failed: | ||
| 412 | mutex_unlock(&object->backer->d_inode->i_mutex); | 430 | mutex_unlock(&object->backer->d_inode->i_mutex); |
| 413 | cachefiles_end_secure(cache, saved_cred); | 431 | cachefiles_end_secure(cache, saved_cred); |
| 414 | 432 | ||
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 4ce818ae39ea..14ac4806e291 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
| @@ -21,17 +21,81 @@ | |||
| 21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
| 22 | #include "internal.h" | 22 | #include "internal.h" |
| 23 | 23 | ||
| 24 | static int cachefiles_wait_bit(void *flags) | 24 | #define CACHEFILES_KEYBUF_SIZE 512 |
| 25 | |||
| 26 | /* | ||
| 27 | * dump debugging info about an object | ||
| 28 | */ | ||
| 29 | static noinline | ||
| 30 | void __cachefiles_printk_object(struct cachefiles_object *object, | ||
| 31 | const char *prefix, | ||
| 32 | u8 *keybuf) | ||
| 25 | { | 33 | { |
| 26 | schedule(); | 34 | struct fscache_cookie *cookie; |
| 27 | return 0; | 35 | unsigned keylen, loop; |
| 36 | |||
| 37 | printk(KERN_ERR "%sobject: OBJ%x\n", | ||
| 38 | prefix, object->fscache.debug_id); | ||
| 39 | printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n", | ||
| 40 | prefix, fscache_object_states[object->fscache.state], | ||
| 41 | object->fscache.flags, object->fscache.work.flags, | ||
| 42 | object->fscache.events, | ||
| 43 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | ||
| 44 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | ||
| 45 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, | ||
| 46 | object->fscache.n_exclusive); | ||
| 47 | printk(KERN_ERR "%sparent=%p\n", | ||
| 48 | prefix, object->fscache.parent); | ||
| 49 | |||
| 50 | spin_lock(&object->fscache.lock); | ||
| 51 | cookie = object->fscache.cookie; | ||
| 52 | if (cookie) { | ||
| 53 | printk(KERN_ERR "%scookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
| 54 | prefix, | ||
| 55 | object->fscache.cookie, | ||
| 56 | object->fscache.cookie->parent, | ||
| 57 | object->fscache.cookie->netfs_data, | ||
| 58 | object->fscache.cookie->flags); | ||
| 59 | if (keybuf) | ||
| 60 | keylen = cookie->def->get_key(cookie->netfs_data, keybuf, | ||
| 61 | CACHEFILES_KEYBUF_SIZE); | ||
| 62 | else | ||
| 63 | keylen = 0; | ||
| 64 | } else { | ||
| 65 | printk(KERN_ERR "%scookie=NULL\n", prefix); | ||
| 66 | keylen = 0; | ||
| 67 | } | ||
| 68 | spin_unlock(&object->fscache.lock); | ||
| 69 | |||
| 70 | if (keylen) { | ||
| 71 | printk(KERN_ERR "%skey=[%u] '", prefix, keylen); | ||
| 72 | for (loop = 0; loop < keylen; loop++) | ||
| 73 | printk("%02x", keybuf[loop]); | ||
| 74 | printk("'\n"); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /* | ||
| 79 | * dump debugging info about a pair of objects | ||
| 80 | */ | ||
| 81 | static noinline void cachefiles_printk_object(struct cachefiles_object *object, | ||
| 82 | struct cachefiles_object *xobject) | ||
| 83 | { | ||
| 84 | u8 *keybuf; | ||
| 85 | |||
| 86 | keybuf = kmalloc(CACHEFILES_KEYBUF_SIZE, GFP_NOIO); | ||
| 87 | if (object) | ||
| 88 | __cachefiles_printk_object(object, "", keybuf); | ||
| 89 | if (xobject) | ||
| 90 | __cachefiles_printk_object(xobject, "x", keybuf); | ||
| 91 | kfree(keybuf); | ||
| 28 | } | 92 | } |
| 29 | 93 | ||
| 30 | /* | 94 | /* |
| 31 | * record the fact that an object is now active | 95 | * record the fact that an object is now active |
| 32 | */ | 96 | */ |
| 33 | static void cachefiles_mark_object_active(struct cachefiles_cache *cache, | 97 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
| 34 | struct cachefiles_object *object) | 98 | struct cachefiles_object *object) |
| 35 | { | 99 | { |
| 36 | struct cachefiles_object *xobject; | 100 | struct cachefiles_object *xobject; |
| 37 | struct rb_node **_p, *_parent = NULL; | 101 | struct rb_node **_p, *_parent = NULL; |
| @@ -42,8 +106,11 @@ static void cachefiles_mark_object_active(struct cachefiles_cache *cache, | |||
| 42 | try_again: | 106 | try_again: |
| 43 | write_lock(&cache->active_lock); | 107 | write_lock(&cache->active_lock); |
| 44 | 108 | ||
| 45 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) | 109 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { |
| 110 | printk(KERN_ERR "CacheFiles: Error: Object already active\n"); | ||
| 111 | cachefiles_printk_object(object, NULL); | ||
| 46 | BUG(); | 112 | BUG(); |
| 113 | } | ||
| 47 | 114 | ||
| 48 | dentry = object->dentry; | 115 | dentry = object->dentry; |
| 49 | _p = &cache->active_nodes.rb_node; | 116 | _p = &cache->active_nodes.rb_node; |
| @@ -66,8 +133,8 @@ try_again: | |||
| 66 | rb_insert_color(&object->active_node, &cache->active_nodes); | 133 | rb_insert_color(&object->active_node, &cache->active_nodes); |
| 67 | 134 | ||
| 68 | write_unlock(&cache->active_lock); | 135 | write_unlock(&cache->active_lock); |
| 69 | _leave(""); | 136 | _leave(" = 0"); |
| 70 | return; | 137 | return 0; |
| 71 | 138 | ||
| 72 | /* an old object from a previous incarnation is hogging the slot - we | 139 | /* an old object from a previous incarnation is hogging the slot - we |
| 73 | * need to wait for it to be destroyed */ | 140 | * need to wait for it to be destroyed */ |
| @@ -76,44 +143,70 @@ wait_for_old_object: | |||
| 76 | printk(KERN_ERR "\n"); | 143 | printk(KERN_ERR "\n"); |
| 77 | printk(KERN_ERR "CacheFiles: Error:" | 144 | printk(KERN_ERR "CacheFiles: Error:" |
| 78 | " Unexpected object collision\n"); | 145 | " Unexpected object collision\n"); |
| 79 | printk(KERN_ERR "xobject: OBJ%x\n", | 146 | cachefiles_printk_object(object, xobject); |
| 80 | xobject->fscache.debug_id); | ||
| 81 | printk(KERN_ERR "xobjstate=%s\n", | ||
| 82 | fscache_object_states[xobject->fscache.state]); | ||
| 83 | printk(KERN_ERR "xobjflags=%lx\n", xobject->fscache.flags); | ||
| 84 | printk(KERN_ERR "xobjevent=%lx [%lx]\n", | ||
| 85 | xobject->fscache.events, xobject->fscache.event_mask); | ||
| 86 | printk(KERN_ERR "xops=%u inp=%u exc=%u\n", | ||
| 87 | xobject->fscache.n_ops, xobject->fscache.n_in_progress, | ||
| 88 | xobject->fscache.n_exclusive); | ||
| 89 | printk(KERN_ERR "xcookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
| 90 | xobject->fscache.cookie, | ||
| 91 | xobject->fscache.cookie->parent, | ||
| 92 | xobject->fscache.cookie->netfs_data, | ||
| 93 | xobject->fscache.cookie->flags); | ||
| 94 | printk(KERN_ERR "xparent=%p\n", | ||
| 95 | xobject->fscache.parent); | ||
| 96 | printk(KERN_ERR "object: OBJ%x\n", | ||
| 97 | object->fscache.debug_id); | ||
| 98 | printk(KERN_ERR "cookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
| 99 | object->fscache.cookie, | ||
| 100 | object->fscache.cookie->parent, | ||
| 101 | object->fscache.cookie->netfs_data, | ||
| 102 | object->fscache.cookie->flags); | ||
| 103 | printk(KERN_ERR "parent=%p\n", | ||
| 104 | object->fscache.parent); | ||
| 105 | BUG(); | 147 | BUG(); |
| 106 | } | 148 | } |
| 107 | atomic_inc(&xobject->usage); | 149 | atomic_inc(&xobject->usage); |
| 108 | write_unlock(&cache->active_lock); | 150 | write_unlock(&cache->active_lock); |
| 109 | 151 | ||
| 110 | _debug(">>> wait"); | 152 | if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { |
| 111 | wait_on_bit(&xobject->flags, CACHEFILES_OBJECT_ACTIVE, | 153 | wait_queue_head_t *wq; |
| 112 | cachefiles_wait_bit, TASK_UNINTERRUPTIBLE); | 154 | |
| 113 | _debug("<<< waited"); | 155 | signed long timeout = 60 * HZ; |
| 156 | wait_queue_t wait; | ||
| 157 | bool requeue; | ||
| 158 | |||
| 159 | /* if the object we're waiting for is queued for processing, | ||
| 160 | * then just put ourselves on the queue behind it */ | ||
| 161 | if (slow_work_is_queued(&xobject->fscache.work)) { | ||
| 162 | _debug("queue OBJ%x behind OBJ%x immediately", | ||
| 163 | object->fscache.debug_id, | ||
| 164 | xobject->fscache.debug_id); | ||
| 165 | goto requeue; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* otherwise we sleep until either the object we're waiting for | ||
| 169 | * is done, or the slow-work facility wants the thread back to | ||
| 170 | * do other work */ | ||
| 171 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | ||
| 172 | init_wait(&wait); | ||
| 173 | requeue = false; | ||
| 174 | do { | ||
| 175 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | ||
| 176 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | ||
| 177 | break; | ||
| 178 | requeue = slow_work_sleep_till_thread_needed( | ||
| 179 | &object->fscache.work, &timeout); | ||
| 180 | } while (timeout > 0 && !requeue); | ||
| 181 | finish_wait(wq, &wait); | ||
| 182 | |||
| 183 | if (requeue && | ||
| 184 | test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { | ||
| 185 | _debug("queue OBJ%x behind OBJ%x after wait", | ||
| 186 | object->fscache.debug_id, | ||
| 187 | xobject->fscache.debug_id); | ||
| 188 | goto requeue; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (timeout <= 0) { | ||
| 192 | printk(KERN_ERR "\n"); | ||
| 193 | printk(KERN_ERR "CacheFiles: Error: Overlong" | ||
| 194 | " wait for old active object to go away\n"); | ||
| 195 | cachefiles_printk_object(object, xobject); | ||
| 196 | goto requeue; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); | ||
| 114 | 201 | ||
| 115 | cache->cache.ops->put_object(&xobject->fscache); | 202 | cache->cache.ops->put_object(&xobject->fscache); |
| 116 | goto try_again; | 203 | goto try_again; |
| 204 | |||
| 205 | requeue: | ||
| 206 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | ||
| 207 | cache->cache.ops->put_object(&xobject->fscache); | ||
| 208 | _leave(" = -ETIMEDOUT"); | ||
| 209 | return -ETIMEDOUT; | ||
| 117 | } | 210 | } |
| 118 | 211 | ||
| 119 | /* | 212 | /* |
| @@ -254,7 +347,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
| 254 | 347 | ||
| 255 | dir = dget_parent(object->dentry); | 348 | dir = dget_parent(object->dentry); |
| 256 | 349 | ||
| 257 | mutex_lock(&dir->d_inode->i_mutex); | 350 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
| 258 | ret = cachefiles_bury_object(cache, dir, object->dentry); | 351 | ret = cachefiles_bury_object(cache, dir, object->dentry); |
| 259 | 352 | ||
| 260 | dput(dir); | 353 | dput(dir); |
| @@ -307,7 +400,7 @@ lookup_again: | |||
| 307 | /* search the current directory for the element name */ | 400 | /* search the current directory for the element name */ |
| 308 | _debug("lookup '%s'", name); | 401 | _debug("lookup '%s'", name); |
| 309 | 402 | ||
| 310 | mutex_lock(&dir->d_inode->i_mutex); | 403 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
| 311 | 404 | ||
| 312 | start = jiffies; | 405 | start = jiffies; |
| 313 | next = lookup_one_len(name, dir, nlen); | 406 | next = lookup_one_len(name, dir, nlen); |
| @@ -418,12 +511,15 @@ lookup_again: | |||
| 418 | } | 511 | } |
| 419 | 512 | ||
| 420 | /* note that we're now using this object */ | 513 | /* note that we're now using this object */ |
| 421 | cachefiles_mark_object_active(cache, object); | 514 | ret = cachefiles_mark_object_active(cache, object); |
| 422 | 515 | ||
| 423 | mutex_unlock(&dir->d_inode->i_mutex); | 516 | mutex_unlock(&dir->d_inode->i_mutex); |
| 424 | dput(dir); | 517 | dput(dir); |
| 425 | dir = NULL; | 518 | dir = NULL; |
| 426 | 519 | ||
| 520 | if (ret == -ETIMEDOUT) | ||
| 521 | goto mark_active_timed_out; | ||
| 522 | |||
| 427 | _debug("=== OBTAINED_OBJECT ==="); | 523 | _debug("=== OBTAINED_OBJECT ==="); |
| 428 | 524 | ||
| 429 | if (object->new) { | 525 | if (object->new) { |
| @@ -467,6 +563,10 @@ create_error: | |||
| 467 | cachefiles_io_error(cache, "Create/mkdir failed"); | 563 | cachefiles_io_error(cache, "Create/mkdir failed"); |
| 468 | goto error; | 564 | goto error; |
| 469 | 565 | ||
| 566 | mark_active_timed_out: | ||
| 567 | _debug("mark active timed out"); | ||
| 568 | goto release_dentry; | ||
| 569 | |||
| 470 | check_error: | 570 | check_error: |
| 471 | _debug("check error %d", ret); | 571 | _debug("check error %d", ret); |
| 472 | write_lock(&cache->active_lock); | 572 | write_lock(&cache->active_lock); |
| @@ -474,7 +574,7 @@ check_error: | |||
| 474 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | 574 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); |
| 475 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); | 575 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); |
| 476 | write_unlock(&cache->active_lock); | 576 | write_unlock(&cache->active_lock); |
| 477 | 577 | release_dentry: | |
| 478 | dput(object->dentry); | 578 | dput(object->dentry); |
| 479 | object->dentry = NULL; | 579 | object->dentry = NULL; |
| 480 | goto error_out; | 580 | goto error_out; |
| @@ -495,9 +595,6 @@ error: | |||
| 495 | error_out2: | 595 | error_out2: |
| 496 | dput(dir); | 596 | dput(dir); |
| 497 | error_out: | 597 | error_out: |
| 498 | if (ret == -ENOSPC) | ||
| 499 | ret = -ENOBUFS; | ||
| 500 | |||
| 501 | _leave(" = error %d", -ret); | 598 | _leave(" = error %d", -ret); |
| 502 | return ret; | 599 | return ret; |
| 503 | } | 600 | } |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index a69787e7dd96..1d8332563863 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
| @@ -40,8 +40,10 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
| 40 | 40 | ||
| 41 | _debug("--- monitor %p %lx ---", page, page->flags); | 41 | _debug("--- monitor %p %lx ---", page, page->flags); |
| 42 | 42 | ||
| 43 | if (!PageUptodate(page) && !PageError(page)) | 43 | if (!PageUptodate(page) && !PageError(page)) { |
| 44 | dump_stack(); | 44 | /* unlocked, not uptodate and not erronous? */ |
| 45 | _debug("page probably truncated"); | ||
| 46 | } | ||
| 45 | 47 | ||
| 46 | /* remove from the waitqueue */ | 48 | /* remove from the waitqueue */ |
| 47 | list_del(&wait->task_list); | 49 | list_del(&wait->task_list); |
| @@ -61,6 +63,84 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | /* | 65 | /* |
| 66 | * handle a probably truncated page | ||
| 67 | * - check to see if the page is still relevant and reissue the read if | ||
| 68 | * possible | ||
| 69 | * - return -EIO on error, -ENODATA if the page is gone, -EINPROGRESS if we | ||
| 70 | * must wait again and 0 if successful | ||
| 71 | */ | ||
| 72 | static int cachefiles_read_reissue(struct cachefiles_object *object, | ||
| 73 | struct cachefiles_one_read *monitor) | ||
| 74 | { | ||
| 75 | struct address_space *bmapping = object->backer->d_inode->i_mapping; | ||
| 76 | struct page *backpage = monitor->back_page, *backpage2; | ||
| 77 | int ret; | ||
| 78 | |||
| 79 | kenter("{ino=%lx},{%lx,%lx}", | ||
| 80 | object->backer->d_inode->i_ino, | ||
| 81 | backpage->index, backpage->flags); | ||
| 82 | |||
| 83 | /* skip if the page was truncated away completely */ | ||
| 84 | if (backpage->mapping != bmapping) { | ||
| 85 | kleave(" = -ENODATA [mapping]"); | ||
| 86 | return -ENODATA; | ||
| 87 | } | ||
| 88 | |||
| 89 | backpage2 = find_get_page(bmapping, backpage->index); | ||
| 90 | if (!backpage2) { | ||
| 91 | kleave(" = -ENODATA [gone]"); | ||
| 92 | return -ENODATA; | ||
| 93 | } | ||
| 94 | |||
| 95 | if (backpage != backpage2) { | ||
| 96 | put_page(backpage2); | ||
| 97 | kleave(" = -ENODATA [different]"); | ||
| 98 | return -ENODATA; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* the page is still there and we already have a ref on it, so we don't | ||
| 102 | * need a second */ | ||
| 103 | put_page(backpage2); | ||
| 104 | |||
| 105 | INIT_LIST_HEAD(&monitor->op_link); | ||
| 106 | add_page_wait_queue(backpage, &monitor->monitor); | ||
| 107 | |||
| 108 | if (trylock_page(backpage)) { | ||
| 109 | ret = -EIO; | ||
| 110 | if (PageError(backpage)) | ||
| 111 | goto unlock_discard; | ||
| 112 | ret = 0; | ||
| 113 | if (PageUptodate(backpage)) | ||
| 114 | goto unlock_discard; | ||
| 115 | |||
| 116 | kdebug("reissue read"); | ||
| 117 | ret = bmapping->a_ops->readpage(NULL, backpage); | ||
| 118 | if (ret < 0) | ||
| 119 | goto unlock_discard; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* but the page may have been read before the monitor was installed, so | ||
| 123 | * the monitor may miss the event - so we have to ensure that we do get | ||
| 124 | * one in such a case */ | ||
| 125 | if (trylock_page(backpage)) { | ||
| 126 | _debug("jumpstart %p {%lx}", backpage, backpage->flags); | ||
| 127 | unlock_page(backpage); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* it'll reappear on the todo list */ | ||
| 131 | kleave(" = -EINPROGRESS"); | ||
| 132 | return -EINPROGRESS; | ||
| 133 | |||
| 134 | unlock_discard: | ||
| 135 | unlock_page(backpage); | ||
| 136 | spin_lock_irq(&object->work_lock); | ||
| 137 | list_del(&monitor->op_link); | ||
| 138 | spin_unlock_irq(&object->work_lock); | ||
| 139 | kleave(" = %d", ret); | ||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 64 | * copy data from backing pages to netfs pages to complete a read operation | 144 | * copy data from backing pages to netfs pages to complete a read operation |
| 65 | * - driven by FS-Cache's thread pool | 145 | * - driven by FS-Cache's thread pool |
| 66 | */ | 146 | */ |
| @@ -92,20 +172,26 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
| 92 | 172 | ||
| 93 | _debug("- copy {%lu}", monitor->back_page->index); | 173 | _debug("- copy {%lu}", monitor->back_page->index); |
| 94 | 174 | ||
| 95 | error = -EIO; | 175 | recheck: |
| 96 | if (PageUptodate(monitor->back_page)) { | 176 | if (PageUptodate(monitor->back_page)) { |
| 97 | copy_highpage(monitor->netfs_page, monitor->back_page); | 177 | copy_highpage(monitor->netfs_page, monitor->back_page); |
| 98 | 178 | ||
| 99 | pagevec_add(&pagevec, monitor->netfs_page); | 179 | pagevec_add(&pagevec, monitor->netfs_page); |
| 100 | fscache_mark_pages_cached(monitor->op, &pagevec); | 180 | fscache_mark_pages_cached(monitor->op, &pagevec); |
| 101 | error = 0; | 181 | error = 0; |
| 102 | } | 182 | } else if (!PageError(monitor->back_page)) { |
| 103 | 183 | /* the page has probably been truncated */ | |
| 104 | if (error) | 184 | error = cachefiles_read_reissue(object, monitor); |
| 185 | if (error == -EINPROGRESS) | ||
| 186 | goto next; | ||
| 187 | goto recheck; | ||
| 188 | } else { | ||
| 105 | cachefiles_io_error_obj( | 189 | cachefiles_io_error_obj( |
| 106 | object, | 190 | object, |
| 107 | "Readpage failed on backing file %lx", | 191 | "Readpage failed on backing file %lx", |
| 108 | (unsigned long) monitor->back_page->flags); | 192 | (unsigned long) monitor->back_page->flags); |
| 193 | error = -EIO; | ||
| 194 | } | ||
| 109 | 195 | ||
| 110 | page_cache_release(monitor->back_page); | 196 | page_cache_release(monitor->back_page); |
| 111 | 197 | ||
| @@ -114,6 +200,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
| 114 | fscache_put_retrieval(op); | 200 | fscache_put_retrieval(op); |
| 115 | kfree(monitor); | 201 | kfree(monitor); |
| 116 | 202 | ||
| 203 | next: | ||
| 117 | /* let the thread pool have some air occasionally */ | 204 | /* let the thread pool have some air occasionally */ |
| 118 | max--; | 205 | max--; |
| 119 | if (max < 0 || need_resched()) { | 206 | if (max < 0 || need_resched()) { |
| @@ -333,7 +420,8 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
| 333 | 420 | ||
| 334 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 421 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
| 335 | 422 | ||
| 336 | op->op.flags = FSCACHE_OP_FAST; | 423 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
| 424 | op->op.flags |= FSCACHE_OP_FAST; | ||
| 337 | op->op.processor = cachefiles_read_copier; | 425 | op->op.processor = cachefiles_read_copier; |
| 338 | 426 | ||
| 339 | pagevec_init(&pagevec, 0); | 427 | pagevec_init(&pagevec, 0); |
| @@ -639,7 +727,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
| 639 | 727 | ||
| 640 | pagevec_init(&pagevec, 0); | 728 | pagevec_init(&pagevec, 0); |
| 641 | 729 | ||
| 642 | op->op.flags = FSCACHE_OP_FAST; | 730 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
| 731 | op->op.flags |= FSCACHE_OP_FAST; | ||
| 643 | op->op.processor = cachefiles_read_copier; | 732 | op->op.processor = cachefiles_read_copier; |
| 644 | 733 | ||
| 645 | INIT_LIST_HEAD(&backpages); | 734 | INIT_LIST_HEAD(&backpages); |
| @@ -801,7 +890,8 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
| 801 | struct cachefiles_cache *cache; | 890 | struct cachefiles_cache *cache; |
| 802 | mm_segment_t old_fs; | 891 | mm_segment_t old_fs; |
| 803 | struct file *file; | 892 | struct file *file; |
| 804 | loff_t pos; | 893 | loff_t pos, eof; |
| 894 | size_t len; | ||
| 805 | void *data; | 895 | void *data; |
| 806 | int ret; | 896 | int ret; |
| 807 | 897 | ||
| @@ -835,15 +925,29 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
| 835 | ret = -EIO; | 925 | ret = -EIO; |
| 836 | if (file->f_op->write) { | 926 | if (file->f_op->write) { |
| 837 | pos = (loff_t) page->index << PAGE_SHIFT; | 927 | pos = (loff_t) page->index << PAGE_SHIFT; |
| 928 | |||
| 929 | /* we mustn't write more data than we have, so we have | ||
| 930 | * to beware of a partial page at EOF */ | ||
| 931 | eof = object->fscache.store_limit_l; | ||
| 932 | len = PAGE_SIZE; | ||
| 933 | if (eof & ~PAGE_MASK) { | ||
| 934 | ASSERTCMP(pos, <, eof); | ||
| 935 | if (eof - pos < PAGE_SIZE) { | ||
| 936 | _debug("cut short %llx to %llx", | ||
| 937 | pos, eof); | ||
| 938 | len = eof - pos; | ||
| 939 | ASSERTCMP(pos + len, ==, eof); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | |||
| 838 | data = kmap(page); | 943 | data = kmap(page); |
| 839 | old_fs = get_fs(); | 944 | old_fs = get_fs(); |
| 840 | set_fs(KERNEL_DS); | 945 | set_fs(KERNEL_DS); |
| 841 | ret = file->f_op->write( | 946 | ret = file->f_op->write( |
| 842 | file, (const void __user *) data, PAGE_SIZE, | 947 | file, (const void __user *) data, len, &pos); |
| 843 | &pos); | ||
| 844 | set_fs(old_fs); | 948 | set_fs(old_fs); |
| 845 | kunmap(page); | 949 | kunmap(page); |
| 846 | if (ret != PAGE_SIZE) | 950 | if (ret != len) |
| 847 | ret = -EIO; | 951 | ret = -EIO; |
| 848 | } | 952 | } |
| 849 | fput(file); | 953 | fput(file); |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9a5e4f5f3122..29f1da761bbf 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -1037,7 +1037,7 @@ init_cifs(void) | |||
| 1037 | if (rc) | 1037 | if (rc) |
| 1038 | goto out_unregister_key_type; | 1038 | goto out_unregister_key_type; |
| 1039 | #endif | 1039 | #endif |
| 1040 | rc = slow_work_register_user(); | 1040 | rc = slow_work_register_user(THIS_MODULE); |
| 1041 | if (rc) | 1041 | if (rc) |
| 1042 | goto out_unregister_resolver_key; | 1042 | goto out_unregister_resolver_key; |
| 1043 | 1043 | ||
diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig index 9bbb8ce7bea0..864dac20a242 100644 --- a/fs/fscache/Kconfig +++ b/fs/fscache/Kconfig | |||
| @@ -54,3 +54,10 @@ config FSCACHE_DEBUG | |||
| 54 | enabled by setting bits in /sys/modules/fscache/parameter/debug. | 54 | enabled by setting bits in /sys/modules/fscache/parameter/debug. |
| 55 | 55 | ||
| 56 | See Documentation/filesystems/caching/fscache.txt for more information. | 56 | See Documentation/filesystems/caching/fscache.txt for more information. |
| 57 | |||
| 58 | config FSCACHE_OBJECT_LIST | ||
| 59 | bool "Maintain global object list for debugging purposes" | ||
| 60 | depends on FSCACHE && PROC_FS | ||
| 61 | help | ||
| 62 | Maintain a global list of active fscache objects that can be | ||
| 63 | retrieved through /proc/fs/fscache/objects for debugging purposes | ||
diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile index 91571b95aacc..6d561531cb36 100644 --- a/fs/fscache/Makefile +++ b/fs/fscache/Makefile | |||
| @@ -15,5 +15,6 @@ fscache-y := \ | |||
| 15 | fscache-$(CONFIG_PROC_FS) += proc.o | 15 | fscache-$(CONFIG_PROC_FS) += proc.o |
| 16 | fscache-$(CONFIG_FSCACHE_STATS) += stats.o | 16 | fscache-$(CONFIG_FSCACHE_STATS) += stats.o |
| 17 | fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o | 17 | fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o |
| 18 | fscache-$(CONFIG_FSCACHE_OBJECT_LIST) += object-list.o | ||
| 18 | 19 | ||
| 19 | obj-$(CONFIG_FSCACHE) := fscache.o | 20 | obj-$(CONFIG_FSCACHE) := fscache.o |
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index e21985bbb1fb..6a3c48abd677 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c | |||
| @@ -263,6 +263,7 @@ int fscache_add_cache(struct fscache_cache *cache, | |||
| 263 | spin_lock(&cache->object_list_lock); | 263 | spin_lock(&cache->object_list_lock); |
| 264 | list_add_tail(&ifsdef->cache_link, &cache->object_list); | 264 | list_add_tail(&ifsdef->cache_link, &cache->object_list); |
| 265 | spin_unlock(&cache->object_list_lock); | 265 | spin_unlock(&cache->object_list_lock); |
| 266 | fscache_objlist_add(ifsdef); | ||
| 266 | 267 | ||
| 267 | /* add the cache's netfs definition index object to the top level index | 268 | /* add the cache's netfs definition index object to the top level index |
| 268 | * cookie as a known backing object */ | 269 | * cookie as a known backing object */ |
| @@ -380,11 +381,15 @@ void fscache_withdraw_cache(struct fscache_cache *cache) | |||
| 380 | 381 | ||
| 381 | /* make sure all pages pinned by operations on behalf of the netfs are | 382 | /* make sure all pages pinned by operations on behalf of the netfs are |
| 382 | * written to disk */ | 383 | * written to disk */ |
| 384 | fscache_stat(&fscache_n_cop_sync_cache); | ||
| 383 | cache->ops->sync_cache(cache); | 385 | cache->ops->sync_cache(cache); |
| 386 | fscache_stat_d(&fscache_n_cop_sync_cache); | ||
| 384 | 387 | ||
| 385 | /* dissociate all the netfs pages backed by this cache from the block | 388 | /* dissociate all the netfs pages backed by this cache from the block |
| 386 | * mappings in the cache */ | 389 | * mappings in the cache */ |
| 390 | fscache_stat(&fscache_n_cop_dissociate_pages); | ||
| 387 | cache->ops->dissociate_pages(cache); | 391 | cache->ops->dissociate_pages(cache); |
| 392 | fscache_stat_d(&fscache_n_cop_dissociate_pages); | ||
| 388 | 393 | ||
| 389 | /* we now have to destroy all the active objects pertaining to this | 394 | /* we now have to destroy all the active objects pertaining to this |
| 390 | * cache - which we do by passing them off to thread pool to be | 395 | * cache - which we do by passing them off to thread pool to be |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 72fd18f6c71f..990535071a8a 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
| @@ -36,6 +36,7 @@ void fscache_cookie_init_once(void *_cookie) | |||
| 36 | 36 | ||
| 37 | memset(cookie, 0, sizeof(*cookie)); | 37 | memset(cookie, 0, sizeof(*cookie)); |
| 38 | spin_lock_init(&cookie->lock); | 38 | spin_lock_init(&cookie->lock); |
| 39 | spin_lock_init(&cookie->stores_lock); | ||
| 39 | INIT_HLIST_HEAD(&cookie->backing_objects); | 40 | INIT_HLIST_HEAD(&cookie->backing_objects); |
| 40 | } | 41 | } |
| 41 | 42 | ||
| @@ -102,7 +103,9 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
| 102 | cookie->netfs_data = netfs_data; | 103 | cookie->netfs_data = netfs_data; |
| 103 | cookie->flags = 0; | 104 | cookie->flags = 0; |
| 104 | 105 | ||
| 105 | INIT_RADIX_TREE(&cookie->stores, GFP_NOFS); | 106 | /* radix tree insertion won't use the preallocation pool unless it's |
| 107 | * told it may not wait */ | ||
| 108 | INIT_RADIX_TREE(&cookie->stores, GFP_NOFS & ~__GFP_WAIT); | ||
| 106 | 109 | ||
| 107 | switch (cookie->def->type) { | 110 | switch (cookie->def->type) { |
| 108 | case FSCACHE_COOKIE_TYPE_INDEX: | 111 | case FSCACHE_COOKIE_TYPE_INDEX: |
| @@ -249,7 +252,9 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
| 249 | 252 | ||
| 250 | /* ask the cache to allocate an object (we may end up with duplicate | 253 | /* ask the cache to allocate an object (we may end up with duplicate |
| 251 | * objects at this stage, but we sort that out later) */ | 254 | * objects at this stage, but we sort that out later) */ |
| 255 | fscache_stat(&fscache_n_cop_alloc_object); | ||
| 252 | object = cache->ops->alloc_object(cache, cookie); | 256 | object = cache->ops->alloc_object(cache, cookie); |
| 257 | fscache_stat_d(&fscache_n_cop_alloc_object); | ||
| 253 | if (IS_ERR(object)) { | 258 | if (IS_ERR(object)) { |
| 254 | fscache_stat(&fscache_n_object_no_alloc); | 259 | fscache_stat(&fscache_n_object_no_alloc); |
| 255 | ret = PTR_ERR(object); | 260 | ret = PTR_ERR(object); |
| @@ -270,8 +275,11 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
| 270 | /* only attach if we managed to allocate all we needed, otherwise | 275 | /* only attach if we managed to allocate all we needed, otherwise |
| 271 | * discard the object we just allocated and instead use the one | 276 | * discard the object we just allocated and instead use the one |
| 272 | * attached to the cookie */ | 277 | * attached to the cookie */ |
| 273 | if (fscache_attach_object(cookie, object) < 0) | 278 | if (fscache_attach_object(cookie, object) < 0) { |
| 279 | fscache_stat(&fscache_n_cop_put_object); | ||
| 274 | cache->ops->put_object(object); | 280 | cache->ops->put_object(object); |
| 281 | fscache_stat_d(&fscache_n_cop_put_object); | ||
| 282 | } | ||
| 275 | 283 | ||
| 276 | _leave(" = 0"); | 284 | _leave(" = 0"); |
| 277 | return 0; | 285 | return 0; |
| @@ -287,7 +295,9 @@ object_already_extant: | |||
| 287 | return 0; | 295 | return 0; |
| 288 | 296 | ||
| 289 | error_put: | 297 | error_put: |
| 298 | fscache_stat(&fscache_n_cop_put_object); | ||
| 290 | cache->ops->put_object(object); | 299 | cache->ops->put_object(object); |
| 300 | fscache_stat_d(&fscache_n_cop_put_object); | ||
| 291 | error: | 301 | error: |
| 292 | _leave(" = %d", ret); | 302 | _leave(" = %d", ret); |
| 293 | return ret; | 303 | return ret; |
| @@ -349,6 +359,8 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
| 349 | object->cookie = cookie; | 359 | object->cookie = cookie; |
| 350 | atomic_inc(&cookie->usage); | 360 | atomic_inc(&cookie->usage); |
| 351 | hlist_add_head(&object->cookie_link, &cookie->backing_objects); | 361 | hlist_add_head(&object->cookie_link, &cookie->backing_objects); |
| 362 | |||
| 363 | fscache_objlist_add(object); | ||
| 352 | ret = 0; | 364 | ret = 0; |
| 353 | 365 | ||
| 354 | cant_attach_object: | 366 | cant_attach_object: |
| @@ -403,6 +415,8 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
| 403 | unsigned long event; | 415 | unsigned long event; |
| 404 | 416 | ||
| 405 | fscache_stat(&fscache_n_relinquishes); | 417 | fscache_stat(&fscache_n_relinquishes); |
| 418 | if (retire) | ||
| 419 | fscache_stat(&fscache_n_relinquishes_retire); | ||
| 406 | 420 | ||
| 407 | if (!cookie) { | 421 | if (!cookie) { |
| 408 | fscache_stat(&fscache_n_relinquishes_null); | 422 | fscache_stat(&fscache_n_relinquishes_null); |
| @@ -428,12 +442,8 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
| 428 | 442 | ||
| 429 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; | 443 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; |
| 430 | 444 | ||
| 431 | /* detach pointers back to the netfs */ | ||
| 432 | spin_lock(&cookie->lock); | 445 | spin_lock(&cookie->lock); |
| 433 | 446 | ||
| 434 | cookie->netfs_data = NULL; | ||
| 435 | cookie->def = NULL; | ||
| 436 | |||
| 437 | /* break links with all the active objects */ | 447 | /* break links with all the active objects */ |
| 438 | while (!hlist_empty(&cookie->backing_objects)) { | 448 | while (!hlist_empty(&cookie->backing_objects)) { |
| 439 | object = hlist_entry(cookie->backing_objects.first, | 449 | object = hlist_entry(cookie->backing_objects.first, |
| @@ -456,6 +466,10 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
| 456 | BUG(); | 466 | BUG(); |
| 457 | } | 467 | } |
| 458 | 468 | ||
| 469 | /* detach pointers back to the netfs */ | ||
| 470 | cookie->netfs_data = NULL; | ||
| 471 | cookie->def = NULL; | ||
| 472 | |||
| 459 | spin_unlock(&cookie->lock); | 473 | spin_unlock(&cookie->lock); |
| 460 | 474 | ||
| 461 | if (cookie->parent) { | 475 | if (cookie->parent) { |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 1c341304621f..edd7434ab6e5 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * - cache->object_list_lock | 17 | * - cache->object_list_lock |
| 18 | * - object->lock | 18 | * - object->lock |
| 19 | * - object->parent->lock | 19 | * - object->parent->lock |
| 20 | * - cookie->stores_lock | ||
| 20 | * - fscache_thread_lock | 21 | * - fscache_thread_lock |
| 21 | * | 22 | * |
| 22 | */ | 23 | */ |
| @@ -88,17 +89,31 @@ extern int fscache_wait_bit_interruptible(void *); | |||
| 88 | /* | 89 | /* |
| 89 | * object.c | 90 | * object.c |
| 90 | */ | 91 | */ |
| 92 | extern const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5]; | ||
| 93 | |||
| 91 | extern void fscache_withdrawing_object(struct fscache_cache *, | 94 | extern void fscache_withdrawing_object(struct fscache_cache *, |
| 92 | struct fscache_object *); | 95 | struct fscache_object *); |
| 93 | extern void fscache_enqueue_object(struct fscache_object *); | 96 | extern void fscache_enqueue_object(struct fscache_object *); |
| 94 | 97 | ||
| 95 | /* | 98 | /* |
| 99 | * object-list.c | ||
| 100 | */ | ||
| 101 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
| 102 | extern const struct file_operations fscache_objlist_fops; | ||
| 103 | |||
| 104 | extern void fscache_objlist_add(struct fscache_object *); | ||
| 105 | #else | ||
| 106 | #define fscache_objlist_add(object) do {} while(0) | ||
| 107 | #endif | ||
| 108 | |||
| 109 | /* | ||
| 96 | * operation.c | 110 | * operation.c |
| 97 | */ | 111 | */ |
| 98 | extern int fscache_submit_exclusive_op(struct fscache_object *, | 112 | extern int fscache_submit_exclusive_op(struct fscache_object *, |
| 99 | struct fscache_operation *); | 113 | struct fscache_operation *); |
| 100 | extern int fscache_submit_op(struct fscache_object *, | 114 | extern int fscache_submit_op(struct fscache_object *, |
| 101 | struct fscache_operation *); | 115 | struct fscache_operation *); |
| 116 | extern int fscache_cancel_op(struct fscache_operation *); | ||
| 102 | extern void fscache_abort_object(struct fscache_object *); | 117 | extern void fscache_abort_object(struct fscache_object *); |
| 103 | extern void fscache_start_operations(struct fscache_object *); | 118 | extern void fscache_start_operations(struct fscache_object *); |
| 104 | extern void fscache_operation_gc(struct work_struct *); | 119 | extern void fscache_operation_gc(struct work_struct *); |
| @@ -127,6 +142,8 @@ extern atomic_t fscache_n_op_enqueue; | |||
| 127 | extern atomic_t fscache_n_op_deferred_release; | 142 | extern atomic_t fscache_n_op_deferred_release; |
| 128 | extern atomic_t fscache_n_op_release; | 143 | extern atomic_t fscache_n_op_release; |
| 129 | extern atomic_t fscache_n_op_gc; | 144 | extern atomic_t fscache_n_op_gc; |
| 145 | extern atomic_t fscache_n_op_cancelled; | ||
| 146 | extern atomic_t fscache_n_op_rejected; | ||
| 130 | 147 | ||
| 131 | extern atomic_t fscache_n_attr_changed; | 148 | extern atomic_t fscache_n_attr_changed; |
| 132 | extern atomic_t fscache_n_attr_changed_ok; | 149 | extern atomic_t fscache_n_attr_changed_ok; |
| @@ -138,6 +155,8 @@ extern atomic_t fscache_n_allocs; | |||
| 138 | extern atomic_t fscache_n_allocs_ok; | 155 | extern atomic_t fscache_n_allocs_ok; |
| 139 | extern atomic_t fscache_n_allocs_wait; | 156 | extern atomic_t fscache_n_allocs_wait; |
| 140 | extern atomic_t fscache_n_allocs_nobufs; | 157 | extern atomic_t fscache_n_allocs_nobufs; |
| 158 | extern atomic_t fscache_n_allocs_intr; | ||
| 159 | extern atomic_t fscache_n_allocs_object_dead; | ||
| 141 | extern atomic_t fscache_n_alloc_ops; | 160 | extern atomic_t fscache_n_alloc_ops; |
| 142 | extern atomic_t fscache_n_alloc_op_waits; | 161 | extern atomic_t fscache_n_alloc_op_waits; |
| 143 | 162 | ||
| @@ -148,6 +167,7 @@ extern atomic_t fscache_n_retrievals_nodata; | |||
| 148 | extern atomic_t fscache_n_retrievals_nobufs; | 167 | extern atomic_t fscache_n_retrievals_nobufs; |
| 149 | extern atomic_t fscache_n_retrievals_intr; | 168 | extern atomic_t fscache_n_retrievals_intr; |
| 150 | extern atomic_t fscache_n_retrievals_nomem; | 169 | extern atomic_t fscache_n_retrievals_nomem; |
| 170 | extern atomic_t fscache_n_retrievals_object_dead; | ||
| 151 | extern atomic_t fscache_n_retrieval_ops; | 171 | extern atomic_t fscache_n_retrieval_ops; |
| 152 | extern atomic_t fscache_n_retrieval_op_waits; | 172 | extern atomic_t fscache_n_retrieval_op_waits; |
| 153 | 173 | ||
| @@ -158,6 +178,14 @@ extern atomic_t fscache_n_stores_nobufs; | |||
| 158 | extern atomic_t fscache_n_stores_oom; | 178 | extern atomic_t fscache_n_stores_oom; |
| 159 | extern atomic_t fscache_n_store_ops; | 179 | extern atomic_t fscache_n_store_ops; |
| 160 | extern atomic_t fscache_n_store_calls; | 180 | extern atomic_t fscache_n_store_calls; |
| 181 | extern atomic_t fscache_n_store_pages; | ||
| 182 | extern atomic_t fscache_n_store_radix_deletes; | ||
| 183 | extern atomic_t fscache_n_store_pages_over_limit; | ||
| 184 | |||
| 185 | extern atomic_t fscache_n_store_vmscan_not_storing; | ||
| 186 | extern atomic_t fscache_n_store_vmscan_gone; | ||
| 187 | extern atomic_t fscache_n_store_vmscan_busy; | ||
| 188 | extern atomic_t fscache_n_store_vmscan_cancelled; | ||
| 161 | 189 | ||
| 162 | extern atomic_t fscache_n_marks; | 190 | extern atomic_t fscache_n_marks; |
| 163 | extern atomic_t fscache_n_uncaches; | 191 | extern atomic_t fscache_n_uncaches; |
| @@ -176,6 +204,7 @@ extern atomic_t fscache_n_updates_run; | |||
| 176 | extern atomic_t fscache_n_relinquishes; | 204 | extern atomic_t fscache_n_relinquishes; |
| 177 | extern atomic_t fscache_n_relinquishes_null; | 205 | extern atomic_t fscache_n_relinquishes_null; |
| 178 | extern atomic_t fscache_n_relinquishes_waitcrt; | 206 | extern atomic_t fscache_n_relinquishes_waitcrt; |
| 207 | extern atomic_t fscache_n_relinquishes_retire; | ||
| 179 | 208 | ||
| 180 | extern atomic_t fscache_n_cookie_index; | 209 | extern atomic_t fscache_n_cookie_index; |
| 181 | extern atomic_t fscache_n_cookie_data; | 210 | extern atomic_t fscache_n_cookie_data; |
| @@ -186,6 +215,7 @@ extern atomic_t fscache_n_object_no_alloc; | |||
| 186 | extern atomic_t fscache_n_object_lookups; | 215 | extern atomic_t fscache_n_object_lookups; |
| 187 | extern atomic_t fscache_n_object_lookups_negative; | 216 | extern atomic_t fscache_n_object_lookups_negative; |
| 188 | extern atomic_t fscache_n_object_lookups_positive; | 217 | extern atomic_t fscache_n_object_lookups_positive; |
| 218 | extern atomic_t fscache_n_object_lookups_timed_out; | ||
| 189 | extern atomic_t fscache_n_object_created; | 219 | extern atomic_t fscache_n_object_created; |
| 190 | extern atomic_t fscache_n_object_avail; | 220 | extern atomic_t fscache_n_object_avail; |
| 191 | extern atomic_t fscache_n_object_dead; | 221 | extern atomic_t fscache_n_object_dead; |
| @@ -195,15 +225,41 @@ extern atomic_t fscache_n_checkaux_okay; | |||
| 195 | extern atomic_t fscache_n_checkaux_update; | 225 | extern atomic_t fscache_n_checkaux_update; |
| 196 | extern atomic_t fscache_n_checkaux_obsolete; | 226 | extern atomic_t fscache_n_checkaux_obsolete; |
| 197 | 227 | ||
| 228 | extern atomic_t fscache_n_cop_alloc_object; | ||
| 229 | extern atomic_t fscache_n_cop_lookup_object; | ||
| 230 | extern atomic_t fscache_n_cop_lookup_complete; | ||
| 231 | extern atomic_t fscache_n_cop_grab_object; | ||
| 232 | extern atomic_t fscache_n_cop_update_object; | ||
| 233 | extern atomic_t fscache_n_cop_drop_object; | ||
| 234 | extern atomic_t fscache_n_cop_put_object; | ||
| 235 | extern atomic_t fscache_n_cop_sync_cache; | ||
| 236 | extern atomic_t fscache_n_cop_attr_changed; | ||
| 237 | extern atomic_t fscache_n_cop_read_or_alloc_page; | ||
| 238 | extern atomic_t fscache_n_cop_read_or_alloc_pages; | ||
| 239 | extern atomic_t fscache_n_cop_allocate_page; | ||
| 240 | extern atomic_t fscache_n_cop_allocate_pages; | ||
| 241 | extern atomic_t fscache_n_cop_write_page; | ||
| 242 | extern atomic_t fscache_n_cop_uncache_page; | ||
| 243 | extern atomic_t fscache_n_cop_dissociate_pages; | ||
| 244 | |||
| 198 | static inline void fscache_stat(atomic_t *stat) | 245 | static inline void fscache_stat(atomic_t *stat) |
| 199 | { | 246 | { |
| 200 | atomic_inc(stat); | 247 | atomic_inc(stat); |
| 201 | } | 248 | } |
| 202 | 249 | ||
| 250 | static inline void fscache_stat_d(atomic_t *stat) | ||
| 251 | { | ||
| 252 | atomic_dec(stat); | ||
| 253 | } | ||
| 254 | |||
| 255 | #define __fscache_stat(stat) (stat) | ||
| 256 | |||
| 203 | extern const struct file_operations fscache_stats_fops; | 257 | extern const struct file_operations fscache_stats_fops; |
| 204 | #else | 258 | #else |
| 205 | 259 | ||
| 260 | #define __fscache_stat(stat) (NULL) | ||
| 206 | #define fscache_stat(stat) do {} while (0) | 261 | #define fscache_stat(stat) do {} while (0) |
| 262 | #define fscache_stat_d(stat) do {} while (0) | ||
| 207 | #endif | 263 | #endif |
| 208 | 264 | ||
| 209 | /* | 265 | /* |
diff --git a/fs/fscache/main.c b/fs/fscache/main.c index 4de41b597499..add6bdb53f04 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c | |||
| @@ -48,7 +48,7 @@ static int __init fscache_init(void) | |||
| 48 | { | 48 | { |
| 49 | int ret; | 49 | int ret; |
| 50 | 50 | ||
| 51 | ret = slow_work_register_user(); | 51 | ret = slow_work_register_user(THIS_MODULE); |
| 52 | if (ret < 0) | 52 | if (ret < 0) |
| 53 | goto error_slow_work; | 53 | goto error_slow_work; |
| 54 | 54 | ||
| @@ -80,7 +80,7 @@ error_kobj: | |||
| 80 | error_cookie_jar: | 80 | error_cookie_jar: |
| 81 | fscache_proc_cleanup(); | 81 | fscache_proc_cleanup(); |
| 82 | error_proc: | 82 | error_proc: |
| 83 | slow_work_unregister_user(); | 83 | slow_work_unregister_user(THIS_MODULE); |
| 84 | error_slow_work: | 84 | error_slow_work: |
| 85 | return ret; | 85 | return ret; |
| 86 | } | 86 | } |
| @@ -97,7 +97,7 @@ static void __exit fscache_exit(void) | |||
| 97 | kobject_put(fscache_root); | 97 | kobject_put(fscache_root); |
| 98 | kmem_cache_destroy(fscache_cookie_jar); | 98 | kmem_cache_destroy(fscache_cookie_jar); |
| 99 | fscache_proc_cleanup(); | 99 | fscache_proc_cleanup(); |
| 100 | slow_work_unregister_user(); | 100 | slow_work_unregister_user(THIS_MODULE); |
| 101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); | 101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); |
| 102 | } | 102 | } |
| 103 | 103 | ||
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c new file mode 100644 index 000000000000..e590242fa41a --- /dev/null +++ b/fs/fscache/object-list.c | |||
| @@ -0,0 +1,432 @@ | |||
| 1 | /* Global fscache object list maintainer and viewer | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define FSCACHE_DEBUG_LEVEL COOKIE | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/seq_file.h> | ||
| 15 | #include <linux/key.h> | ||
| 16 | #include <keys/user-type.h> | ||
| 17 | #include "internal.h" | ||
| 18 | |||
| 19 | static struct rb_root fscache_object_list; | ||
| 20 | static DEFINE_RWLOCK(fscache_object_list_lock); | ||
| 21 | |||
| 22 | struct fscache_objlist_data { | ||
| 23 | unsigned long config; /* display configuration */ | ||
| 24 | #define FSCACHE_OBJLIST_CONFIG_KEY 0x00000001 /* show object keys */ | ||
| 25 | #define FSCACHE_OBJLIST_CONFIG_AUX 0x00000002 /* show object auxdata */ | ||
| 26 | #define FSCACHE_OBJLIST_CONFIG_COOKIE 0x00000004 /* show objects with cookies */ | ||
| 27 | #define FSCACHE_OBJLIST_CONFIG_NOCOOKIE 0x00000008 /* show objects without cookies */ | ||
| 28 | #define FSCACHE_OBJLIST_CONFIG_BUSY 0x00000010 /* show busy objects */ | ||
| 29 | #define FSCACHE_OBJLIST_CONFIG_IDLE 0x00000020 /* show idle objects */ | ||
| 30 | #define FSCACHE_OBJLIST_CONFIG_PENDWR 0x00000040 /* show objects with pending writes */ | ||
| 31 | #define FSCACHE_OBJLIST_CONFIG_NOPENDWR 0x00000080 /* show objects without pending writes */ | ||
| 32 | #define FSCACHE_OBJLIST_CONFIG_READS 0x00000100 /* show objects with active reads */ | ||
| 33 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ | ||
| 34 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ | ||
| 35 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ | ||
| 36 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */ | ||
| 37 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */ | ||
| 38 | |||
| 39 | u8 buf[512]; /* key and aux data buffer */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Add an object to the object list | ||
| 44 | * - we use the address of the fscache_object structure as the key into the | ||
| 45 | * tree | ||
| 46 | */ | ||
| 47 | void fscache_objlist_add(struct fscache_object *obj) | ||
| 48 | { | ||
| 49 | struct fscache_object *xobj; | ||
| 50 | struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; | ||
| 51 | |||
| 52 | write_lock(&fscache_object_list_lock); | ||
| 53 | |||
| 54 | while (*p) { | ||
| 55 | parent = *p; | ||
| 56 | xobj = rb_entry(parent, struct fscache_object, objlist_link); | ||
| 57 | |||
| 58 | if (obj < xobj) | ||
| 59 | p = &(*p)->rb_left; | ||
| 60 | else if (obj > xobj) | ||
| 61 | p = &(*p)->rb_right; | ||
| 62 | else | ||
| 63 | BUG(); | ||
| 64 | } | ||
| 65 | |||
| 66 | rb_link_node(&obj->objlist_link, parent, p); | ||
| 67 | rb_insert_color(&obj->objlist_link, &fscache_object_list); | ||
| 68 | |||
| 69 | write_unlock(&fscache_object_list_lock); | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * fscache_object_destroy - Note that a cache object is about to be destroyed | ||
| 74 | * @object: The object to be destroyed | ||
| 75 | * | ||
| 76 | * Note the imminent destruction and deallocation of a cache object record. | ||
| 77 | */ | ||
| 78 | void fscache_object_destroy(struct fscache_object *obj) | ||
| 79 | { | ||
| 80 | write_lock(&fscache_object_list_lock); | ||
| 81 | |||
| 82 | BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); | ||
| 83 | rb_erase(&obj->objlist_link, &fscache_object_list); | ||
| 84 | |||
| 85 | write_unlock(&fscache_object_list_lock); | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL(fscache_object_destroy); | ||
| 88 | |||
| 89 | /* | ||
| 90 | * find the object in the tree on or after the specified index | ||
| 91 | */ | ||
| 92 | static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) | ||
| 93 | { | ||
| 94 | struct fscache_object *pobj, *obj, *minobj = NULL; | ||
| 95 | struct rb_node *p; | ||
| 96 | unsigned long pos; | ||
| 97 | |||
| 98 | if (*_pos >= (unsigned long) ERR_PTR(-ENOENT)) | ||
| 99 | return NULL; | ||
| 100 | pos = *_pos; | ||
| 101 | |||
| 102 | /* banners (can't represent line 0 by pos 0 as that would involve | ||
| 103 | * returning a NULL pointer) */ | ||
| 104 | if (pos == 0) | ||
| 105 | return (struct fscache_object *) ++(*_pos); | ||
| 106 | if (pos < 3) | ||
| 107 | return (struct fscache_object *)pos; | ||
| 108 | |||
| 109 | pobj = (struct fscache_object *)pos; | ||
| 110 | p = fscache_object_list.rb_node; | ||
| 111 | while (p) { | ||
| 112 | obj = rb_entry(p, struct fscache_object, objlist_link); | ||
| 113 | if (pobj < obj) { | ||
| 114 | if (!minobj || minobj > obj) | ||
| 115 | minobj = obj; | ||
| 116 | p = p->rb_left; | ||
| 117 | } else if (pobj > obj) { | ||
| 118 | p = p->rb_right; | ||
| 119 | } else { | ||
| 120 | minobj = obj; | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | obj = NULL; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (!minobj) | ||
| 127 | *_pos = (unsigned long) ERR_PTR(-ENOENT); | ||
| 128 | else if (minobj != obj) | ||
| 129 | *_pos = (unsigned long) minobj; | ||
| 130 | return minobj; | ||
| 131 | } | ||
| 132 | |||
| 133 | /* | ||
| 134 | * set up the iterator to start reading from the first line | ||
| 135 | */ | ||
| 136 | static void *fscache_objlist_start(struct seq_file *m, loff_t *_pos) | ||
| 137 | __acquires(&fscache_object_list_lock) | ||
| 138 | { | ||
| 139 | read_lock(&fscache_object_list_lock); | ||
| 140 | return fscache_objlist_lookup(_pos); | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * move to the next line | ||
| 145 | */ | ||
| 146 | static void *fscache_objlist_next(struct seq_file *m, void *v, loff_t *_pos) | ||
| 147 | { | ||
| 148 | (*_pos)++; | ||
| 149 | return fscache_objlist_lookup(_pos); | ||
| 150 | } | ||
| 151 | |||
| 152 | /* | ||
| 153 | * clean up after reading | ||
| 154 | */ | ||
| 155 | static void fscache_objlist_stop(struct seq_file *m, void *v) | ||
| 156 | __releases(&fscache_object_list_lock) | ||
| 157 | { | ||
| 158 | read_unlock(&fscache_object_list_lock); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* | ||
| 162 | * display an object | ||
| 163 | */ | ||
| 164 | static int fscache_objlist_show(struct seq_file *m, void *v) | ||
| 165 | { | ||
| 166 | struct fscache_objlist_data *data = m->private; | ||
| 167 | struct fscache_object *obj = v; | ||
| 168 | unsigned long config = data->config; | ||
| 169 | uint16_t keylen, auxlen; | ||
| 170 | char _type[3], *type; | ||
| 171 | bool no_cookie; | ||
| 172 | u8 *buf = data->buf, *p; | ||
| 173 | |||
| 174 | if ((unsigned long) v == 1) { | ||
| 175 | seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" | ||
| 176 | " EM EV F S" | ||
| 177 | " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); | ||
| 178 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
| 179 | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
| 180 | seq_puts(m, " "); | ||
| 181 | if (config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
| 182 | seq_puts(m, "OBJECT_KEY"); | ||
| 183 | if ((config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
| 184 | FSCACHE_OBJLIST_CONFIG_AUX)) == | ||
| 185 | (FSCACHE_OBJLIST_CONFIG_KEY | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
| 186 | seq_puts(m, ", "); | ||
| 187 | if (config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
| 188 | seq_puts(m, "AUX_DATA"); | ||
| 189 | seq_puts(m, "\n"); | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | if ((unsigned long) v == 2) { | ||
| 194 | seq_puts(m, "======== ======== ==== ===== === === === == =====" | ||
| 195 | " == == = =" | ||
| 196 | " | ================ == == ================"); | ||
| 197 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
| 198 | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
| 199 | seq_puts(m, " ================"); | ||
| 200 | seq_puts(m, "\n"); | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* filter out any unwanted objects */ | ||
| 205 | #define FILTER(criterion, _yes, _no) \ | ||
| 206 | do { \ | ||
| 207 | unsigned long yes = FSCACHE_OBJLIST_CONFIG_##_yes; \ | ||
| 208 | unsigned long no = FSCACHE_OBJLIST_CONFIG_##_no; \ | ||
| 209 | if (criterion) { \ | ||
| 210 | if (!(config & yes)) \ | ||
| 211 | return 0; \ | ||
| 212 | } else { \ | ||
| 213 | if (!(config & no)) \ | ||
| 214 | return 0; \ | ||
| 215 | } \ | ||
| 216 | } while(0) | ||
| 217 | |||
| 218 | if (~config) { | ||
| 219 | FILTER(obj->cookie, | ||
| 220 | COOKIE, NOCOOKIE); | ||
| 221 | FILTER(obj->state != FSCACHE_OBJECT_ACTIVE || | ||
| 222 | obj->n_ops != 0 || | ||
| 223 | obj->n_obj_ops != 0 || | ||
| 224 | obj->flags || | ||
| 225 | !list_empty(&obj->dependents), | ||
| 226 | BUSY, IDLE); | ||
| 227 | FILTER(test_bit(FSCACHE_OBJECT_PENDING_WRITE, &obj->flags), | ||
| 228 | PENDWR, NOPENDWR); | ||
| 229 | FILTER(atomic_read(&obj->n_reads), | ||
| 230 | READS, NOREADS); | ||
| 231 | FILTER(obj->events & obj->event_mask, | ||
| 232 | EVENTS, NOEVENTS); | ||
| 233 | FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW), | ||
| 234 | WORK, NOWORK); | ||
| 235 | } | ||
| 236 | |||
| 237 | seq_printf(m, | ||
| 238 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ", | ||
| 239 | obj->debug_id, | ||
| 240 | obj->parent ? obj->parent->debug_id : -1, | ||
| 241 | fscache_object_states_short[obj->state], | ||
| 242 | obj->n_children, | ||
| 243 | obj->n_ops, | ||
| 244 | obj->n_obj_ops, | ||
| 245 | obj->n_in_progress, | ||
| 246 | obj->n_exclusive, | ||
| 247 | atomic_read(&obj->n_reads), | ||
| 248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | ||
| 249 | obj->events, | ||
| 250 | obj->flags, | ||
| 251 | obj->work.flags); | ||
| 252 | |||
| 253 | no_cookie = true; | ||
| 254 | keylen = auxlen = 0; | ||
| 255 | if (obj->cookie) { | ||
| 256 | spin_lock(&obj->lock); | ||
| 257 | if (obj->cookie) { | ||
| 258 | switch (obj->cookie->def->type) { | ||
| 259 | case 0: | ||
| 260 | type = "IX"; | ||
| 261 | break; | ||
| 262 | case 1: | ||
| 263 | type = "DT"; | ||
| 264 | break; | ||
| 265 | default: | ||
| 266 | sprintf(_type, "%02u", | ||
| 267 | obj->cookie->def->type); | ||
| 268 | type = _type; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | |||
| 272 | seq_printf(m, "%-16s %s %2lx %16p", | ||
| 273 | obj->cookie->def->name, | ||
| 274 | type, | ||
| 275 | obj->cookie->flags, | ||
| 276 | obj->cookie->netfs_data); | ||
| 277 | |||
| 278 | if (obj->cookie->def->get_key && | ||
| 279 | config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
| 280 | keylen = obj->cookie->def->get_key( | ||
| 281 | obj->cookie->netfs_data, | ||
| 282 | buf, 400); | ||
| 283 | |||
| 284 | if (obj->cookie->def->get_aux && | ||
| 285 | config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
| 286 | auxlen = obj->cookie->def->get_aux( | ||
| 287 | obj->cookie->netfs_data, | ||
| 288 | buf + keylen, 512 - keylen); | ||
| 289 | |||
| 290 | no_cookie = false; | ||
| 291 | } | ||
| 292 | spin_unlock(&obj->lock); | ||
| 293 | |||
| 294 | if (!no_cookie && (keylen > 0 || auxlen > 0)) { | ||
| 295 | seq_printf(m, " "); | ||
| 296 | for (p = buf; keylen > 0; keylen--) | ||
| 297 | seq_printf(m, "%02x", *p++); | ||
| 298 | if (auxlen > 0) { | ||
| 299 | if (config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
| 300 | seq_printf(m, ", "); | ||
| 301 | for (; auxlen > 0; auxlen--) | ||
| 302 | seq_printf(m, "%02x", *p++); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | if (no_cookie) | ||
| 308 | seq_printf(m, "<no_cookie>\n"); | ||
| 309 | else | ||
| 310 | seq_printf(m, "\n"); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static const struct seq_operations fscache_objlist_ops = { | ||
| 315 | .start = fscache_objlist_start, | ||
| 316 | .stop = fscache_objlist_stop, | ||
| 317 | .next = fscache_objlist_next, | ||
| 318 | .show = fscache_objlist_show, | ||
| 319 | }; | ||
| 320 | |||
| 321 | /* | ||
| 322 | * get the configuration for filtering the list | ||
| 323 | */ | ||
| 324 | static void fscache_objlist_config(struct fscache_objlist_data *data) | ||
| 325 | { | ||
| 326 | #ifdef CONFIG_KEYS | ||
| 327 | struct user_key_payload *confkey; | ||
| 328 | unsigned long config; | ||
| 329 | struct key *key; | ||
| 330 | const char *buf; | ||
| 331 | int len; | ||
| 332 | |||
| 333 | key = request_key(&key_type_user, "fscache:objlist", NULL); | ||
| 334 | if (IS_ERR(key)) | ||
| 335 | goto no_config; | ||
| 336 | |||
| 337 | config = 0; | ||
| 338 | rcu_read_lock(); | ||
| 339 | |||
| 340 | confkey = key->payload.data; | ||
| 341 | buf = confkey->data; | ||
| 342 | |||
| 343 | for (len = confkey->datalen - 1; len >= 0; len--) { | ||
| 344 | switch (buf[len]) { | ||
| 345 | case 'K': config |= FSCACHE_OBJLIST_CONFIG_KEY; break; | ||
| 346 | case 'A': config |= FSCACHE_OBJLIST_CONFIG_AUX; break; | ||
| 347 | case 'C': config |= FSCACHE_OBJLIST_CONFIG_COOKIE; break; | ||
| 348 | case 'c': config |= FSCACHE_OBJLIST_CONFIG_NOCOOKIE; break; | ||
| 349 | case 'B': config |= FSCACHE_OBJLIST_CONFIG_BUSY; break; | ||
| 350 | case 'b': config |= FSCACHE_OBJLIST_CONFIG_IDLE; break; | ||
| 351 | case 'W': config |= FSCACHE_OBJLIST_CONFIG_PENDWR; break; | ||
| 352 | case 'w': config |= FSCACHE_OBJLIST_CONFIG_NOPENDWR; break; | ||
| 353 | case 'R': config |= FSCACHE_OBJLIST_CONFIG_READS; break; | ||
| 354 | case 'r': config |= FSCACHE_OBJLIST_CONFIG_NOREADS; break; | ||
| 355 | case 'S': config |= FSCACHE_OBJLIST_CONFIG_WORK; break; | ||
| 356 | case 's': config |= FSCACHE_OBJLIST_CONFIG_NOWORK; break; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | rcu_read_unlock(); | ||
| 361 | key_put(key); | ||
| 362 | |||
| 363 | if (!(config & (FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE))) | ||
| 364 | config |= FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE; | ||
| 365 | if (!(config & (FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE))) | ||
| 366 | config |= FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE; | ||
| 367 | if (!(config & (FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR))) | ||
| 368 | config |= FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR; | ||
| 369 | if (!(config & (FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS))) | ||
| 370 | config |= FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS; | ||
| 371 | if (!(config & (FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS))) | ||
| 372 | config |= FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS; | ||
| 373 | if (!(config & (FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK))) | ||
| 374 | config |= FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK; | ||
| 375 | |||
| 376 | data->config = config; | ||
| 377 | return; | ||
| 378 | |||
| 379 | no_config: | ||
| 380 | #endif | ||
| 381 | data->config = ULONG_MAX; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* | ||
| 385 | * open "/proc/fs/fscache/objects" to provide a list of active objects | ||
| 386 | * - can be configured by a user-defined key added to the caller's keyrings | ||
| 387 | */ | ||
| 388 | static int fscache_objlist_open(struct inode *inode, struct file *file) | ||
| 389 | { | ||
| 390 | struct fscache_objlist_data *data; | ||
| 391 | struct seq_file *m; | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | ret = seq_open(file, &fscache_objlist_ops); | ||
| 395 | if (ret < 0) | ||
| 396 | return ret; | ||
| 397 | |||
| 398 | m = file->private_data; | ||
| 399 | |||
| 400 | /* buffer for key extraction */ | ||
| 401 | data = kmalloc(sizeof(struct fscache_objlist_data), GFP_KERNEL); | ||
| 402 | if (!data) { | ||
| 403 | seq_release(inode, file); | ||
| 404 | return -ENOMEM; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* get the configuration key */ | ||
| 408 | fscache_objlist_config(data); | ||
| 409 | |||
| 410 | m->private = data; | ||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* | ||
| 415 | * clean up on close | ||
| 416 | */ | ||
| 417 | static int fscache_objlist_release(struct inode *inode, struct file *file) | ||
| 418 | { | ||
| 419 | struct seq_file *m = file->private_data; | ||
| 420 | |||
| 421 | kfree(m->private); | ||
| 422 | m->private = NULL; | ||
| 423 | return seq_release(inode, file); | ||
| 424 | } | ||
| 425 | |||
| 426 | const struct file_operations fscache_objlist_fops = { | ||
| 427 | .owner = THIS_MODULE, | ||
| 428 | .open = fscache_objlist_open, | ||
| 429 | .read = seq_read, | ||
| 430 | .llseek = seq_lseek, | ||
| 431 | .release = fscache_objlist_release, | ||
| 432 | }; | ||
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 392a41b1b79d..e513ac599c8e 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
| @@ -14,9 +14,10 @@ | |||
| 14 | 14 | ||
| 15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/seq_file.h> | ||
| 17 | #include "internal.h" | 18 | #include "internal.h" |
| 18 | 19 | ||
| 19 | const char *fscache_object_states[] = { | 20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
| 20 | [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", | 21 | [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", |
| 21 | [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", | 22 | [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", |
| 22 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", |
| @@ -33,9 +34,28 @@ const char *fscache_object_states[] = { | |||
| 33 | }; | 34 | }; |
| 34 | EXPORT_SYMBOL(fscache_object_states); | 35 | EXPORT_SYMBOL(fscache_object_states); |
| 35 | 36 | ||
| 37 | const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | ||
| 38 | [FSCACHE_OBJECT_INIT] = "INIT", | ||
| 39 | [FSCACHE_OBJECT_LOOKING_UP] = "LOOK", | ||
| 40 | [FSCACHE_OBJECT_CREATING] = "CRTN", | ||
| 41 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | ||
| 42 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | ||
| 43 | [FSCACHE_OBJECT_UPDATING] = "UPDT", | ||
| 44 | [FSCACHE_OBJECT_DYING] = "DYNG", | ||
| 45 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", | ||
| 46 | [FSCACHE_OBJECT_ABORT_INIT] = "ABTI", | ||
| 47 | [FSCACHE_OBJECT_RELEASING] = "RELS", | ||
| 48 | [FSCACHE_OBJECT_RECYCLING] = "RCYC", | ||
| 49 | [FSCACHE_OBJECT_WITHDRAWING] = "WTHD", | ||
| 50 | [FSCACHE_OBJECT_DEAD] = "DEAD", | ||
| 51 | }; | ||
| 52 | |||
| 36 | static void fscache_object_slow_work_put_ref(struct slow_work *); | 53 | static void fscache_object_slow_work_put_ref(struct slow_work *); |
| 37 | static int fscache_object_slow_work_get_ref(struct slow_work *); | 54 | static int fscache_object_slow_work_get_ref(struct slow_work *); |
| 38 | static void fscache_object_slow_work_execute(struct slow_work *); | 55 | static void fscache_object_slow_work_execute(struct slow_work *); |
| 56 | #ifdef CONFIG_SLOW_WORK_PROC | ||
| 57 | static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); | ||
| 58 | #endif | ||
| 39 | static void fscache_initialise_object(struct fscache_object *); | 59 | static void fscache_initialise_object(struct fscache_object *); |
| 40 | static void fscache_lookup_object(struct fscache_object *); | 60 | static void fscache_lookup_object(struct fscache_object *); |
| 41 | static void fscache_object_available(struct fscache_object *); | 61 | static void fscache_object_available(struct fscache_object *); |
| @@ -45,9 +65,13 @@ static void fscache_enqueue_dependents(struct fscache_object *); | |||
| 45 | static void fscache_dequeue_object(struct fscache_object *); | 65 | static void fscache_dequeue_object(struct fscache_object *); |
| 46 | 66 | ||
| 47 | const struct slow_work_ops fscache_object_slow_work_ops = { | 67 | const struct slow_work_ops fscache_object_slow_work_ops = { |
| 68 | .owner = THIS_MODULE, | ||
| 48 | .get_ref = fscache_object_slow_work_get_ref, | 69 | .get_ref = fscache_object_slow_work_get_ref, |
| 49 | .put_ref = fscache_object_slow_work_put_ref, | 70 | .put_ref = fscache_object_slow_work_put_ref, |
| 50 | .execute = fscache_object_slow_work_execute, | 71 | .execute = fscache_object_slow_work_execute, |
| 72 | #ifdef CONFIG_SLOW_WORK_PROC | ||
| 73 | .desc = fscache_object_slow_work_desc, | ||
| 74 | #endif | ||
| 51 | }; | 75 | }; |
| 52 | EXPORT_SYMBOL(fscache_object_slow_work_ops); | 76 | EXPORT_SYMBOL(fscache_object_slow_work_ops); |
| 53 | 77 | ||
| @@ -81,6 +105,7 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
| 81 | static void fscache_object_state_machine(struct fscache_object *object) | 105 | static void fscache_object_state_machine(struct fscache_object *object) |
| 82 | { | 106 | { |
| 83 | enum fscache_object_state new_state; | 107 | enum fscache_object_state new_state; |
| 108 | struct fscache_cookie *cookie; | ||
| 84 | 109 | ||
| 85 | ASSERT(object != NULL); | 110 | ASSERT(object != NULL); |
| 86 | 111 | ||
| @@ -120,20 +145,31 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
| 120 | case FSCACHE_OBJECT_UPDATING: | 145 | case FSCACHE_OBJECT_UPDATING: |
| 121 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | 146 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); |
| 122 | fscache_stat(&fscache_n_updates_run); | 147 | fscache_stat(&fscache_n_updates_run); |
| 148 | fscache_stat(&fscache_n_cop_update_object); | ||
| 123 | object->cache->ops->update_object(object); | 149 | object->cache->ops->update_object(object); |
| 150 | fscache_stat_d(&fscache_n_cop_update_object); | ||
| 124 | goto active_transit; | 151 | goto active_transit; |
| 125 | 152 | ||
| 126 | /* handle an object dying during lookup or creation */ | 153 | /* handle an object dying during lookup or creation */ |
| 127 | case FSCACHE_OBJECT_LC_DYING: | 154 | case FSCACHE_OBJECT_LC_DYING: |
| 128 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); | 155 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); |
| 156 | fscache_stat(&fscache_n_cop_lookup_complete); | ||
| 129 | object->cache->ops->lookup_complete(object); | 157 | object->cache->ops->lookup_complete(object); |
| 158 | fscache_stat_d(&fscache_n_cop_lookup_complete); | ||
| 130 | 159 | ||
| 131 | spin_lock(&object->lock); | 160 | spin_lock(&object->lock); |
| 132 | object->state = FSCACHE_OBJECT_DYING; | 161 | object->state = FSCACHE_OBJECT_DYING; |
| 133 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | 162 | cookie = object->cookie; |
| 134 | &object->cookie->flags)) | 163 | if (cookie) { |
| 135 | wake_up_bit(&object->cookie->flags, | 164 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, |
| 136 | FSCACHE_COOKIE_CREATING); | 165 | &cookie->flags)) |
| 166 | wake_up_bit(&cookie->flags, | ||
| 167 | FSCACHE_COOKIE_LOOKING_UP); | ||
| 168 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | ||
| 169 | &cookie->flags)) | ||
| 170 | wake_up_bit(&cookie->flags, | ||
| 171 | FSCACHE_COOKIE_CREATING); | ||
| 172 | } | ||
| 137 | spin_unlock(&object->lock); | 173 | spin_unlock(&object->lock); |
| 138 | 174 | ||
| 139 | fscache_done_parent_op(object); | 175 | fscache_done_parent_op(object); |
| @@ -165,6 +201,7 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
| 165 | } | 201 | } |
| 166 | spin_unlock(&object->lock); | 202 | spin_unlock(&object->lock); |
| 167 | fscache_enqueue_dependents(object); | 203 | fscache_enqueue_dependents(object); |
| 204 | fscache_start_operations(object); | ||
| 168 | goto terminal_transit; | 205 | goto terminal_transit; |
| 169 | 206 | ||
| 170 | /* handle an abort during initialisation */ | 207 | /* handle an abort during initialisation */ |
| @@ -316,14 +353,29 @@ static void fscache_object_slow_work_execute(struct slow_work *work) | |||
| 316 | 353 | ||
| 317 | _enter("{OBJ%x}", object->debug_id); | 354 | _enter("{OBJ%x}", object->debug_id); |
| 318 | 355 | ||
| 319 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
| 320 | |||
| 321 | start = jiffies; | 356 | start = jiffies; |
| 322 | fscache_object_state_machine(object); | 357 | fscache_object_state_machine(object); |
| 323 | fscache_hist(fscache_objs_histogram, start); | 358 | fscache_hist(fscache_objs_histogram, start); |
| 324 | if (object->events & object->event_mask) | 359 | if (object->events & object->event_mask) |
| 325 | fscache_enqueue_object(object); | 360 | fscache_enqueue_object(object); |
| 361 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
| 362 | } | ||
| 363 | |||
| 364 | /* | ||
| 365 | * describe an object for slow-work debugging | ||
| 366 | */ | ||
| 367 | #ifdef CONFIG_SLOW_WORK_PROC | ||
| 368 | static void fscache_object_slow_work_desc(struct slow_work *work, | ||
| 369 | struct seq_file *m) | ||
| 370 | { | ||
| 371 | struct fscache_object *object = | ||
| 372 | container_of(work, struct fscache_object, work); | ||
| 373 | |||
| 374 | seq_printf(m, "FSC: OBJ%x: %s", | ||
| 375 | object->debug_id, | ||
| 376 | fscache_object_states_short[object->state]); | ||
| 326 | } | 377 | } |
| 378 | #endif | ||
| 327 | 379 | ||
| 328 | /* | 380 | /* |
| 329 | * initialise an object | 381 | * initialise an object |
| @@ -376,7 +428,9 @@ static void fscache_initialise_object(struct fscache_object *object) | |||
| 376 | * binding on to us, so we need to make sure we don't | 428 | * binding on to us, so we need to make sure we don't |
| 377 | * add ourself to the list multiple times */ | 429 | * add ourself to the list multiple times */ |
| 378 | if (list_empty(&object->dep_link)) { | 430 | if (list_empty(&object->dep_link)) { |
| 431 | fscache_stat(&fscache_n_cop_grab_object); | ||
| 379 | object->cache->ops->grab_object(object); | 432 | object->cache->ops->grab_object(object); |
| 433 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
| 380 | list_add(&object->dep_link, | 434 | list_add(&object->dep_link, |
| 381 | &parent->dependents); | 435 | &parent->dependents); |
| 382 | 436 | ||
| @@ -414,6 +468,7 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
| 414 | { | 468 | { |
| 415 | struct fscache_cookie *cookie = object->cookie; | 469 | struct fscache_cookie *cookie = object->cookie; |
| 416 | struct fscache_object *parent; | 470 | struct fscache_object *parent; |
| 471 | int ret; | ||
| 417 | 472 | ||
| 418 | _enter(""); | 473 | _enter(""); |
| 419 | 474 | ||
| @@ -438,11 +493,20 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
| 438 | object->cache->tag->name); | 493 | object->cache->tag->name); |
| 439 | 494 | ||
| 440 | fscache_stat(&fscache_n_object_lookups); | 495 | fscache_stat(&fscache_n_object_lookups); |
| 441 | object->cache->ops->lookup_object(object); | 496 | fscache_stat(&fscache_n_cop_lookup_object); |
| 497 | ret = object->cache->ops->lookup_object(object); | ||
| 498 | fscache_stat_d(&fscache_n_cop_lookup_object); | ||
| 442 | 499 | ||
| 443 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) | 500 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) |
| 444 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | 501 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
| 445 | 502 | ||
| 503 | if (ret == -ETIMEDOUT) { | ||
| 504 | /* probably stuck behind another object, so move this one to | ||
| 505 | * the back of the queue */ | ||
| 506 | fscache_stat(&fscache_n_object_lookups_timed_out); | ||
| 507 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
| 508 | } | ||
| 509 | |||
| 446 | _leave(""); | 510 | _leave(""); |
| 447 | } | 511 | } |
| 448 | 512 | ||
| @@ -546,7 +610,8 @@ static void fscache_object_available(struct fscache_object *object) | |||
| 546 | 610 | ||
| 547 | spin_lock(&object->lock); | 611 | spin_lock(&object->lock); |
| 548 | 612 | ||
| 549 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)) | 613 | if (object->cookie && |
| 614 | test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)) | ||
| 550 | wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING); | 615 | wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING); |
| 551 | 616 | ||
| 552 | fscache_done_parent_op(object); | 617 | fscache_done_parent_op(object); |
| @@ -562,7 +627,9 @@ static void fscache_object_available(struct fscache_object *object) | |||
| 562 | } | 627 | } |
| 563 | spin_unlock(&object->lock); | 628 | spin_unlock(&object->lock); |
| 564 | 629 | ||
| 630 | fscache_stat(&fscache_n_cop_lookup_complete); | ||
| 565 | object->cache->ops->lookup_complete(object); | 631 | object->cache->ops->lookup_complete(object); |
| 632 | fscache_stat_d(&fscache_n_cop_lookup_complete); | ||
| 566 | fscache_enqueue_dependents(object); | 633 | fscache_enqueue_dependents(object); |
| 567 | 634 | ||
| 568 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); | 635 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); |
| @@ -581,11 +648,16 @@ static void fscache_drop_object(struct fscache_object *object) | |||
| 581 | 648 | ||
| 582 | _enter("{OBJ%x,%d}", object->debug_id, object->n_children); | 649 | _enter("{OBJ%x,%d}", object->debug_id, object->n_children); |
| 583 | 650 | ||
| 651 | ASSERTCMP(object->cookie, ==, NULL); | ||
| 652 | ASSERT(hlist_unhashed(&object->cookie_link)); | ||
| 653 | |||
| 584 | spin_lock(&cache->object_list_lock); | 654 | spin_lock(&cache->object_list_lock); |
| 585 | list_del_init(&object->cache_link); | 655 | list_del_init(&object->cache_link); |
| 586 | spin_unlock(&cache->object_list_lock); | 656 | spin_unlock(&cache->object_list_lock); |
| 587 | 657 | ||
| 658 | fscache_stat(&fscache_n_cop_drop_object); | ||
| 588 | cache->ops->drop_object(object); | 659 | cache->ops->drop_object(object); |
| 660 | fscache_stat_d(&fscache_n_cop_drop_object); | ||
| 589 | 661 | ||
| 590 | if (parent) { | 662 | if (parent) { |
| 591 | _debug("release parent OBJ%x {%d}", | 663 | _debug("release parent OBJ%x {%d}", |
| @@ -600,7 +672,9 @@ static void fscache_drop_object(struct fscache_object *object) | |||
| 600 | } | 672 | } |
| 601 | 673 | ||
| 602 | /* this just shifts the object release to the slow work processor */ | 674 | /* this just shifts the object release to the slow work processor */ |
| 675 | fscache_stat(&fscache_n_cop_put_object); | ||
| 603 | object->cache->ops->put_object(object); | 676 | object->cache->ops->put_object(object); |
| 677 | fscache_stat_d(&fscache_n_cop_put_object); | ||
| 604 | 678 | ||
| 605 | _leave(""); | 679 | _leave(""); |
| 606 | } | 680 | } |
| @@ -690,8 +764,12 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work) | |||
| 690 | { | 764 | { |
| 691 | struct fscache_object *object = | 765 | struct fscache_object *object = |
| 692 | container_of(work, struct fscache_object, work); | 766 | container_of(work, struct fscache_object, work); |
| 767 | int ret; | ||
| 693 | 768 | ||
| 694 | return object->cache->ops->grab_object(object) ? 0 : -EAGAIN; | 769 | fscache_stat(&fscache_n_cop_grab_object); |
| 770 | ret = object->cache->ops->grab_object(object) ? 0 : -EAGAIN; | ||
| 771 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
| 772 | return ret; | ||
| 695 | } | 773 | } |
| 696 | 774 | ||
| 697 | /* | 775 | /* |
| @@ -702,7 +780,9 @@ static void fscache_object_slow_work_put_ref(struct slow_work *work) | |||
| 702 | struct fscache_object *object = | 780 | struct fscache_object *object = |
| 703 | container_of(work, struct fscache_object, work); | 781 | container_of(work, struct fscache_object, work); |
| 704 | 782 | ||
| 705 | return object->cache->ops->put_object(object); | 783 | fscache_stat(&fscache_n_cop_put_object); |
| 784 | object->cache->ops->put_object(object); | ||
| 785 | fscache_stat_d(&fscache_n_cop_put_object); | ||
| 706 | } | 786 | } |
| 707 | 787 | ||
| 708 | /* | 788 | /* |
| @@ -739,7 +819,9 @@ static void fscache_enqueue_dependents(struct fscache_object *object) | |||
| 739 | 819 | ||
| 740 | /* sort onto appropriate lists */ | 820 | /* sort onto appropriate lists */ |
| 741 | fscache_enqueue_object(dep); | 821 | fscache_enqueue_object(dep); |
| 822 | fscache_stat(&fscache_n_cop_put_object); | ||
| 742 | dep->cache->ops->put_object(dep); | 823 | dep->cache->ops->put_object(dep); |
| 824 | fscache_stat_d(&fscache_n_cop_put_object); | ||
| 743 | 825 | ||
| 744 | if (!list_empty(&object->dependents)) | 826 | if (!list_empty(&object->dependents)) |
| 745 | cond_resched_lock(&object->lock); | 827 | cond_resched_lock(&object->lock); |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index e7f8d53b8b6b..313e79a14266 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #define FSCACHE_DEBUG_LEVEL OPERATION | 14 | #define FSCACHE_DEBUG_LEVEL OPERATION |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/seq_file.h> | ||
| 16 | #include "internal.h" | 17 | #include "internal.h" |
| 17 | 18 | ||
| 18 | atomic_t fscache_op_debug_id; | 19 | atomic_t fscache_op_debug_id; |
| @@ -31,32 +32,33 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
| 31 | _enter("{OBJ%x OP%x,%u}", | 32 | _enter("{OBJ%x OP%x,%u}", |
| 32 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); | 33 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); |
| 33 | 34 | ||
| 35 | fscache_set_op_state(op, "EnQ"); | ||
| 36 | |||
| 37 | ASSERT(list_empty(&op->pend_link)); | ||
| 34 | ASSERT(op->processor != NULL); | 38 | ASSERT(op->processor != NULL); |
| 35 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 39 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
| 36 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 40 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
| 37 | 41 | ||
| 38 | if (list_empty(&op->pend_link)) { | 42 | fscache_stat(&fscache_n_op_enqueue); |
| 39 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
| 40 | case FSCACHE_OP_FAST: | 44 | case FSCACHE_OP_FAST: |
| 41 | _debug("queue fast"); | 45 | _debug("queue fast"); |
| 42 | atomic_inc(&op->usage); | 46 | atomic_inc(&op->usage); |
| 43 | if (!schedule_work(&op->fast_work)) | 47 | if (!schedule_work(&op->fast_work)) |
| 44 | fscache_put_operation(op); | 48 | fscache_put_operation(op); |
| 45 | break; | 49 | break; |
| 46 | case FSCACHE_OP_SLOW: | 50 | case FSCACHE_OP_SLOW: |
| 47 | _debug("queue slow"); | 51 | _debug("queue slow"); |
| 48 | slow_work_enqueue(&op->slow_work); | 52 | slow_work_enqueue(&op->slow_work); |
| 49 | break; | 53 | break; |
| 50 | case FSCACHE_OP_MYTHREAD: | 54 | case FSCACHE_OP_MYTHREAD: |
| 51 | _debug("queue for caller's attention"); | 55 | _debug("queue for caller's attention"); |
| 52 | break; | 56 | break; |
| 53 | default: | 57 | default: |
| 54 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", | 58 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", |
| 55 | op->flags); | 59 | op->flags); |
| 56 | BUG(); | 60 | BUG(); |
| 57 | break; | 61 | break; |
| 58 | } | ||
| 59 | fscache_stat(&fscache_n_op_enqueue); | ||
| 60 | } | 62 | } |
| 61 | } | 63 | } |
| 62 | EXPORT_SYMBOL(fscache_enqueue_operation); | 64 | EXPORT_SYMBOL(fscache_enqueue_operation); |
| @@ -67,6 +69,8 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
| 67 | static void fscache_run_op(struct fscache_object *object, | 69 | static void fscache_run_op(struct fscache_object *object, |
| 68 | struct fscache_operation *op) | 70 | struct fscache_operation *op) |
| 69 | { | 71 | { |
| 72 | fscache_set_op_state(op, "Run"); | ||
| 73 | |||
| 70 | object->n_in_progress++; | 74 | object->n_in_progress++; |
| 71 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 75 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
| 72 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 76 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
| @@ -87,9 +91,12 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
| 87 | 91 | ||
| 88 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 92 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
| 89 | 93 | ||
| 94 | fscache_set_op_state(op, "SubmitX"); | ||
| 95 | |||
| 90 | spin_lock(&object->lock); | 96 | spin_lock(&object->lock); |
| 91 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 97 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
| 92 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 98 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
| 99 | ASSERT(list_empty(&op->pend_link)); | ||
| 93 | 100 | ||
| 94 | ret = -ENOBUFS; | 101 | ret = -ENOBUFS; |
| 95 | if (fscache_object_is_active(object)) { | 102 | if (fscache_object_is_active(object)) { |
| @@ -190,9 +197,12 @@ int fscache_submit_op(struct fscache_object *object, | |||
| 190 | 197 | ||
| 191 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 198 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
| 192 | 199 | ||
| 200 | fscache_set_op_state(op, "Submit"); | ||
| 201 | |||
| 193 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
| 194 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 203 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
| 195 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 204 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
| 205 | ASSERT(list_empty(&op->pend_link)); | ||
| 196 | 206 | ||
| 197 | ostate = object->state; | 207 | ostate = object->state; |
| 198 | smp_rmb(); | 208 | smp_rmb(); |
| @@ -222,6 +232,11 @@ int fscache_submit_op(struct fscache_object *object, | |||
| 222 | list_add_tail(&op->pend_link, &object->pending_ops); | 232 | list_add_tail(&op->pend_link, &object->pending_ops); |
| 223 | fscache_stat(&fscache_n_op_pend); | 233 | fscache_stat(&fscache_n_op_pend); |
| 224 | ret = 0; | 234 | ret = 0; |
| 235 | } else if (object->state == FSCACHE_OBJECT_DYING || | ||
| 236 | object->state == FSCACHE_OBJECT_LC_DYING || | ||
| 237 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | ||
| 238 | fscache_stat(&fscache_n_op_rejected); | ||
| 239 | ret = -ENOBUFS; | ||
| 225 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 240 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
| 226 | fscache_report_unexpected_submission(object, op, ostate); | 241 | fscache_report_unexpected_submission(object, op, ostate); |
| 227 | ASSERT(!fscache_object_is_active(object)); | 242 | ASSERT(!fscache_object_is_active(object)); |
| @@ -264,12 +279,7 @@ void fscache_start_operations(struct fscache_object *object) | |||
| 264 | stop = true; | 279 | stop = true; |
| 265 | } | 280 | } |
| 266 | list_del_init(&op->pend_link); | 281 | list_del_init(&op->pend_link); |
| 267 | object->n_in_progress++; | 282 | fscache_run_op(object, op); |
| 268 | |||
| 269 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
| 270 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
| 271 | if (op->processor) | ||
| 272 | fscache_enqueue_operation(op); | ||
| 273 | 283 | ||
| 274 | /* the pending queue was holding a ref on the object */ | 284 | /* the pending queue was holding a ref on the object */ |
| 275 | fscache_put_operation(op); | 285 | fscache_put_operation(op); |
| @@ -282,6 +292,36 @@ void fscache_start_operations(struct fscache_object *object) | |||
| 282 | } | 292 | } |
| 283 | 293 | ||
| 284 | /* | 294 | /* |
| 295 | * cancel an operation that's pending on an object | ||
| 296 | */ | ||
| 297 | int fscache_cancel_op(struct fscache_operation *op) | ||
| 298 | { | ||
| 299 | struct fscache_object *object = op->object; | ||
| 300 | int ret; | ||
| 301 | |||
| 302 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | ||
| 303 | |||
| 304 | spin_lock(&object->lock); | ||
| 305 | |||
| 306 | ret = -EBUSY; | ||
| 307 | if (!list_empty(&op->pend_link)) { | ||
| 308 | fscache_stat(&fscache_n_op_cancelled); | ||
| 309 | list_del_init(&op->pend_link); | ||
| 310 | object->n_ops--; | ||
| 311 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
| 312 | object->n_exclusive--; | ||
| 313 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
| 314 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
| 315 | fscache_put_operation(op); | ||
| 316 | ret = 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | spin_unlock(&object->lock); | ||
| 320 | _leave(" = %d", ret); | ||
| 321 | return ret; | ||
| 322 | } | ||
| 323 | |||
| 324 | /* | ||
| 285 | * release an operation | 325 | * release an operation |
| 286 | * - queues pending ops if this is the last in-progress op | 326 | * - queues pending ops if this is the last in-progress op |
| 287 | */ | 327 | */ |
| @@ -298,6 +338,8 @@ void fscache_put_operation(struct fscache_operation *op) | |||
| 298 | if (!atomic_dec_and_test(&op->usage)) | 338 | if (!atomic_dec_and_test(&op->usage)) |
| 299 | return; | 339 | return; |
| 300 | 340 | ||
| 341 | fscache_set_op_state(op, "Put"); | ||
| 342 | |||
| 301 | _debug("PUT OP"); | 343 | _debug("PUT OP"); |
| 302 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 344 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) |
| 303 | BUG(); | 345 | BUG(); |
| @@ -311,6 +353,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
| 311 | 353 | ||
| 312 | object = op->object; | 354 | object = op->object; |
| 313 | 355 | ||
| 356 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | ||
| 357 | atomic_dec(&object->n_reads); | ||
| 358 | |||
| 314 | /* now... we may get called with the object spinlock held, so we | 359 | /* now... we may get called with the object spinlock held, so we |
| 315 | * complete the cleanup here only if we can immediately acquire the | 360 | * complete the cleanup here only if we can immediately acquire the |
| 316 | * lock, and defer it otherwise */ | 361 | * lock, and defer it otherwise */ |
| @@ -452,8 +497,27 @@ static void fscache_op_execute(struct slow_work *work) | |||
| 452 | _leave(""); | 497 | _leave(""); |
| 453 | } | 498 | } |
| 454 | 499 | ||
| 500 | /* | ||
| 501 | * describe an operation for slow-work debugging | ||
| 502 | */ | ||
| 503 | #ifdef CONFIG_SLOW_WORK_PROC | ||
| 504 | static void fscache_op_desc(struct slow_work *work, struct seq_file *m) | ||
| 505 | { | ||
| 506 | struct fscache_operation *op = | ||
| 507 | container_of(work, struct fscache_operation, slow_work); | ||
| 508 | |||
| 509 | seq_printf(m, "FSC: OBJ%x OP%x: %s/%s fl=%lx", | ||
| 510 | op->object->debug_id, op->debug_id, | ||
| 511 | op->name, op->state, op->flags); | ||
| 512 | } | ||
| 513 | #endif | ||
| 514 | |||
| 455 | const struct slow_work_ops fscache_op_slow_work_ops = { | 515 | const struct slow_work_ops fscache_op_slow_work_ops = { |
| 516 | .owner = THIS_MODULE, | ||
| 456 | .get_ref = fscache_op_get_ref, | 517 | .get_ref = fscache_op_get_ref, |
| 457 | .put_ref = fscache_op_put_ref, | 518 | .put_ref = fscache_op_put_ref, |
| 458 | .execute = fscache_op_execute, | 519 | .execute = fscache_op_execute, |
| 520 | #ifdef CONFIG_SLOW_WORK_PROC | ||
| 521 | .desc = fscache_op_desc, | ||
| 522 | #endif | ||
| 459 | }; | 523 | }; |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 2568e0eb644f..c598ea4c4e7d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
| @@ -43,18 +43,102 @@ void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *pa | |||
| 43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); | 43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * note that a page has finished being written to the cache | 46 | * decide whether a page can be released, possibly by cancelling a store to it |
| 47 | * - we're allowed to sleep if __GFP_WAIT is flagged | ||
| 47 | */ | 48 | */ |
| 48 | static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *page) | 49 | bool __fscache_maybe_release_page(struct fscache_cookie *cookie, |
| 50 | struct page *page, | ||
| 51 | gfp_t gfp) | ||
| 49 | { | 52 | { |
| 50 | struct page *xpage; | 53 | struct page *xpage; |
| 54 | void *val; | ||
| 55 | |||
| 56 | _enter("%p,%p,%x", cookie, page, gfp); | ||
| 57 | |||
| 58 | rcu_read_lock(); | ||
| 59 | val = radix_tree_lookup(&cookie->stores, page->index); | ||
| 60 | if (!val) { | ||
| 61 | rcu_read_unlock(); | ||
| 62 | fscache_stat(&fscache_n_store_vmscan_not_storing); | ||
| 63 | __fscache_uncache_page(cookie, page); | ||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* see if the page is actually undergoing storage - if so we can't get | ||
| 68 | * rid of it till the cache has finished with it */ | ||
| 69 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
| 70 | FSCACHE_COOKIE_STORING_TAG)) { | ||
| 71 | rcu_read_unlock(); | ||
| 72 | goto page_busy; | ||
| 73 | } | ||
| 74 | |||
| 75 | /* the page is pending storage, so we attempt to cancel the store and | ||
| 76 | * discard the store request so that the page can be reclaimed */ | ||
| 77 | spin_lock(&cookie->stores_lock); | ||
| 78 | rcu_read_unlock(); | ||
| 79 | |||
| 80 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
| 81 | FSCACHE_COOKIE_STORING_TAG)) { | ||
| 82 | /* the page started to undergo storage whilst we were looking, | ||
| 83 | * so now we can only wait or return */ | ||
| 84 | spin_unlock(&cookie->stores_lock); | ||
| 85 | goto page_busy; | ||
| 86 | } | ||
| 51 | 87 | ||
| 52 | spin_lock(&cookie->lock); | ||
| 53 | xpage = radix_tree_delete(&cookie->stores, page->index); | 88 | xpage = radix_tree_delete(&cookie->stores, page->index); |
| 54 | spin_unlock(&cookie->lock); | 89 | spin_unlock(&cookie->stores_lock); |
| 55 | ASSERT(xpage != NULL); | 90 | |
| 91 | if (xpage) { | ||
| 92 | fscache_stat(&fscache_n_store_vmscan_cancelled); | ||
| 93 | fscache_stat(&fscache_n_store_radix_deletes); | ||
| 94 | ASSERTCMP(xpage, ==, page); | ||
| 95 | } else { | ||
| 96 | fscache_stat(&fscache_n_store_vmscan_gone); | ||
| 97 | } | ||
| 56 | 98 | ||
| 57 | wake_up_bit(&cookie->flags, 0); | 99 | wake_up_bit(&cookie->flags, 0); |
| 100 | if (xpage) | ||
| 101 | page_cache_release(xpage); | ||
| 102 | __fscache_uncache_page(cookie, page); | ||
| 103 | return true; | ||
| 104 | |||
| 105 | page_busy: | ||
| 106 | /* we might want to wait here, but that could deadlock the allocator as | ||
| 107 | * the slow-work threads writing to the cache may all end up sleeping | ||
| 108 | * on memory allocation */ | ||
| 109 | fscache_stat(&fscache_n_store_vmscan_busy); | ||
| 110 | return false; | ||
| 111 | } | ||
| 112 | EXPORT_SYMBOL(__fscache_maybe_release_page); | ||
| 113 | |||
| 114 | /* | ||
| 115 | * note that a page has finished being written to the cache | ||
| 116 | */ | ||
| 117 | static void fscache_end_page_write(struct fscache_object *object, | ||
| 118 | struct page *page) | ||
| 119 | { | ||
| 120 | struct fscache_cookie *cookie; | ||
| 121 | struct page *xpage = NULL; | ||
| 122 | |||
| 123 | spin_lock(&object->lock); | ||
| 124 | cookie = object->cookie; | ||
| 125 | if (cookie) { | ||
| 126 | /* delete the page from the tree if it is now no longer | ||
| 127 | * pending */ | ||
| 128 | spin_lock(&cookie->stores_lock); | ||
| 129 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
| 130 | FSCACHE_COOKIE_STORING_TAG); | ||
| 131 | if (!radix_tree_tag_get(&cookie->stores, page->index, | ||
| 132 | FSCACHE_COOKIE_PENDING_TAG)) { | ||
| 133 | fscache_stat(&fscache_n_store_radix_deletes); | ||
| 134 | xpage = radix_tree_delete(&cookie->stores, page->index); | ||
| 135 | } | ||
| 136 | spin_unlock(&cookie->stores_lock); | ||
| 137 | wake_up_bit(&cookie->flags, 0); | ||
| 138 | } | ||
| 139 | spin_unlock(&object->lock); | ||
| 140 | if (xpage) | ||
| 141 | page_cache_release(xpage); | ||
| 58 | } | 142 | } |
| 59 | 143 | ||
| 60 | /* | 144 | /* |
| @@ -63,14 +147,21 @@ static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *p | |||
| 63 | static void fscache_attr_changed_op(struct fscache_operation *op) | 147 | static void fscache_attr_changed_op(struct fscache_operation *op) |
| 64 | { | 148 | { |
| 65 | struct fscache_object *object = op->object; | 149 | struct fscache_object *object = op->object; |
| 150 | int ret; | ||
| 66 | 151 | ||
| 67 | _enter("{OBJ%x OP%x}", object->debug_id, op->debug_id); | 152 | _enter("{OBJ%x OP%x}", object->debug_id, op->debug_id); |
| 68 | 153 | ||
| 69 | fscache_stat(&fscache_n_attr_changed_calls); | 154 | fscache_stat(&fscache_n_attr_changed_calls); |
| 70 | 155 | ||
| 71 | if (fscache_object_is_active(object) && | 156 | if (fscache_object_is_active(object)) { |
| 72 | object->cache->ops->attr_changed(object) < 0) | 157 | fscache_set_op_state(op, "CallFS"); |
| 73 | fscache_abort_object(object); | 158 | fscache_stat(&fscache_n_cop_attr_changed); |
| 159 | ret = object->cache->ops->attr_changed(object); | ||
| 160 | fscache_stat_d(&fscache_n_cop_attr_changed); | ||
| 161 | fscache_set_op_state(op, "Done"); | ||
| 162 | if (ret < 0) | ||
| 163 | fscache_abort_object(object); | ||
| 164 | } | ||
| 74 | 165 | ||
| 75 | _leave(""); | 166 | _leave(""); |
| 76 | } | 167 | } |
| @@ -99,6 +190,7 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
| 99 | fscache_operation_init(op, NULL); | 190 | fscache_operation_init(op, NULL); |
| 100 | fscache_operation_init_slow(op, fscache_attr_changed_op); | 191 | fscache_operation_init_slow(op, fscache_attr_changed_op); |
| 101 | op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE); | 192 | op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE); |
| 193 | fscache_set_op_name(op, "Attr"); | ||
| 102 | 194 | ||
| 103 | spin_lock(&cookie->lock); | 195 | spin_lock(&cookie->lock); |
| 104 | 196 | ||
| @@ -184,6 +276,7 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
| 184 | op->start_time = jiffies; | 276 | op->start_time = jiffies; |
| 185 | INIT_WORK(&op->op.fast_work, fscache_retrieval_work); | 277 | INIT_WORK(&op->op.fast_work, fscache_retrieval_work); |
| 186 | INIT_LIST_HEAD(&op->to_do); | 278 | INIT_LIST_HEAD(&op->to_do); |
| 279 | fscache_set_op_name(&op->op, "Retr"); | ||
| 187 | return op; | 280 | return op; |
| 188 | } | 281 | } |
| 189 | 282 | ||
| @@ -221,6 +314,43 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | |||
| 221 | } | 314 | } |
| 222 | 315 | ||
| 223 | /* | 316 | /* |
| 317 | * wait for an object to become active (or dead) | ||
| 318 | */ | ||
| 319 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | ||
| 320 | struct fscache_retrieval *op, | ||
| 321 | atomic_t *stat_op_waits, | ||
| 322 | atomic_t *stat_object_dead) | ||
| 323 | { | ||
| 324 | int ret; | ||
| 325 | |||
| 326 | if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags)) | ||
| 327 | goto check_if_dead; | ||
| 328 | |||
| 329 | _debug(">>> WT"); | ||
| 330 | fscache_stat(stat_op_waits); | ||
| 331 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
| 332 | fscache_wait_bit_interruptible, | ||
| 333 | TASK_INTERRUPTIBLE) < 0) { | ||
| 334 | ret = fscache_cancel_op(&op->op); | ||
| 335 | if (ret == 0) | ||
| 336 | return -ERESTARTSYS; | ||
| 337 | |||
| 338 | /* it's been removed from the pending queue by another party, | ||
| 339 | * so we should get to run shortly */ | ||
| 340 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
| 341 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
| 342 | } | ||
| 343 | _debug("<<< GO"); | ||
| 344 | |||
| 345 | check_if_dead: | ||
| 346 | if (unlikely(fscache_object_is_dead(object))) { | ||
| 347 | fscache_stat(stat_object_dead); | ||
| 348 | return -ENOBUFS; | ||
| 349 | } | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 224 | * read a page from the cache or allocate a block in which to store it | 354 | * read a page from the cache or allocate a block in which to store it |
| 225 | * - we return: | 355 | * - we return: |
| 226 | * -ENOMEM - out of memory, nothing done | 356 | * -ENOMEM - out of memory, nothing done |
| @@ -257,6 +387,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
| 257 | _leave(" = -ENOMEM"); | 387 | _leave(" = -ENOMEM"); |
| 258 | return -ENOMEM; | 388 | return -ENOMEM; |
| 259 | } | 389 | } |
| 390 | fscache_set_op_name(&op->op, "RetrRA1"); | ||
| 260 | 391 | ||
| 261 | spin_lock(&cookie->lock); | 392 | spin_lock(&cookie->lock); |
| 262 | 393 | ||
| @@ -267,6 +398,9 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
| 267 | 398 | ||
| 268 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 399 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); |
| 269 | 400 | ||
| 401 | atomic_inc(&object->n_reads); | ||
| 402 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | ||
| 403 | |||
| 270 | if (fscache_submit_op(object, &op->op) < 0) | 404 | if (fscache_submit_op(object, &op->op) < 0) |
| 271 | goto nobufs_unlock; | 405 | goto nobufs_unlock; |
| 272 | spin_unlock(&cookie->lock); | 406 | spin_unlock(&cookie->lock); |
| @@ -279,23 +413,27 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
| 279 | 413 | ||
| 280 | /* we wait for the operation to become active, and then process it | 414 | /* we wait for the operation to become active, and then process it |
| 281 | * *here*, in this thread, and not in the thread pool */ | 415 | * *here*, in this thread, and not in the thread pool */ |
| 282 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 416 | ret = fscache_wait_for_retrieval_activation( |
| 283 | _debug(">>> WT"); | 417 | object, op, |
| 284 | fscache_stat(&fscache_n_retrieval_op_waits); | 418 | __fscache_stat(&fscache_n_retrieval_op_waits), |
| 285 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 419 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
| 286 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 420 | if (ret < 0) |
| 287 | _debug("<<< GO"); | 421 | goto error; |
| 288 | } | ||
| 289 | 422 | ||
| 290 | /* ask the cache to honour the operation */ | 423 | /* ask the cache to honour the operation */ |
| 291 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { | 424 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
| 425 | fscache_stat(&fscache_n_cop_allocate_page); | ||
| 292 | ret = object->cache->ops->allocate_page(op, page, gfp); | 426 | ret = object->cache->ops->allocate_page(op, page, gfp); |
| 427 | fscache_stat_d(&fscache_n_cop_allocate_page); | ||
| 293 | if (ret == 0) | 428 | if (ret == 0) |
| 294 | ret = -ENODATA; | 429 | ret = -ENODATA; |
| 295 | } else { | 430 | } else { |
| 431 | fscache_stat(&fscache_n_cop_read_or_alloc_page); | ||
| 296 | ret = object->cache->ops->read_or_alloc_page(op, page, gfp); | 432 | ret = object->cache->ops->read_or_alloc_page(op, page, gfp); |
| 433 | fscache_stat_d(&fscache_n_cop_read_or_alloc_page); | ||
| 297 | } | 434 | } |
| 298 | 435 | ||
| 436 | error: | ||
| 299 | if (ret == -ENOMEM) | 437 | if (ret == -ENOMEM) |
| 300 | fscache_stat(&fscache_n_retrievals_nomem); | 438 | fscache_stat(&fscache_n_retrievals_nomem); |
| 301 | else if (ret == -ERESTARTSYS) | 439 | else if (ret == -ERESTARTSYS) |
| @@ -347,7 +485,6 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
| 347 | void *context, | 485 | void *context, |
| 348 | gfp_t gfp) | 486 | gfp_t gfp) |
| 349 | { | 487 | { |
| 350 | fscache_pages_retrieval_func_t func; | ||
| 351 | struct fscache_retrieval *op; | 488 | struct fscache_retrieval *op; |
| 352 | struct fscache_object *object; | 489 | struct fscache_object *object; |
| 353 | int ret; | 490 | int ret; |
| @@ -369,6 +506,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
| 369 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 506 | op = fscache_alloc_retrieval(mapping, end_io_func, context); |
| 370 | if (!op) | 507 | if (!op) |
| 371 | return -ENOMEM; | 508 | return -ENOMEM; |
| 509 | fscache_set_op_name(&op->op, "RetrRAN"); | ||
| 372 | 510 | ||
| 373 | spin_lock(&cookie->lock); | 511 | spin_lock(&cookie->lock); |
| 374 | 512 | ||
| @@ -377,6 +515,9 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
| 377 | object = hlist_entry(cookie->backing_objects.first, | 515 | object = hlist_entry(cookie->backing_objects.first, |
| 378 | struct fscache_object, cookie_link); | 516 | struct fscache_object, cookie_link); |
| 379 | 517 | ||
| 518 | atomic_inc(&object->n_reads); | ||
| 519 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | ||
| 520 | |||
| 380 | if (fscache_submit_op(object, &op->op) < 0) | 521 | if (fscache_submit_op(object, &op->op) < 0) |
| 381 | goto nobufs_unlock; | 522 | goto nobufs_unlock; |
| 382 | spin_unlock(&cookie->lock); | 523 | spin_unlock(&cookie->lock); |
| @@ -389,21 +530,27 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
| 389 | 530 | ||
| 390 | /* we wait for the operation to become active, and then process it | 531 | /* we wait for the operation to become active, and then process it |
| 391 | * *here*, in this thread, and not in the thread pool */ | 532 | * *here*, in this thread, and not in the thread pool */ |
| 392 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 533 | ret = fscache_wait_for_retrieval_activation( |
| 393 | _debug(">>> WT"); | 534 | object, op, |
| 394 | fscache_stat(&fscache_n_retrieval_op_waits); | 535 | __fscache_stat(&fscache_n_retrieval_op_waits), |
| 395 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 536 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
| 396 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 537 | if (ret < 0) |
| 397 | _debug("<<< GO"); | 538 | goto error; |
| 398 | } | ||
| 399 | 539 | ||
| 400 | /* ask the cache to honour the operation */ | 540 | /* ask the cache to honour the operation */ |
| 401 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) | 541 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
| 402 | func = object->cache->ops->allocate_pages; | 542 | fscache_stat(&fscache_n_cop_allocate_pages); |
| 403 | else | 543 | ret = object->cache->ops->allocate_pages( |
| 404 | func = object->cache->ops->read_or_alloc_pages; | 544 | op, pages, nr_pages, gfp); |
| 405 | ret = func(op, pages, nr_pages, gfp); | 545 | fscache_stat_d(&fscache_n_cop_allocate_pages); |
| 546 | } else { | ||
| 547 | fscache_stat(&fscache_n_cop_read_or_alloc_pages); | ||
| 548 | ret = object->cache->ops->read_or_alloc_pages( | ||
| 549 | op, pages, nr_pages, gfp); | ||
| 550 | fscache_stat_d(&fscache_n_cop_read_or_alloc_pages); | ||
| 551 | } | ||
| 406 | 552 | ||
| 553 | error: | ||
| 407 | if (ret == -ENOMEM) | 554 | if (ret == -ENOMEM) |
| 408 | fscache_stat(&fscache_n_retrievals_nomem); | 555 | fscache_stat(&fscache_n_retrievals_nomem); |
| 409 | else if (ret == -ERESTARTSYS) | 556 | else if (ret == -ERESTARTSYS) |
| @@ -461,6 +608,7 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
| 461 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 608 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); |
| 462 | if (!op) | 609 | if (!op) |
| 463 | return -ENOMEM; | 610 | return -ENOMEM; |
| 611 | fscache_set_op_name(&op->op, "RetrAL1"); | ||
| 464 | 612 | ||
| 465 | spin_lock(&cookie->lock); | 613 | spin_lock(&cookie->lock); |
| 466 | 614 | ||
| @@ -475,18 +623,22 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
| 475 | 623 | ||
| 476 | fscache_stat(&fscache_n_alloc_ops); | 624 | fscache_stat(&fscache_n_alloc_ops); |
| 477 | 625 | ||
| 478 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 626 | ret = fscache_wait_for_retrieval_activation( |
| 479 | _debug(">>> WT"); | 627 | object, op, |
| 480 | fscache_stat(&fscache_n_alloc_op_waits); | 628 | __fscache_stat(&fscache_n_alloc_op_waits), |
| 481 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 629 | __fscache_stat(&fscache_n_allocs_object_dead)); |
| 482 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 630 | if (ret < 0) |
| 483 | _debug("<<< GO"); | 631 | goto error; |
| 484 | } | ||
| 485 | 632 | ||
| 486 | /* ask the cache to honour the operation */ | 633 | /* ask the cache to honour the operation */ |
| 634 | fscache_stat(&fscache_n_cop_allocate_page); | ||
| 487 | ret = object->cache->ops->allocate_page(op, page, gfp); | 635 | ret = object->cache->ops->allocate_page(op, page, gfp); |
| 636 | fscache_stat_d(&fscache_n_cop_allocate_page); | ||
| 488 | 637 | ||
| 489 | if (ret < 0) | 638 | error: |
| 639 | if (ret == -ERESTARTSYS) | ||
| 640 | fscache_stat(&fscache_n_allocs_intr); | ||
| 641 | else if (ret < 0) | ||
| 490 | fscache_stat(&fscache_n_allocs_nobufs); | 642 | fscache_stat(&fscache_n_allocs_nobufs); |
| 491 | else | 643 | else |
| 492 | fscache_stat(&fscache_n_allocs_ok); | 644 | fscache_stat(&fscache_n_allocs_ok); |
| @@ -521,7 +673,7 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
| 521 | struct fscache_storage *op = | 673 | struct fscache_storage *op = |
| 522 | container_of(_op, struct fscache_storage, op); | 674 | container_of(_op, struct fscache_storage, op); |
| 523 | struct fscache_object *object = op->op.object; | 675 | struct fscache_object *object = op->op.object; |
| 524 | struct fscache_cookie *cookie = object->cookie; | 676 | struct fscache_cookie *cookie; |
| 525 | struct page *page; | 677 | struct page *page; |
| 526 | unsigned n; | 678 | unsigned n; |
| 527 | void *results[1]; | 679 | void *results[1]; |
| @@ -529,16 +681,19 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
| 529 | 681 | ||
| 530 | _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); | 682 | _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); |
| 531 | 683 | ||
| 532 | spin_lock(&cookie->lock); | 684 | fscache_set_op_state(&op->op, "GetPage"); |
| 685 | |||
| 533 | spin_lock(&object->lock); | 686 | spin_lock(&object->lock); |
| 687 | cookie = object->cookie; | ||
| 534 | 688 | ||
| 535 | if (!fscache_object_is_active(object)) { | 689 | if (!fscache_object_is_active(object) || !cookie) { |
| 536 | spin_unlock(&object->lock); | 690 | spin_unlock(&object->lock); |
| 537 | spin_unlock(&cookie->lock); | ||
| 538 | _leave(""); | 691 | _leave(""); |
| 539 | return; | 692 | return; |
| 540 | } | 693 | } |
| 541 | 694 | ||
| 695 | spin_lock(&cookie->stores_lock); | ||
| 696 | |||
| 542 | fscache_stat(&fscache_n_store_calls); | 697 | fscache_stat(&fscache_n_store_calls); |
| 543 | 698 | ||
| 544 | /* find a page to store */ | 699 | /* find a page to store */ |
| @@ -549,23 +704,35 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
| 549 | goto superseded; | 704 | goto superseded; |
| 550 | page = results[0]; | 705 | page = results[0]; |
| 551 | _debug("gang %d [%lx]", n, page->index); | 706 | _debug("gang %d [%lx]", n, page->index); |
| 552 | if (page->index > op->store_limit) | 707 | if (page->index > op->store_limit) { |
| 708 | fscache_stat(&fscache_n_store_pages_over_limit); | ||
| 553 | goto superseded; | 709 | goto superseded; |
| 710 | } | ||
| 554 | 711 | ||
| 555 | radix_tree_tag_clear(&cookie->stores, page->index, | 712 | if (page) { |
| 556 | FSCACHE_COOKIE_PENDING_TAG); | 713 | radix_tree_tag_set(&cookie->stores, page->index, |
| 714 | FSCACHE_COOKIE_STORING_TAG); | ||
| 715 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
| 716 | FSCACHE_COOKIE_PENDING_TAG); | ||
| 717 | } | ||
| 557 | 718 | ||
| 719 | spin_unlock(&cookie->stores_lock); | ||
| 558 | spin_unlock(&object->lock); | 720 | spin_unlock(&object->lock); |
| 559 | spin_unlock(&cookie->lock); | ||
| 560 | 721 | ||
| 561 | if (page) { | 722 | if (page) { |
| 723 | fscache_set_op_state(&op->op, "Store"); | ||
| 724 | fscache_stat(&fscache_n_store_pages); | ||
| 725 | fscache_stat(&fscache_n_cop_write_page); | ||
| 562 | ret = object->cache->ops->write_page(op, page); | 726 | ret = object->cache->ops->write_page(op, page); |
| 563 | fscache_end_page_write(cookie, page); | 727 | fscache_stat_d(&fscache_n_cop_write_page); |
| 564 | page_cache_release(page); | 728 | fscache_set_op_state(&op->op, "EndWrite"); |
| 565 | if (ret < 0) | 729 | fscache_end_page_write(object, page); |
| 730 | if (ret < 0) { | ||
| 731 | fscache_set_op_state(&op->op, "Abort"); | ||
| 566 | fscache_abort_object(object); | 732 | fscache_abort_object(object); |
| 567 | else | 733 | } else { |
| 568 | fscache_enqueue_operation(&op->op); | 734 | fscache_enqueue_operation(&op->op); |
| 735 | } | ||
| 569 | } | 736 | } |
| 570 | 737 | ||
| 571 | _leave(""); | 738 | _leave(""); |
| @@ -575,9 +742,9 @@ superseded: | |||
| 575 | /* this writer is going away and there aren't any more things to | 742 | /* this writer is going away and there aren't any more things to |
| 576 | * write */ | 743 | * write */ |
| 577 | _debug("cease"); | 744 | _debug("cease"); |
| 745 | spin_unlock(&cookie->stores_lock); | ||
| 578 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 746 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
| 579 | spin_unlock(&object->lock); | 747 | spin_unlock(&object->lock); |
| 580 | spin_unlock(&cookie->lock); | ||
| 581 | _leave(""); | 748 | _leave(""); |
| 582 | } | 749 | } |
| 583 | 750 | ||
| @@ -634,6 +801,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
| 634 | fscache_operation_init(&op->op, fscache_release_write_op); | 801 | fscache_operation_init(&op->op, fscache_release_write_op); |
| 635 | fscache_operation_init_slow(&op->op, fscache_write_op); | 802 | fscache_operation_init_slow(&op->op, fscache_write_op); |
| 636 | op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING); | 803 | op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING); |
| 804 | fscache_set_op_name(&op->op, "Write1"); | ||
| 637 | 805 | ||
| 638 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); | 806 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); |
| 639 | if (ret < 0) | 807 | if (ret < 0) |
| @@ -652,6 +820,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
| 652 | /* add the page to the pending-storage radix tree on the backing | 820 | /* add the page to the pending-storage radix tree on the backing |
| 653 | * object */ | 821 | * object */ |
| 654 | spin_lock(&object->lock); | 822 | spin_lock(&object->lock); |
| 823 | spin_lock(&cookie->stores_lock); | ||
| 655 | 824 | ||
| 656 | _debug("store limit %llx", (unsigned long long) object->store_limit); | 825 | _debug("store limit %llx", (unsigned long long) object->store_limit); |
| 657 | 826 | ||
| @@ -672,6 +841,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
| 672 | if (test_and_set_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags)) | 841 | if (test_and_set_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags)) |
| 673 | goto already_pending; | 842 | goto already_pending; |
| 674 | 843 | ||
| 844 | spin_unlock(&cookie->stores_lock); | ||
| 675 | spin_unlock(&object->lock); | 845 | spin_unlock(&object->lock); |
| 676 | 846 | ||
| 677 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); | 847 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); |
| @@ -693,6 +863,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
| 693 | already_queued: | 863 | already_queued: |
| 694 | fscache_stat(&fscache_n_stores_again); | 864 | fscache_stat(&fscache_n_stores_again); |
| 695 | already_pending: | 865 | already_pending: |
| 866 | spin_unlock(&cookie->stores_lock); | ||
| 696 | spin_unlock(&object->lock); | 867 | spin_unlock(&object->lock); |
| 697 | spin_unlock(&cookie->lock); | 868 | spin_unlock(&cookie->lock); |
| 698 | radix_tree_preload_end(); | 869 | radix_tree_preload_end(); |
| @@ -702,7 +873,9 @@ already_pending: | |||
| 702 | return 0; | 873 | return 0; |
| 703 | 874 | ||
| 704 | submit_failed: | 875 | submit_failed: |
| 876 | spin_lock(&cookie->stores_lock); | ||
| 705 | radix_tree_delete(&cookie->stores, page->index); | 877 | radix_tree_delete(&cookie->stores, page->index); |
| 878 | spin_unlock(&cookie->stores_lock); | ||
| 706 | page_cache_release(page); | 879 | page_cache_release(page); |
| 707 | ret = -ENOBUFS; | 880 | ret = -ENOBUFS; |
| 708 | goto nobufs; | 881 | goto nobufs; |
| @@ -763,7 +936,9 @@ void __fscache_uncache_page(struct fscache_cookie *cookie, struct page *page) | |||
| 763 | if (TestClearPageFsCache(page) && | 936 | if (TestClearPageFsCache(page) && |
| 764 | object->cache->ops->uncache_page) { | 937 | object->cache->ops->uncache_page) { |
| 765 | /* the cache backend releases the cookie lock */ | 938 | /* the cache backend releases the cookie lock */ |
| 939 | fscache_stat(&fscache_n_cop_uncache_page); | ||
| 766 | object->cache->ops->uncache_page(object, page); | 940 | object->cache->ops->uncache_page(object, page); |
| 941 | fscache_stat_d(&fscache_n_cop_uncache_page); | ||
| 767 | goto done; | 942 | goto done; |
| 768 | } | 943 | } |
| 769 | 944 | ||
diff --git a/fs/fscache/proc.c b/fs/fscache/proc.c index beeab44bc31a..1d9e4951a597 100644 --- a/fs/fscache/proc.c +++ b/fs/fscache/proc.c | |||
| @@ -37,10 +37,20 @@ int __init fscache_proc_init(void) | |||
| 37 | goto error_histogram; | 37 | goto error_histogram; |
| 38 | #endif | 38 | #endif |
| 39 | 39 | ||
| 40 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
| 41 | if (!proc_create("fs/fscache/objects", S_IFREG | 0444, NULL, | ||
| 42 | &fscache_objlist_fops)) | ||
| 43 | goto error_objects; | ||
| 44 | #endif | ||
| 45 | |||
| 40 | _leave(" = 0"); | 46 | _leave(" = 0"); |
| 41 | return 0; | 47 | return 0; |
| 42 | 48 | ||
| 49 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
| 50 | error_objects: | ||
| 51 | #endif | ||
| 43 | #ifdef CONFIG_FSCACHE_HISTOGRAM | 52 | #ifdef CONFIG_FSCACHE_HISTOGRAM |
| 53 | remove_proc_entry("fs/fscache/histogram", NULL); | ||
| 44 | error_histogram: | 54 | error_histogram: |
| 45 | #endif | 55 | #endif |
| 46 | #ifdef CONFIG_FSCACHE_STATS | 56 | #ifdef CONFIG_FSCACHE_STATS |
| @@ -58,6 +68,9 @@ error_dir: | |||
| 58 | */ | 68 | */ |
| 59 | void fscache_proc_cleanup(void) | 69 | void fscache_proc_cleanup(void) |
| 60 | { | 70 | { |
| 71 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
| 72 | remove_proc_entry("fs/fscache/objects", NULL); | ||
| 73 | #endif | ||
| 61 | #ifdef CONFIG_FSCACHE_HISTOGRAM | 74 | #ifdef CONFIG_FSCACHE_HISTOGRAM |
| 62 | remove_proc_entry("fs/fscache/histogram", NULL); | 75 | remove_proc_entry("fs/fscache/histogram", NULL); |
| 63 | #endif | 76 | #endif |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 65deb99e756b..46435f3aae68 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
| @@ -25,6 +25,8 @@ atomic_t fscache_n_op_requeue; | |||
| 25 | atomic_t fscache_n_op_deferred_release; | 25 | atomic_t fscache_n_op_deferred_release; |
| 26 | atomic_t fscache_n_op_release; | 26 | atomic_t fscache_n_op_release; |
| 27 | atomic_t fscache_n_op_gc; | 27 | atomic_t fscache_n_op_gc; |
| 28 | atomic_t fscache_n_op_cancelled; | ||
| 29 | atomic_t fscache_n_op_rejected; | ||
| 28 | 30 | ||
| 29 | atomic_t fscache_n_attr_changed; | 31 | atomic_t fscache_n_attr_changed; |
| 30 | atomic_t fscache_n_attr_changed_ok; | 32 | atomic_t fscache_n_attr_changed_ok; |
| @@ -36,6 +38,8 @@ atomic_t fscache_n_allocs; | |||
| 36 | atomic_t fscache_n_allocs_ok; | 38 | atomic_t fscache_n_allocs_ok; |
| 37 | atomic_t fscache_n_allocs_wait; | 39 | atomic_t fscache_n_allocs_wait; |
| 38 | atomic_t fscache_n_allocs_nobufs; | 40 | atomic_t fscache_n_allocs_nobufs; |
| 41 | atomic_t fscache_n_allocs_intr; | ||
| 42 | atomic_t fscache_n_allocs_object_dead; | ||
| 39 | atomic_t fscache_n_alloc_ops; | 43 | atomic_t fscache_n_alloc_ops; |
| 40 | atomic_t fscache_n_alloc_op_waits; | 44 | atomic_t fscache_n_alloc_op_waits; |
| 41 | 45 | ||
| @@ -46,6 +50,7 @@ atomic_t fscache_n_retrievals_nodata; | |||
| 46 | atomic_t fscache_n_retrievals_nobufs; | 50 | atomic_t fscache_n_retrievals_nobufs; |
| 47 | atomic_t fscache_n_retrievals_intr; | 51 | atomic_t fscache_n_retrievals_intr; |
| 48 | atomic_t fscache_n_retrievals_nomem; | 52 | atomic_t fscache_n_retrievals_nomem; |
| 53 | atomic_t fscache_n_retrievals_object_dead; | ||
| 49 | atomic_t fscache_n_retrieval_ops; | 54 | atomic_t fscache_n_retrieval_ops; |
| 50 | atomic_t fscache_n_retrieval_op_waits; | 55 | atomic_t fscache_n_retrieval_op_waits; |
| 51 | 56 | ||
| @@ -56,6 +61,14 @@ atomic_t fscache_n_stores_nobufs; | |||
| 56 | atomic_t fscache_n_stores_oom; | 61 | atomic_t fscache_n_stores_oom; |
| 57 | atomic_t fscache_n_store_ops; | 62 | atomic_t fscache_n_store_ops; |
| 58 | atomic_t fscache_n_store_calls; | 63 | atomic_t fscache_n_store_calls; |
| 64 | atomic_t fscache_n_store_pages; | ||
| 65 | atomic_t fscache_n_store_radix_deletes; | ||
| 66 | atomic_t fscache_n_store_pages_over_limit; | ||
| 67 | |||
| 68 | atomic_t fscache_n_store_vmscan_not_storing; | ||
| 69 | atomic_t fscache_n_store_vmscan_gone; | ||
| 70 | atomic_t fscache_n_store_vmscan_busy; | ||
| 71 | atomic_t fscache_n_store_vmscan_cancelled; | ||
| 59 | 72 | ||
| 60 | atomic_t fscache_n_marks; | 73 | atomic_t fscache_n_marks; |
| 61 | atomic_t fscache_n_uncaches; | 74 | atomic_t fscache_n_uncaches; |
| @@ -74,6 +87,7 @@ atomic_t fscache_n_updates_run; | |||
| 74 | atomic_t fscache_n_relinquishes; | 87 | atomic_t fscache_n_relinquishes; |
| 75 | atomic_t fscache_n_relinquishes_null; | 88 | atomic_t fscache_n_relinquishes_null; |
| 76 | atomic_t fscache_n_relinquishes_waitcrt; | 89 | atomic_t fscache_n_relinquishes_waitcrt; |
| 90 | atomic_t fscache_n_relinquishes_retire; | ||
| 77 | 91 | ||
| 78 | atomic_t fscache_n_cookie_index; | 92 | atomic_t fscache_n_cookie_index; |
| 79 | atomic_t fscache_n_cookie_data; | 93 | atomic_t fscache_n_cookie_data; |
| @@ -84,6 +98,7 @@ atomic_t fscache_n_object_no_alloc; | |||
| 84 | atomic_t fscache_n_object_lookups; | 98 | atomic_t fscache_n_object_lookups; |
| 85 | atomic_t fscache_n_object_lookups_negative; | 99 | atomic_t fscache_n_object_lookups_negative; |
| 86 | atomic_t fscache_n_object_lookups_positive; | 100 | atomic_t fscache_n_object_lookups_positive; |
| 101 | atomic_t fscache_n_object_lookups_timed_out; | ||
| 87 | atomic_t fscache_n_object_created; | 102 | atomic_t fscache_n_object_created; |
| 88 | atomic_t fscache_n_object_avail; | 103 | atomic_t fscache_n_object_avail; |
| 89 | atomic_t fscache_n_object_dead; | 104 | atomic_t fscache_n_object_dead; |
| @@ -93,6 +108,23 @@ atomic_t fscache_n_checkaux_okay; | |||
| 93 | atomic_t fscache_n_checkaux_update; | 108 | atomic_t fscache_n_checkaux_update; |
| 94 | atomic_t fscache_n_checkaux_obsolete; | 109 | atomic_t fscache_n_checkaux_obsolete; |
| 95 | 110 | ||
| 111 | atomic_t fscache_n_cop_alloc_object; | ||
| 112 | atomic_t fscache_n_cop_lookup_object; | ||
| 113 | atomic_t fscache_n_cop_lookup_complete; | ||
| 114 | atomic_t fscache_n_cop_grab_object; | ||
| 115 | atomic_t fscache_n_cop_update_object; | ||
| 116 | atomic_t fscache_n_cop_drop_object; | ||
| 117 | atomic_t fscache_n_cop_put_object; | ||
| 118 | atomic_t fscache_n_cop_sync_cache; | ||
| 119 | atomic_t fscache_n_cop_attr_changed; | ||
| 120 | atomic_t fscache_n_cop_read_or_alloc_page; | ||
| 121 | atomic_t fscache_n_cop_read_or_alloc_pages; | ||
| 122 | atomic_t fscache_n_cop_allocate_page; | ||
| 123 | atomic_t fscache_n_cop_allocate_pages; | ||
| 124 | atomic_t fscache_n_cop_write_page; | ||
| 125 | atomic_t fscache_n_cop_uncache_page; | ||
| 126 | atomic_t fscache_n_cop_dissociate_pages; | ||
| 127 | |||
| 96 | /* | 128 | /* |
| 97 | * display the general statistics | 129 | * display the general statistics |
| 98 | */ | 130 | */ |
| @@ -129,10 +161,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
| 129 | atomic_read(&fscache_n_acquires_nobufs), | 161 | atomic_read(&fscache_n_acquires_nobufs), |
| 130 | atomic_read(&fscache_n_acquires_oom)); | 162 | atomic_read(&fscache_n_acquires_oom)); |
| 131 | 163 | ||
| 132 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u\n", | 164 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u tmo=%u\n", |
| 133 | atomic_read(&fscache_n_object_lookups), | 165 | atomic_read(&fscache_n_object_lookups), |
| 134 | atomic_read(&fscache_n_object_lookups_negative), | 166 | atomic_read(&fscache_n_object_lookups_negative), |
| 135 | atomic_read(&fscache_n_object_lookups_positive), | 167 | atomic_read(&fscache_n_object_lookups_positive), |
| 168 | atomic_read(&fscache_n_object_lookups_timed_out), | ||
| 136 | atomic_read(&fscache_n_object_created)); | 169 | atomic_read(&fscache_n_object_created)); |
| 137 | 170 | ||
| 138 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
| @@ -140,10 +173,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
| 140 | atomic_read(&fscache_n_updates_null), | 173 | atomic_read(&fscache_n_updates_null), |
| 141 | atomic_read(&fscache_n_updates_run)); | 174 | atomic_read(&fscache_n_updates_run)); |
| 142 | 175 | ||
| 143 | seq_printf(m, "Relinqs: n=%u nul=%u wcr=%u\n", | 176 | seq_printf(m, "Relinqs: n=%u nul=%u wcr=%u rtr=%u\n", |
| 144 | atomic_read(&fscache_n_relinquishes), | 177 | atomic_read(&fscache_n_relinquishes), |
| 145 | atomic_read(&fscache_n_relinquishes_null), | 178 | atomic_read(&fscache_n_relinquishes_null), |
| 146 | atomic_read(&fscache_n_relinquishes_waitcrt)); | 179 | atomic_read(&fscache_n_relinquishes_waitcrt), |
| 180 | atomic_read(&fscache_n_relinquishes_retire)); | ||
| 147 | 181 | ||
| 148 | seq_printf(m, "AttrChg: n=%u ok=%u nbf=%u oom=%u run=%u\n", | 182 | seq_printf(m, "AttrChg: n=%u ok=%u nbf=%u oom=%u run=%u\n", |
| 149 | atomic_read(&fscache_n_attr_changed), | 183 | atomic_read(&fscache_n_attr_changed), |
| @@ -152,14 +186,16 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
| 152 | atomic_read(&fscache_n_attr_changed_nomem), | 186 | atomic_read(&fscache_n_attr_changed_nomem), |
| 153 | atomic_read(&fscache_n_attr_changed_calls)); | 187 | atomic_read(&fscache_n_attr_changed_calls)); |
| 154 | 188 | ||
| 155 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u\n", | 189 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u int=%u\n", |
| 156 | atomic_read(&fscache_n_allocs), | 190 | atomic_read(&fscache_n_allocs), |
| 157 | atomic_read(&fscache_n_allocs_ok), | 191 | atomic_read(&fscache_n_allocs_ok), |
| 158 | atomic_read(&fscache_n_allocs_wait), | 192 | atomic_read(&fscache_n_allocs_wait), |
| 159 | atomic_read(&fscache_n_allocs_nobufs)); | 193 | atomic_read(&fscache_n_allocs_nobufs), |
| 160 | seq_printf(m, "Allocs : ops=%u owt=%u\n", | 194 | atomic_read(&fscache_n_allocs_intr)); |
| 195 | seq_printf(m, "Allocs : ops=%u owt=%u abt=%u\n", | ||
| 161 | atomic_read(&fscache_n_alloc_ops), | 196 | atomic_read(&fscache_n_alloc_ops), |
| 162 | atomic_read(&fscache_n_alloc_op_waits)); | 197 | atomic_read(&fscache_n_alloc_op_waits), |
| 198 | atomic_read(&fscache_n_allocs_object_dead)); | ||
| 163 | 199 | ||
| 164 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" | 200 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" |
| 165 | " int=%u oom=%u\n", | 201 | " int=%u oom=%u\n", |
| @@ -170,9 +206,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
| 170 | atomic_read(&fscache_n_retrievals_nobufs), | 206 | atomic_read(&fscache_n_retrievals_nobufs), |
| 171 | atomic_read(&fscache_n_retrievals_intr), | 207 | atomic_read(&fscache_n_retrievals_intr), |
| 172 | atomic_read(&fscache_n_retrievals_nomem)); | 208 | atomic_read(&fscache_n_retrievals_nomem)); |
| 173 | seq_printf(m, "Retrvls: ops=%u owt=%u\n", | 209 | seq_printf(m, "Retrvls: ops=%u owt=%u abt=%u\n", |
| 174 | atomic_read(&fscache_n_retrieval_ops), | 210 | atomic_read(&fscache_n_retrieval_ops), |
| 175 | atomic_read(&fscache_n_retrieval_op_waits)); | 211 | atomic_read(&fscache_n_retrieval_op_waits), |
| 212 | atomic_read(&fscache_n_retrievals_object_dead)); | ||
| 176 | 213 | ||
| 177 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", | 214 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", |
| 178 | atomic_read(&fscache_n_stores), | 215 | atomic_read(&fscache_n_stores), |
| @@ -180,18 +217,49 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
| 180 | atomic_read(&fscache_n_stores_again), | 217 | atomic_read(&fscache_n_stores_again), |
| 181 | atomic_read(&fscache_n_stores_nobufs), | 218 | atomic_read(&fscache_n_stores_nobufs), |
| 182 | atomic_read(&fscache_n_stores_oom)); | 219 | atomic_read(&fscache_n_stores_oom)); |
| 183 | seq_printf(m, "Stores : ops=%u run=%u\n", | 220 | seq_printf(m, "Stores : ops=%u run=%u pgs=%u rxd=%u olm=%u\n", |
| 184 | atomic_read(&fscache_n_store_ops), | 221 | atomic_read(&fscache_n_store_ops), |
| 185 | atomic_read(&fscache_n_store_calls)); | 222 | atomic_read(&fscache_n_store_calls), |
| 223 | atomic_read(&fscache_n_store_pages), | ||
| 224 | atomic_read(&fscache_n_store_radix_deletes), | ||
| 225 | atomic_read(&fscache_n_store_pages_over_limit)); | ||
| 186 | 226 | ||
| 187 | seq_printf(m, "Ops : pend=%u run=%u enq=%u\n", | 227 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", |
| 228 | atomic_read(&fscache_n_store_vmscan_not_storing), | ||
| 229 | atomic_read(&fscache_n_store_vmscan_gone), | ||
| 230 | atomic_read(&fscache_n_store_vmscan_busy), | ||
| 231 | atomic_read(&fscache_n_store_vmscan_cancelled)); | ||
| 232 | |||
| 233 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", | ||
| 188 | atomic_read(&fscache_n_op_pend), | 234 | atomic_read(&fscache_n_op_pend), |
| 189 | atomic_read(&fscache_n_op_run), | 235 | atomic_read(&fscache_n_op_run), |
| 190 | atomic_read(&fscache_n_op_enqueue)); | 236 | atomic_read(&fscache_n_op_enqueue), |
| 237 | atomic_read(&fscache_n_op_cancelled), | ||
| 238 | atomic_read(&fscache_n_op_rejected)); | ||
| 191 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", | 239 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", |
| 192 | atomic_read(&fscache_n_op_deferred_release), | 240 | atomic_read(&fscache_n_op_deferred_release), |
| 193 | atomic_read(&fscache_n_op_release), | 241 | atomic_read(&fscache_n_op_release), |
| 194 | atomic_read(&fscache_n_op_gc)); | 242 | atomic_read(&fscache_n_op_gc)); |
| 243 | |||
| 244 | seq_printf(m, "CacheOp: alo=%d luo=%d luc=%d gro=%d\n", | ||
| 245 | atomic_read(&fscache_n_cop_alloc_object), | ||
| 246 | atomic_read(&fscache_n_cop_lookup_object), | ||
| 247 | atomic_read(&fscache_n_cop_lookup_complete), | ||
| 248 | atomic_read(&fscache_n_cop_grab_object)); | ||
| 249 | seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", | ||
| 250 | atomic_read(&fscache_n_cop_update_object), | ||
| 251 | atomic_read(&fscache_n_cop_drop_object), | ||
| 252 | atomic_read(&fscache_n_cop_put_object), | ||
| 253 | atomic_read(&fscache_n_cop_attr_changed), | ||
| 254 | atomic_read(&fscache_n_cop_sync_cache)); | ||
| 255 | seq_printf(m, "CacheOp: rap=%d ras=%d alp=%d als=%d wrp=%d ucp=%d dsp=%d\n", | ||
| 256 | atomic_read(&fscache_n_cop_read_or_alloc_page), | ||
| 257 | atomic_read(&fscache_n_cop_read_or_alloc_pages), | ||
| 258 | atomic_read(&fscache_n_cop_allocate_page), | ||
| 259 | atomic_read(&fscache_n_cop_allocate_pages), | ||
| 260 | atomic_read(&fscache_n_cop_write_page), | ||
| 261 | atomic_read(&fscache_n_cop_uncache_page), | ||
| 262 | atomic_read(&fscache_n_cop_dissociate_pages)); | ||
| 195 | return 0; | 263 | return 0; |
| 196 | } | 264 | } |
| 197 | 265 | ||
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index eacd78a5d082..5b31f7741a8f 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
| @@ -114,7 +114,7 @@ static int __init init_gfs2_fs(void) | |||
| 114 | if (error) | 114 | if (error) |
| 115 | goto fail_unregister; | 115 | goto fail_unregister; |
| 116 | 116 | ||
| 117 | error = slow_work_register_user(); | 117 | error = slow_work_register_user(THIS_MODULE); |
| 118 | if (error) | 118 | if (error) |
| 119 | goto fail_slow; | 119 | goto fail_slow; |
| 120 | 120 | ||
| @@ -163,7 +163,7 @@ static void __exit exit_gfs2_fs(void) | |||
| 163 | gfs2_unregister_debugfs(); | 163 | gfs2_unregister_debugfs(); |
| 164 | unregister_filesystem(&gfs2_fs_type); | 164 | unregister_filesystem(&gfs2_fs_type); |
| 165 | unregister_filesystem(&gfs2meta_fs_type); | 165 | unregister_filesystem(&gfs2meta_fs_type); |
| 166 | slow_work_unregister_user(); | 166 | slow_work_unregister_user(THIS_MODULE); |
| 167 | 167 | ||
| 168 | kmem_cache_destroy(gfs2_quotad_cachep); | 168 | kmem_cache_destroy(gfs2_quotad_cachep); |
| 169 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 169 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 59d2695509d3..09fa31965576 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * of the GNU General Public License version 2. | 7 | * of the GNU General Public License version 2. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/module.h> | ||
| 10 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
| 11 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
| 12 | #include <linux/completion.h> | 13 | #include <linux/completion.h> |
| @@ -593,6 +594,7 @@ fail: | |||
| 593 | } | 594 | } |
| 594 | 595 | ||
| 595 | struct slow_work_ops gfs2_recover_ops = { | 596 | struct slow_work_ops gfs2_recover_ops = { |
| 597 | .owner = THIS_MODULE, | ||
| 596 | .get_ref = gfs2_recover_get_ref, | 598 | .get_ref = gfs2_recover_get_ref, |
| 597 | .put_ref = gfs2_recover_put_ref, | 599 | .put_ref = gfs2_recover_put_ref, |
| 598 | .execute = gfs2_recover_work, | 600 | .execute = gfs2_recover_work, |
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index cfe05c1966a5..3f39be1b0455 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c | |||
| @@ -164,12 +164,15 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
| 164 | 164 | ||
| 165 | /* XXX FIXME: Where a single physical node actually shows up in two | 165 | /* XXX FIXME: Where a single physical node actually shows up in two |
| 166 | frags, we read it twice. Don't do that. */ | 166 | frags, we read it twice. Don't do that. */ |
| 167 | /* Now we're pointing at the first frag which overlaps our page */ | 167 | /* Now we're pointing at the first frag which overlaps our page |
| 168 | * (or perhaps is before it, if we've been asked to read off the | ||
| 169 | * end of the file). */ | ||
| 168 | while(offset < end) { | 170 | while(offset < end) { |
| 169 | D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); | 171 | D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); |
| 170 | if (unlikely(!frag || frag->ofs > offset)) { | 172 | if (unlikely(!frag || frag->ofs > offset || |
| 173 | frag->ofs + frag->size <= offset)) { | ||
| 171 | uint32_t holesize = end - offset; | 174 | uint32_t holesize = end - offset; |
| 172 | if (frag) { | 175 | if (frag && frag->ofs > offset) { |
| 173 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); | 176 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); |
| 174 | holesize = min(holesize, frag->ofs - offset); | 177 | holesize = min(holesize, frag->ofs - offset); |
| 175 | } | 178 | } |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 70fad69eb959..fa588006588d 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
| @@ -359,17 +359,13 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp) | |||
| 359 | 359 | ||
| 360 | BUG_ON(!cookie); | 360 | BUG_ON(!cookie); |
| 361 | 361 | ||
| 362 | if (fscache_check_page_write(cookie, page)) { | ||
| 363 | if (!(gfp & __GFP_WAIT)) | ||
| 364 | return 0; | ||
| 365 | fscache_wait_on_page_write(cookie, page); | ||
| 366 | } | ||
| 367 | |||
| 368 | if (PageFsCache(page)) { | 362 | if (PageFsCache(page)) { |
| 369 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
| 370 | cookie, page, nfsi); | 364 | cookie, page, nfsi); |
| 371 | 365 | ||
| 372 | fscache_uncache_page(cookie, page); | 366 | if (!fscache_maybe_release_page(cookie, page, gfp)) |
| 367 | return 0; | ||
| 368 | |||
| 373 | nfs_add_fscache_stats(page->mapping->host, | 369 | nfs_add_fscache_stats(page->mapping->host, |
| 374 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | 370 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); |
| 375 | } | 371 | } |
