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); |