diff options
Diffstat (limited to 'fs/cachefiles')
| -rw-r--r-- | fs/cachefiles/interface.c | 32 | ||||
| -rw-r--r-- | fs/cachefiles/namei.c | 187 | ||||
| -rw-r--r-- | fs/cachefiles/rdwr.c | 130 |
3 files changed, 285 insertions, 64 deletions
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..a6c8c6fe8df9 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
| 13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
| 14 | #include <linux/ima.h> | ||
| 14 | #include "internal.h" | 15 | #include "internal.h" |
| 15 | 16 | ||
| 16 | /* | 17 | /* |
| @@ -40,8 +41,10 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
| 40 | 41 | ||
| 41 | _debug("--- monitor %p %lx ---", page, page->flags); | 42 | _debug("--- monitor %p %lx ---", page, page->flags); |
| 42 | 43 | ||
| 43 | if (!PageUptodate(page) && !PageError(page)) | 44 | if (!PageUptodate(page) && !PageError(page)) { |
| 44 | dump_stack(); | 45 | /* unlocked, not uptodate and not erronous? */ |
| 46 | _debug("page probably truncated"); | ||
| 47 | } | ||
| 45 | 48 | ||
| 46 | /* remove from the waitqueue */ | 49 | /* remove from the waitqueue */ |
| 47 | list_del(&wait->task_list); | 50 | list_del(&wait->task_list); |
| @@ -61,6 +64,84 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
| 61 | } | 64 | } |
| 62 | 65 | ||
| 63 | /* | 66 | /* |
| 67 | * handle a probably truncated page | ||
| 68 | * - check to see if the page is still relevant and reissue the read if | ||
| 69 | * possible | ||
| 70 | * - return -EIO on error, -ENODATA if the page is gone, -EINPROGRESS if we | ||
| 71 | * must wait again and 0 if successful | ||
| 72 | */ | ||
| 73 | static int cachefiles_read_reissue(struct cachefiles_object *object, | ||
| 74 | struct cachefiles_one_read *monitor) | ||
| 75 | { | ||
| 76 | struct address_space *bmapping = object->backer->d_inode->i_mapping; | ||
| 77 | struct page *backpage = monitor->back_page, *backpage2; | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | kenter("{ino=%lx},{%lx,%lx}", | ||
| 81 | object->backer->d_inode->i_ino, | ||
| 82 | backpage->index, backpage->flags); | ||
| 83 | |||
| 84 | /* skip if the page was truncated away completely */ | ||
| 85 | if (backpage->mapping != bmapping) { | ||
| 86 | kleave(" = -ENODATA [mapping]"); | ||
| 87 | return -ENODATA; | ||
| 88 | } | ||
| 89 | |||
| 90 | backpage2 = find_get_page(bmapping, backpage->index); | ||
| 91 | if (!backpage2) { | ||
| 92 | kleave(" = -ENODATA [gone]"); | ||
| 93 | return -ENODATA; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (backpage != backpage2) { | ||
| 97 | put_page(backpage2); | ||
| 98 | kleave(" = -ENODATA [different]"); | ||
| 99 | return -ENODATA; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* the page is still there and we already have a ref on it, so we don't | ||
| 103 | * need a second */ | ||
| 104 | put_page(backpage2); | ||
| 105 | |||
| 106 | INIT_LIST_HEAD(&monitor->op_link); | ||
| 107 | add_page_wait_queue(backpage, &monitor->monitor); | ||
| 108 | |||
| 109 | if (trylock_page(backpage)) { | ||
| 110 | ret = -EIO; | ||
| 111 | if (PageError(backpage)) | ||
| 112 | goto unlock_discard; | ||
| 113 | ret = 0; | ||
| 114 | if (PageUptodate(backpage)) | ||
| 115 | goto unlock_discard; | ||
| 116 | |||
| 117 | kdebug("reissue read"); | ||
| 118 | ret = bmapping->a_ops->readpage(NULL, backpage); | ||
| 119 | if (ret < 0) | ||
| 120 | goto unlock_discard; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* but the page may have been read before the monitor was installed, so | ||
| 124 | * the monitor may miss the event - so we have to ensure that we do get | ||
| 125 | * one in such a case */ | ||
| 126 | if (trylock_page(backpage)) { | ||
| 127 | _debug("jumpstart %p {%lx}", backpage, backpage->flags); | ||
| 128 | unlock_page(backpage); | ||
| 129 | } | ||
| 130 | |||
| 131 | /* it'll reappear on the todo list */ | ||
| 132 | kleave(" = -EINPROGRESS"); | ||
| 133 | return -EINPROGRESS; | ||
| 134 | |||
| 135 | unlock_discard: | ||
| 136 | unlock_page(backpage); | ||
| 137 | spin_lock_irq(&object->work_lock); | ||
| 138 | list_del(&monitor->op_link); | ||
| 139 | spin_unlock_irq(&object->work_lock); | ||
| 140 | kleave(" = %d", ret); | ||
| 141 | return ret; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* | ||
| 64 | * copy data from backing pages to netfs pages to complete a read operation | 145 | * copy data from backing pages to netfs pages to complete a read operation |
| 65 | * - driven by FS-Cache's thread pool | 146 | * - driven by FS-Cache's thread pool |
| 66 | */ | 147 | */ |
| @@ -92,20 +173,26 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
| 92 | 173 | ||
| 93 | _debug("- copy {%lu}", monitor->back_page->index); | 174 | _debug("- copy {%lu}", monitor->back_page->index); |
| 94 | 175 | ||
| 95 | error = -EIO; | 176 | recheck: |
| 96 | if (PageUptodate(monitor->back_page)) { | 177 | if (PageUptodate(monitor->back_page)) { |
| 97 | copy_highpage(monitor->netfs_page, monitor->back_page); | 178 | copy_highpage(monitor->netfs_page, monitor->back_page); |
| 98 | 179 | ||
| 99 | pagevec_add(&pagevec, monitor->netfs_page); | 180 | pagevec_add(&pagevec, monitor->netfs_page); |
| 100 | fscache_mark_pages_cached(monitor->op, &pagevec); | 181 | fscache_mark_pages_cached(monitor->op, &pagevec); |
| 101 | error = 0; | 182 | error = 0; |
| 102 | } | 183 | } else if (!PageError(monitor->back_page)) { |
| 103 | 184 | /* the page has probably been truncated */ | |
| 104 | if (error) | 185 | error = cachefiles_read_reissue(object, monitor); |
| 186 | if (error == -EINPROGRESS) | ||
| 187 | goto next; | ||
| 188 | goto recheck; | ||
| 189 | } else { | ||
| 105 | cachefiles_io_error_obj( | 190 | cachefiles_io_error_obj( |
| 106 | object, | 191 | object, |
| 107 | "Readpage failed on backing file %lx", | 192 | "Readpage failed on backing file %lx", |
| 108 | (unsigned long) monitor->back_page->flags); | 193 | (unsigned long) monitor->back_page->flags); |
| 194 | error = -EIO; | ||
| 195 | } | ||
| 109 | 196 | ||
| 110 | page_cache_release(monitor->back_page); | 197 | page_cache_release(monitor->back_page); |
| 111 | 198 | ||
| @@ -114,6 +201,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
| 114 | fscache_put_retrieval(op); | 201 | fscache_put_retrieval(op); |
| 115 | kfree(monitor); | 202 | kfree(monitor); |
| 116 | 203 | ||
| 204 | next: | ||
| 117 | /* let the thread pool have some air occasionally */ | 205 | /* let the thread pool have some air occasionally */ |
| 118 | max--; | 206 | max--; |
| 119 | if (max < 0 || need_resched()) { | 207 | if (max < 0 || need_resched()) { |
| @@ -333,7 +421,8 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
| 333 | 421 | ||
| 334 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
| 335 | 423 | ||
| 336 | op->op.flags = FSCACHE_OP_FAST; | 424 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
| 425 | op->op.flags |= FSCACHE_OP_FAST; | ||
| 337 | op->op.processor = cachefiles_read_copier; | 426 | op->op.processor = cachefiles_read_copier; |
| 338 | 427 | ||
| 339 | pagevec_init(&pagevec, 0); | 428 | pagevec_init(&pagevec, 0); |
| @@ -639,7 +728,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
| 639 | 728 | ||
| 640 | pagevec_init(&pagevec, 0); | 729 | pagevec_init(&pagevec, 0); |
| 641 | 730 | ||
| 642 | op->op.flags = FSCACHE_OP_FAST; | 731 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
| 732 | op->op.flags |= FSCACHE_OP_FAST; | ||
| 643 | op->op.processor = cachefiles_read_copier; | 733 | op->op.processor = cachefiles_read_copier; |
| 644 | 734 | ||
| 645 | INIT_LIST_HEAD(&backpages); | 735 | INIT_LIST_HEAD(&backpages); |
| @@ -801,7 +891,8 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
| 801 | struct cachefiles_cache *cache; | 891 | struct cachefiles_cache *cache; |
| 802 | mm_segment_t old_fs; | 892 | mm_segment_t old_fs; |
| 803 | struct file *file; | 893 | struct file *file; |
| 804 | loff_t pos; | 894 | loff_t pos, eof; |
| 895 | size_t len; | ||
| 805 | void *data; | 896 | void *data; |
| 806 | int ret; | 897 | int ret; |
| 807 | 898 | ||
| @@ -832,18 +923,33 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
| 832 | if (IS_ERR(file)) { | 923 | if (IS_ERR(file)) { |
| 833 | ret = PTR_ERR(file); | 924 | ret = PTR_ERR(file); |
| 834 | } else { | 925 | } else { |
| 926 | ima_counts_get(file); | ||
| 835 | ret = -EIO; | 927 | ret = -EIO; |
| 836 | if (file->f_op->write) { | 928 | if (file->f_op->write) { |
| 837 | pos = (loff_t) page->index << PAGE_SHIFT; | 929 | pos = (loff_t) page->index << PAGE_SHIFT; |
| 930 | |||
| 931 | /* we mustn't write more data than we have, so we have | ||
| 932 | * to beware of a partial page at EOF */ | ||
| 933 | eof = object->fscache.store_limit_l; | ||
| 934 | len = PAGE_SIZE; | ||
| 935 | if (eof & ~PAGE_MASK) { | ||
| 936 | ASSERTCMP(pos, <, eof); | ||
| 937 | if (eof - pos < PAGE_SIZE) { | ||
| 938 | _debug("cut short %llx to %llx", | ||
| 939 | pos, eof); | ||
| 940 | len = eof - pos; | ||
| 941 | ASSERTCMP(pos + len, ==, eof); | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 838 | data = kmap(page); | 945 | data = kmap(page); |
| 839 | old_fs = get_fs(); | 946 | old_fs = get_fs(); |
| 840 | set_fs(KERNEL_DS); | 947 | set_fs(KERNEL_DS); |
| 841 | ret = file->f_op->write( | 948 | ret = file->f_op->write( |
| 842 | file, (const void __user *) data, PAGE_SIZE, | 949 | file, (const void __user *) data, len, &pos); |
| 843 | &pos); | ||
| 844 | set_fs(old_fs); | 950 | set_fs(old_fs); |
| 845 | kunmap(page); | 951 | kunmap(page); |
| 846 | if (ret != PAGE_SIZE) | 952 | if (ret != len) |
| 847 | ret = -EIO; | 953 | ret = -EIO; |
| 848 | } | 954 | } |
| 849 | fput(file); | 955 | fput(file); |
