diff options
Diffstat (limited to 'fs/fscache/operation.c')
| -rw-r--r-- | fs/fscache/operation.c | 140 |
1 files changed, 108 insertions, 32 deletions
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 30afdfa7aec7..762a9ec4ffa4 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
| @@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
| 37 | ASSERT(op->processor != NULL); | 37 | ASSERT(op->processor != NULL); |
| 38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
| 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
| 40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
| 40 | 41 | ||
| 41 | fscache_stat(&fscache_n_op_enqueue); | 42 | fscache_stat(&fscache_n_op_enqueue); |
| 42 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
| @@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
| 64 | static void fscache_run_op(struct fscache_object *object, | 65 | static void fscache_run_op(struct fscache_object *object, |
| 65 | struct fscache_operation *op) | 66 | struct fscache_operation *op) |
| 66 | { | 67 | { |
| 68 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
| 69 | |||
| 70 | op->state = FSCACHE_OP_ST_IN_PROGRESS; | ||
| 67 | object->n_in_progress++; | 71 | object->n_in_progress++; |
| 68 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 72 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
| 69 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 73 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
| @@ -84,18 +88,21 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
| 84 | 88 | ||
| 85 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 89 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
| 86 | 90 | ||
| 91 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
| 92 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
| 93 | |||
| 87 | spin_lock(&object->lock); | 94 | spin_lock(&object->lock); |
| 88 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 95 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
| 89 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 96 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
| 90 | ASSERT(list_empty(&op->pend_link)); | 97 | ASSERT(list_empty(&op->pend_link)); |
| 91 | 98 | ||
| 92 | ret = -ENOBUFS; | 99 | op->state = FSCACHE_OP_ST_PENDING; |
| 93 | if (fscache_object_is_active(object)) { | 100 | if (fscache_object_is_active(object)) { |
| 94 | op->object = object; | 101 | op->object = object; |
| 95 | object->n_ops++; | 102 | object->n_ops++; |
| 96 | object->n_exclusive++; /* reads and writes must wait */ | 103 | object->n_exclusive++; /* reads and writes must wait */ |
| 97 | 104 | ||
| 98 | if (object->n_ops > 1) { | 105 | if (object->n_in_progress > 0) { |
| 99 | atomic_inc(&op->usage); | 106 | atomic_inc(&op->usage); |
| 100 | list_add_tail(&op->pend_link, &object->pending_ops); | 107 | list_add_tail(&op->pend_link, &object->pending_ops); |
| 101 | fscache_stat(&fscache_n_op_pend); | 108 | fscache_stat(&fscache_n_op_pend); |
| @@ -121,8 +128,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
| 121 | fscache_stat(&fscache_n_op_pend); | 128 | fscache_stat(&fscache_n_op_pend); |
| 122 | ret = 0; | 129 | ret = 0; |
| 123 | } else { | 130 | } else { |
| 124 | /* not allowed to submit ops in any other state */ | 131 | /* If we're in any other state, there must have been an I/O |
| 125 | BUG(); | 132 | * error of some nature. |
| 133 | */ | ||
| 134 | ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags)); | ||
| 135 | ret = -EIO; | ||
| 126 | } | 136 | } |
| 127 | 137 | ||
| 128 | spin_unlock(&object->lock); | 138 | spin_unlock(&object->lock); |
| @@ -186,6 +196,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
| 186 | _enter("{OBJ%x OP%x},{%u}", | 196 | _enter("{OBJ%x OP%x},{%u}", |
| 187 | object->debug_id, op->debug_id, atomic_read(&op->usage)); | 197 | object->debug_id, op->debug_id, atomic_read(&op->usage)); |
| 188 | 198 | ||
| 199 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
| 189 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 200 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
| 190 | 201 | ||
| 191 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
| @@ -196,6 +207,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
| 196 | ostate = object->state; | 207 | ostate = object->state; |
| 197 | smp_rmb(); | 208 | smp_rmb(); |
| 198 | 209 | ||
| 210 | op->state = FSCACHE_OP_ST_PENDING; | ||
| 199 | if (fscache_object_is_active(object)) { | 211 | if (fscache_object_is_active(object)) { |
| 200 | op->object = object; | 212 | op->object = object; |
| 201 | object->n_ops++; | 213 | object->n_ops++; |
| @@ -225,12 +237,15 @@ int fscache_submit_op(struct fscache_object *object, | |||
| 225 | object->state == FSCACHE_OBJECT_LC_DYING || | 237 | object->state == FSCACHE_OBJECT_LC_DYING || |
| 226 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | 238 | object->state == FSCACHE_OBJECT_WITHDRAWING) { |
| 227 | fscache_stat(&fscache_n_op_rejected); | 239 | fscache_stat(&fscache_n_op_rejected); |
| 240 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
| 228 | ret = -ENOBUFS; | 241 | ret = -ENOBUFS; |
| 229 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 242 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
| 230 | fscache_report_unexpected_submission(object, op, ostate); | 243 | fscache_report_unexpected_submission(object, op, ostate); |
| 231 | ASSERT(!fscache_object_is_active(object)); | 244 | ASSERT(!fscache_object_is_active(object)); |
| 245 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
| 232 | ret = -ENOBUFS; | 246 | ret = -ENOBUFS; |
| 233 | } else { | 247 | } else { |
| 248 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
| 234 | ret = -ENOBUFS; | 249 | ret = -ENOBUFS; |
| 235 | } | 250 | } |
| 236 | 251 | ||
| @@ -283,20 +298,28 @@ void fscache_start_operations(struct fscache_object *object) | |||
| 283 | /* | 298 | /* |
| 284 | * cancel an operation that's pending on an object | 299 | * cancel an operation that's pending on an object |
| 285 | */ | 300 | */ |
| 286 | int fscache_cancel_op(struct fscache_operation *op) | 301 | int fscache_cancel_op(struct fscache_operation *op, |
| 302 | void (*do_cancel)(struct fscache_operation *)) | ||
| 287 | { | 303 | { |
| 288 | struct fscache_object *object = op->object; | 304 | struct fscache_object *object = op->object; |
| 289 | int ret; | 305 | int ret; |
| 290 | 306 | ||
| 291 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | 307 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); |
| 292 | 308 | ||
| 309 | ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING); | ||
| 310 | ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED); | ||
| 311 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
| 312 | |||
| 293 | spin_lock(&object->lock); | 313 | spin_lock(&object->lock); |
| 294 | 314 | ||
| 295 | ret = -EBUSY; | 315 | ret = -EBUSY; |
| 296 | if (!list_empty(&op->pend_link)) { | 316 | if (op->state == FSCACHE_OP_ST_PENDING) { |
| 317 | ASSERT(!list_empty(&op->pend_link)); | ||
| 297 | fscache_stat(&fscache_n_op_cancelled); | 318 | fscache_stat(&fscache_n_op_cancelled); |
| 298 | list_del_init(&op->pend_link); | 319 | list_del_init(&op->pend_link); |
| 299 | object->n_ops--; | 320 | if (do_cancel) |
| 321 | do_cancel(op); | ||
| 322 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
| 300 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | 323 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) |
| 301 | object->n_exclusive--; | 324 | object->n_exclusive--; |
| 302 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 325 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
| @@ -311,6 +334,70 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
| 311 | } | 334 | } |
| 312 | 335 | ||
| 313 | /* | 336 | /* |
| 337 | * Cancel all pending operations on an object | ||
| 338 | */ | ||
| 339 | void fscache_cancel_all_ops(struct fscache_object *object) | ||
| 340 | { | ||
| 341 | struct fscache_operation *op; | ||
| 342 | |||
| 343 | _enter("OBJ%x", object->debug_id); | ||
| 344 | |||
| 345 | spin_lock(&object->lock); | ||
| 346 | |||
| 347 | while (!list_empty(&object->pending_ops)) { | ||
| 348 | op = list_entry(object->pending_ops.next, | ||
| 349 | struct fscache_operation, pend_link); | ||
| 350 | fscache_stat(&fscache_n_op_cancelled); | ||
| 351 | list_del_init(&op->pend_link); | ||
| 352 | |||
| 353 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
| 354 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
| 355 | |||
| 356 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
| 357 | object->n_exclusive--; | ||
| 358 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
| 359 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
| 360 | fscache_put_operation(op); | ||
| 361 | cond_resched_lock(&object->lock); | ||
| 362 | } | ||
| 363 | |||
| 364 | spin_unlock(&object->lock); | ||
| 365 | _leave(""); | ||
| 366 | } | ||
| 367 | |||
| 368 | /* | ||
| 369 | * Record the completion or cancellation of an in-progress operation. | ||
| 370 | */ | ||
| 371 | void fscache_op_complete(struct fscache_operation *op, bool cancelled) | ||
| 372 | { | ||
| 373 | struct fscache_object *object = op->object; | ||
| 374 | |||
| 375 | _enter("OBJ%x", object->debug_id); | ||
| 376 | |||
| 377 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
| 378 | ASSERTCMP(object->n_in_progress, >, 0); | ||
| 379 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
| 380 | object->n_exclusive, >, 0); | ||
| 381 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
| 382 | object->n_in_progress, ==, 1); | ||
| 383 | |||
| 384 | spin_lock(&object->lock); | ||
| 385 | |||
| 386 | op->state = cancelled ? | ||
| 387 | FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE; | ||
| 388 | |||
| 389 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
| 390 | object->n_exclusive--; | ||
| 391 | object->n_in_progress--; | ||
| 392 | if (object->n_in_progress == 0) | ||
| 393 | fscache_start_operations(object); | ||
| 394 | |||
| 395 | spin_unlock(&object->lock); | ||
| 396 | _leave(""); | ||
| 397 | } | ||
| 398 | EXPORT_SYMBOL(fscache_op_complete); | ||
| 399 | |||
| 400 | /* | ||
| 314 | * release an operation | 401 | * release an operation |
| 315 | * - queues pending ops if this is the last in-progress op | 402 | * - queues pending ops if this is the last in-progress op |
| 316 | */ | 403 | */ |
| @@ -328,8 +415,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
| 328 | return; | 415 | return; |
| 329 | 416 | ||
| 330 | _debug("PUT OP"); | 417 | _debug("PUT OP"); |
| 331 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 418 | ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE, |
| 332 | BUG(); | 419 | op->state, ==, FSCACHE_OP_ST_CANCELLED); |
| 420 | op->state = FSCACHE_OP_ST_DEAD; | ||
| 333 | 421 | ||
| 334 | fscache_stat(&fscache_n_op_release); | 422 | fscache_stat(&fscache_n_op_release); |
| 335 | 423 | ||
| @@ -340,8 +428,14 @@ void fscache_put_operation(struct fscache_operation *op) | |||
| 340 | 428 | ||
| 341 | object = op->object; | 429 | object = op->object; |
| 342 | 430 | ||
| 343 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | 431 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { |
| 344 | atomic_dec(&object->n_reads); | 432 | if (atomic_dec_and_test(&object->n_reads)) { |
| 433 | clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, | ||
| 434 | &object->cookie->flags); | ||
| 435 | wake_up_bit(&object->cookie->flags, | ||
| 436 | FSCACHE_COOKIE_WAITING_ON_READS); | ||
| 437 | } | ||
| 438 | } | ||
| 345 | 439 | ||
| 346 | /* now... we may get called with the object spinlock held, so we | 440 | /* now... we may get called with the object spinlock held, so we |
| 347 | * complete the cleanup here only if we can immediately acquire the | 441 | * complete the cleanup here only if we can immediately acquire the |
| @@ -359,16 +453,6 @@ void fscache_put_operation(struct fscache_operation *op) | |||
| 359 | return; | 453 | return; |
| 360 | } | 454 | } |
| 361 | 455 | ||
| 362 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
| 363 | ASSERTCMP(object->n_exclusive, >, 0); | ||
| 364 | object->n_exclusive--; | ||
| 365 | } | ||
| 366 | |||
| 367 | ASSERTCMP(object->n_in_progress, >, 0); | ||
| 368 | object->n_in_progress--; | ||
| 369 | if (object->n_in_progress == 0) | ||
| 370 | fscache_start_operations(object); | ||
| 371 | |||
| 372 | ASSERTCMP(object->n_ops, >, 0); | 456 | ASSERTCMP(object->n_ops, >, 0); |
| 373 | object->n_ops--; | 457 | object->n_ops--; |
| 374 | if (object->n_ops == 0) | 458 | if (object->n_ops == 0) |
| @@ -407,23 +491,14 @@ void fscache_operation_gc(struct work_struct *work) | |||
| 407 | spin_unlock(&cache->op_gc_list_lock); | 491 | spin_unlock(&cache->op_gc_list_lock); |
| 408 | 492 | ||
| 409 | object = op->object; | 493 | object = op->object; |
| 494 | spin_lock(&object->lock); | ||
| 410 | 495 | ||
| 411 | _debug("GC DEFERRED REL OBJ%x OP%x", | 496 | _debug("GC DEFERRED REL OBJ%x OP%x", |
| 412 | object->debug_id, op->debug_id); | 497 | object->debug_id, op->debug_id); |
| 413 | fscache_stat(&fscache_n_op_gc); | 498 | fscache_stat(&fscache_n_op_gc); |
| 414 | 499 | ||
| 415 | ASSERTCMP(atomic_read(&op->usage), ==, 0); | 500 | ASSERTCMP(atomic_read(&op->usage), ==, 0); |
| 416 | 501 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD); | |
| 417 | spin_lock(&object->lock); | ||
| 418 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
| 419 | ASSERTCMP(object->n_exclusive, >, 0); | ||
| 420 | object->n_exclusive--; | ||
| 421 | } | ||
| 422 | |||
| 423 | ASSERTCMP(object->n_in_progress, >, 0); | ||
| 424 | object->n_in_progress--; | ||
| 425 | if (object->n_in_progress == 0) | ||
| 426 | fscache_start_operations(object); | ||
| 427 | 502 | ||
| 428 | ASSERTCMP(object->n_ops, >, 0); | 503 | ASSERTCMP(object->n_ops, >, 0); |
| 429 | object->n_ops--; | 504 | object->n_ops--; |
| @@ -431,6 +506,7 @@ void fscache_operation_gc(struct work_struct *work) | |||
| 431 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); | 506 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); |
| 432 | 507 | ||
| 433 | spin_unlock(&object->lock); | 508 | spin_unlock(&object->lock); |
| 509 | kfree(op); | ||
| 434 | 510 | ||
| 435 | } while (count++ < 20); | 511 | } while (count++ < 20); |
| 436 | 512 | ||
