aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fscache
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-12-05 08:34:48 -0500
committerDavid Howells <dhowells@redhat.com>2012-12-20 17:10:58 -0500
commit8d76349d359064859217dc292dc8733e209705af (patch)
tree07a43fff286f2c911d14a8714bf3dcb3321f5dfd /fs/fscache
parent75bc411388f4aeb9fb0381bd56eb5d67193ed9a1 (diff)
FS-Cache: Exclusive op submission can BUG if there's been an I/O error
The function to submit an exclusive op (fscache_submit_exclusive_op()) can BUG if there's been an I/O error because it may see the parent cache object in an unexpected state. It should only BUG if there hasn't been an I/O error. In this case the problem was produced by remounting the cache partition to be R/O. The EROFS state was detected and the cache was aborted, but not everything handled the aborting correctly. SysRq : Emergency Remount R/O EXT4-fs (sda6): re-mounted. Opts: (null) Emergency Remount complete CacheFiles: I/O Error: Failed to update xattr with error -30 FS-Cache: Cache cachefiles stopped due to I/O error ------------[ cut here ]------------ kernel BUG at fs/fscache/operation.c:128! invalid opcode: 0000 [#1] SMP CPU 0 Modules linked in: cachefiles nfs fscache auth_rpcgss nfs_acl lockd sunrpc Pid: 6612, comm: kworker/u:2 Not tainted 3.1.0-rc8-fsdevel+ #1093 /DG965RY RIP: 0010:[<ffffffffa00739c0>] [<ffffffffa00739c0>] fscache_submit_exclusive_op+0x2ad/0x2c2 [fscache] RSP: 0018:ffff880000853d40 EFLAGS: 00010206 RAX: ffff880038ac72a8 RBX: ffff8800181f2260 RCX: ffffffff81f2b2b0 RDX: 0000000000000001 RSI: ffffffff8179a478 RDI: ffff8800181f2280 RBP: ffff880000853d60 R08: 0000000000000002 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000001 R12: ffff880038ac7268 R13: ffff8800181f2280 R14: ffff88003a359190 R15: 000000010122b162 FS: 0000000000000000(0000) GS:ffff88003bc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000034cc4a77f0 CR3: 0000000010e96000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process kworker/u:2 (pid: 6612, threadinfo ffff880000852000, task ffff880014c3c040) Stack: ffff8800181f2260 ffff8800181f2310 ffff880038ac7268 ffff8800181f2260 ffff880000853dc0 ffffffffa0072375 ffff880037ecfe00 ffff88003a359198 ffff880000853dc0 0000000000000246 0000000000000000 ffff88000a91d308 Call Trace: [<ffffffffa0072375>] fscache_object_work_func+0x792/0xe65 [fscache] [<ffffffff81047e44>] process_one_work+0x1eb/0x37f [<ffffffff81047de6>] ? process_one_work+0x18d/0x37f [<ffffffffa0071be3>] ? fscache_enqueue_dependents+0xd8/0xd8 [fscache] [<ffffffff810482e4>] worker_thread+0x15a/0x21a [<ffffffff8104818a>] ? rescuer_thread+0x188/0x188 [<ffffffff8104bf96>] kthread+0x7f/0x87 [<ffffffff813ad6f4>] kernel_thread_helper+0x4/0x10 [<ffffffff81026b98>] ? finish_task_switch+0x45/0xc0 [<ffffffff813abd1d>] ? retint_restore_args+0xe/0xe [<ffffffff8104bf17>] ? __init_kthread_worker+0x53/0x53 [<ffffffff813ad6f0>] ? gs_change+0xb/0xb Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/fscache')
-rw-r--r--fs/fscache/internal.h1
-rw-r--r--fs/fscache/object.c23
-rw-r--r--fs/fscache/operation.c13
3 files changed, 28 insertions, 9 deletions
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index c81179303930..dcb3e1d5dbf6 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -288,6 +288,7 @@ extern const struct file_operations fscache_stats_fops;
288static inline void fscache_raise_event(struct fscache_object *object, 288static inline void fscache_raise_event(struct fscache_object *object,
289 unsigned event) 289 unsigned event)
290{ 290{
291 BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS);
291 if (!test_and_set_bit(event, &object->events) && 292 if (!test_and_set_bit(event, &object->events) &&
292 test_bit(event, &object->event_mask)) 293 test_bit(event, &object->event_mask))
293 fscache_enqueue_object(object); 294 fscache_enqueue_object(object);
diff --git a/fs/fscache/object.c b/fs/fscache/object.c
index 2ef8a082a272..2c512cbac380 100644
--- a/fs/fscache/object.c
+++ b/fs/fscache/object.c
@@ -103,6 +103,7 @@ static void fscache_object_state_machine(struct fscache_object *object)
103{ 103{
104 enum fscache_object_state new_state; 104 enum fscache_object_state new_state;
105 struct fscache_cookie *cookie; 105 struct fscache_cookie *cookie;
106 int event;
106 107
107 ASSERT(object != NULL); 108 ASSERT(object != NULL);
108 109
@@ -275,7 +276,8 @@ static void fscache_object_state_machine(struct fscache_object *object)
275 276
276 /* determine the transition from a lookup state */ 277 /* determine the transition from a lookup state */
277lookup_transit: 278lookup_transit:
278 switch (fls(object->events & object->event_mask) - 1) { 279 event = fls(object->events & object->event_mask) - 1;
280 switch (event) {
279 case FSCACHE_OBJECT_EV_WITHDRAW: 281 case FSCACHE_OBJECT_EV_WITHDRAW:
280 case FSCACHE_OBJECT_EV_RETIRE: 282 case FSCACHE_OBJECT_EV_RETIRE:
281 case FSCACHE_OBJECT_EV_RELEASE: 283 case FSCACHE_OBJECT_EV_RELEASE:
@@ -292,7 +294,8 @@ lookup_transit:
292 294
293 /* determine the transition from an active state */ 295 /* determine the transition from an active state */
294active_transit: 296active_transit:
295 switch (fls(object->events & object->event_mask) - 1) { 297 event = fls(object->events & object->event_mask) - 1;
298 switch (event) {
296 case FSCACHE_OBJECT_EV_WITHDRAW: 299 case FSCACHE_OBJECT_EV_WITHDRAW:
297 case FSCACHE_OBJECT_EV_RETIRE: 300 case FSCACHE_OBJECT_EV_RETIRE:
298 case FSCACHE_OBJECT_EV_RELEASE: 301 case FSCACHE_OBJECT_EV_RELEASE:
@@ -314,7 +317,8 @@ active_transit:
314 317
315 /* determine the transition from a terminal state */ 318 /* determine the transition from a terminal state */
316terminal_transit: 319terminal_transit:
317 switch (fls(object->events & object->event_mask) - 1) { 320 event = fls(object->events & object->event_mask) - 1;
321 switch (event) {
318 case FSCACHE_OBJECT_EV_WITHDRAW: 322 case FSCACHE_OBJECT_EV_WITHDRAW:
319 new_state = FSCACHE_OBJECT_WITHDRAWING; 323 new_state = FSCACHE_OBJECT_WITHDRAWING;
320 goto change_state; 324 goto change_state;
@@ -347,8 +351,8 @@ done:
347 351
348unsupported_event: 352unsupported_event:
349 printk(KERN_ERR "FS-Cache:" 353 printk(KERN_ERR "FS-Cache:"
350 " Unsupported event %lx [mask %lx] in state %s\n", 354 " Unsupported event %d [%lx/%lx] in state %s\n",
351 object->events, object->event_mask, 355 event, object->events, object->event_mask,
352 fscache_object_states[object->state]); 356 fscache_object_states[object->state]);
353 BUG(); 357 BUG();
354} 358}
@@ -945,7 +949,7 @@ static void fscache_invalidate_object(struct fscache_object *object)
945 949
946 spin_lock(&cookie->lock); 950 spin_lock(&cookie->lock);
947 if (fscache_submit_exclusive_op(object, op) < 0) 951 if (fscache_submit_exclusive_op(object, op) < 0)
948 BUG(); 952 goto submit_op_failed;
949 spin_unlock(&cookie->lock); 953 spin_unlock(&cookie->lock);
950 fscache_put_operation(op); 954 fscache_put_operation(op);
951 955
@@ -960,4 +964,11 @@ static void fscache_invalidate_object(struct fscache_object *object)
960 */ 964 */
961 fscache_invalidation_complete(cookie); 965 fscache_invalidation_complete(cookie);
962 _leave(""); 966 _leave("");
967 return;
968
969submit_op_failed:
970 spin_unlock(&cookie->lock);
971 kfree(op);
972 fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
973 _leave(" [EIO]");
963} 974}
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index c58dbe613266..9e6b7d232bb1 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -84,6 +84,8 @@ static void fscache_run_op(struct fscache_object *object,
84int fscache_submit_exclusive_op(struct fscache_object *object, 84int fscache_submit_exclusive_op(struct fscache_object *object,
85 struct fscache_operation *op) 85 struct fscache_operation *op)
86{ 86{
87 int ret;
88
87 _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); 89 _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
88 90
89 ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); 91 ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
@@ -116,6 +118,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
116 118
117 /* need to issue a new write op after this */ 119 /* need to issue a new write op after this */
118 clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); 120 clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
121 ret = 0;
119 } else if (object->state == FSCACHE_OBJECT_CREATING) { 122 } else if (object->state == FSCACHE_OBJECT_CREATING) {
120 op->object = object; 123 op->object = object;
121 object->n_ops++; 124 object->n_ops++;
@@ -123,13 +126,17 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
123 atomic_inc(&op->usage); 126 atomic_inc(&op->usage);
124 list_add_tail(&op->pend_link, &object->pending_ops); 127 list_add_tail(&op->pend_link, &object->pending_ops);
125 fscache_stat(&fscache_n_op_pend); 128 fscache_stat(&fscache_n_op_pend);
129 ret = 0;
126 } else { 130 } else {
127 /* not allowed to submit ops in any other state */ 131 /* If we're in any other state, there must have been an I/O
128 BUG(); 132 * error of some nature.
133 */
134 ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags));
135 ret = -EIO;
129 } 136 }
130 137
131 spin_unlock(&object->lock); 138 spin_unlock(&object->lock);
132 return 0; 139 return ret;
133} 140}
134 141
135/* 142/*