| 277 | } |
| 278 | |
| 279 | static void write_block_finalize(struct ternfs_transient_span* span, int b, u64 proof, int block_write_err) { |
| 280 | int i; |
| 281 | int B = ternfs_blocks(span->parity); |
| 282 | struct ternfs_inode* enode = span->enode; |
| 283 | |
| 284 | ternfs_debug("block=%d proof=%016llx err=%d", b, proof, block_write_err); |
| 285 | |
| 286 | bool finished_writing = true; |
| 287 | bool any_block_errs = false; |
| 288 | // Mark the current one as done/error out, and check if we're done with all block |
| 289 | // writing requests. |
| 290 | spin_lock_bh(&span->lock); |
| 291 | for (i = 0; i < B; i++) { |
| 292 | BUG_ON(span->block_ids[i] == 0); |
| 293 | if (i == b) { |
| 294 | if (block_write_err == 0) { |
| 295 | span->blocks_proofs[i] = proof; |
| 296 | } else { |
| 297 | span->blocks_errs[i] = block_write_err; |
| 298 | } |
| 299 | } else if (span->blocks_proofs[i] == 0 && span->blocks_errs[i] == 0) { |
| 300 | // we're waiting on some other block proof. |
| 301 | finished_writing = false; |
| 302 | } |
| 303 | any_block_errs = any_block_errs || (span->blocks_errs[i] != 0); |
| 304 | } |
| 305 | spin_unlock_bh(&span->lock); |
| 306 | |
| 307 | int err = 0; |
| 308 | if (finished_writing && likely(!any_block_errs)) { |
| 309 | // TODO just like in the other case, would be nicer to have this async, since we're in a queue here. |
| 310 | err = ternfs_error_to_linux(ternfs_shard_add_span_certify( |
| 311 | (struct ternfs_fs_info*)enode->inode.i_sb->s_fs_info, |
| 312 | enode->inode.i_ino, enode->file.cookie, span->offset, span->parity, |
| 313 | span->block_ids, span->blocks_proofs |
| 314 | )); |
| 315 | } |
| 316 | |
| 317 | if (finished_writing) { |
| 318 | span->attempts++; |
| 319 | if (unlikely(err == 0 && any_block_errs)) { |
| 320 | // if we failed writing blocks, consider retrying |
| 321 | err = retry_after_block_error(span); |
| 322 | } |
| 323 | atomic_cmpxchg(&enode->file.transient_err, 0, err); |
| 324 | } |
| 325 | // waiters will be woken up once span ref count reaches 0 |
| 326 | put_transient_span(span); |
| 327 | } |
| 328 | |
| 329 | static void write_block_done(void* data, struct list_head* pages, u64 block_id, u64 proof, int block_write_err) { |
| 330 | // We need to be careful with locking here: the writer waits on the |
no test coverage detected