diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-12-08 14:36:45 -0900 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:41:25 -0900 |
commit | 755abaff012ff855012d66802f53336162956ac1 (patch) | |
tree | e512fe7c3a51486a8b01be4cc2d95b2a6567a57b | |
parent | b55f2f3b3452ba86edc662f3c907470f1f2d9a49 (diff) |
bcache: Refactor write path to not split bios unnecessarily
compression code is a good deal saner now, too
-rw-r--r-- | drivers/md/bcache/alloc.c | 46 | ||||
-rw-r--r-- | drivers/md/bcache/alloc.h | 7 | ||||
-rw-r--r-- | drivers/md/bcache/compress.c | 203 | ||||
-rw-r--r-- | drivers/md/bcache/compress.h | 6 | ||||
-rw-r--r-- | drivers/md/bcache/io.c | 208 | ||||
-rw-r--r-- | include/trace/events/bcache.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/bcache.h | 2 |
7 files changed, 229 insertions, 248 deletions
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 376721461381..ac40a96b381e 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -1294,12 +1294,10 @@ static struct open_bucket *lock_writepoint(struct cache_set *c, static int open_bucket_add_buckets(struct cache_set *c, struct write_point *wp, struct open_bucket *ob, - struct bkey_i_extent *e, unsigned nr_replicas, enum alloc_reserve reserve, struct closure *cl) { - const struct bch_extent_ptr *ptr; long caches_used[BITS_TO_LONGS(MAX_CACHES_PER_SET)]; int i, dst; @@ -1311,14 +1309,11 @@ static int open_bucket_add_buckets(struct cache_set *c, */ /* Short circuit all the fun stuff if posssible: */ - if (!bkey_val_u64s(&e->k) && ob->nr_ptrs >= nr_replicas) + if (ob->nr_ptrs >= nr_replicas) return 0; memset(caches_used, 0, sizeof(caches_used)); - extent_for_each_ptr(extent_i_to_s_c(e), ptr) - __set_bit(ptr->dev, caches_used); - /* * Shuffle pointers to devices we already have to the end: * bch_bucket_alloc_set() will add new pointers to the statr of @b, and @@ -1343,7 +1338,6 @@ static int open_bucket_add_buckets(struct cache_set *c, */ struct open_bucket *bch_alloc_sectors_start(struct cache_set *c, struct write_point *wp, - struct bkey_i_extent *e, unsigned nr_replicas, enum alloc_reserve reserve, struct closure *cl) @@ -1398,7 +1392,7 @@ retry: ob = new_ob; } - ret = open_bucket_add_buckets(c, wp, ob, e, nr_replicas, + ret = open_bucket_add_buckets(c, wp, ob, nr_replicas, reserve, cl); if (ret) { mutex_unlock(&ob->lock); @@ -1417,11 +1411,10 @@ retry: * Append pointers to the space we just allocated to @k, and mark @sectors space * as allocated out of @ob */ -void bch_alloc_sectors_done(struct cache_set *c, struct write_point *wp, - struct bkey_i_extent *e, unsigned nr_replicas, - struct open_bucket *ob, unsigned sectors) +void bch_alloc_sectors_append_ptrs(struct cache_set *c, struct bkey_i_extent *e, + unsigned nr_replicas, struct open_bucket *ob, + unsigned sectors) { - struct cache_member_rcu *mi = cache_member_info_get(c); struct bch_extent_ptr tmp, *ptr; struct cache *ca; bool has_data = false; @@ -1450,22 +1443,37 @@ void bch_alloc_sectors_done(struct cache_set *c, struct write_point *wp, extent_ptr_append(e, tmp); ob->ptr_offset[i] += sectors; + } + + open_bucket_for_each_online_device(c, ob, ptr, ca) + this_cpu_add(*ca->sectors_written, sectors); +} +/* + * Append pointers to the space we just allocated to @k, and mark @sectors space + * as allocated out of @ob + */ +void bch_alloc_sectors_done(struct cache_set *c, struct write_point *wp, + struct open_bucket *ob) +{ + struct cache_member_rcu *mi = cache_member_info_get(c); + bool has_data = false; + unsigned i; + + for (i = 0; i < ob->nr_ptrs; i++) { if (!ob_ptr_sectors_free(ob, mi, &ob->ptrs[i])) ob->has_full_ptrs = true; else has_data = true; } + cache_member_info_put(); + if (likely(has_data)) atomic_inc(&ob->pin); else BUG_ON(xchg(&wp->b, NULL) != ob); - open_bucket_for_each_online_device(c, ob, ptr, ca) - this_cpu_add(*ca->sectors_written, sectors); - cache_member_info_put(); - mutex_unlock(&ob->lock); } @@ -1495,14 +1503,16 @@ struct open_bucket *bch_alloc_sectors(struct cache_set *c, { struct open_bucket *ob; - ob = bch_alloc_sectors_start(c, wp, e, nr_replicas, reserve, cl); + ob = bch_alloc_sectors_start(c, wp, nr_replicas, reserve, cl); if (IS_ERR_OR_NULL(ob)) return ob; if (e->k.size > ob->sectors_free) bch_key_resize(&e->k, ob->sectors_free); - bch_alloc_sectors_done(c, wp, e, nr_replicas, ob, e->k.size); + bch_alloc_sectors_append_ptrs(c, e, nr_replicas, ob, e->k.size); + + bch_alloc_sectors_done(c, wp, ob); return ob; } diff --git a/drivers/md/bcache/alloc.h b/drivers/md/bcache/alloc.h index d3d82fd994be..c39f43e02e80 100644 --- a/drivers/md/bcache/alloc.h +++ b/drivers/md/bcache/alloc.h @@ -17,12 +17,13 @@ void bch_open_bucket_put(struct cache_set *, struct open_bucket *); struct open_bucket *bch_alloc_sectors_start(struct cache_set *, struct write_point *, - struct bkey_i_extent *, unsigned, enum alloc_reserve, struct closure *); + +void bch_alloc_sectors_append_ptrs(struct cache_set *, struct bkey_i_extent *, + unsigned, struct open_bucket *, unsigned); void bch_alloc_sectors_done(struct cache_set *, struct write_point *, - struct bkey_i_extent *, unsigned, - struct open_bucket *, unsigned); + struct open_bucket *); struct open_bucket *bch_alloc_sectors(struct cache_set *, struct write_point *, struct bkey_i_extent *, unsigned, diff --git a/drivers/md/bcache/compress.c b/drivers/md/bcache/compress.c index a4f30bc32e64..f7bfd57f9578 100644 --- a/drivers/md/bcache/compress.c +++ b/drivers/md/bcache/compress.c @@ -44,13 +44,13 @@ static void *__bio_map_or_bounce(struct cache_set *c, struct bio_vec bv; struct bvec_iter iter; unsigned nr_pages = 0; - struct page *stack_pages[4]; + struct page *stack_pages[16]; struct page **pages = NULL; bool first = true; unsigned prev_end = PAGE_SIZE; void *data; - BUG_ON(start.bi_size > (BCH_COMPRESSED_EXTENT_MAX << 9)); + BUG_ON(bvec_iter_sectors(start) > BCH_COMPRESSED_EXTENT_MAX); *bounced = BOUNCED_MAPPED; @@ -178,13 +178,14 @@ err: } int bch_bio_uncompress_inplace(struct cache_set *c, struct bio *bio, - struct bkey *k, struct bch_extent_crc64 crc) + unsigned live_data_sectors, + struct bch_extent_crc64 crc) { void *dst_data = NULL; size_t dst_len = crc.uncompressed_size << 9; int ret = -ENOMEM; - BUG_ON(DIV_ROUND_UP(k->size, PAGE_SECTORS) > bio->bi_max_vecs); + BUG_ON(DIV_ROUND_UP(live_data_sectors, PAGE_SECTORS) > bio->bi_max_vecs); /* XXX mempoolify */ dst_data = kmalloc(dst_len, GFP_NOIO|__GFP_NOWARN); @@ -198,7 +199,7 @@ int bch_bio_uncompress_inplace(struct cache_set *c, struct bio *bio, if (ret) goto err; - while (bio->bi_vcnt < DIV_ROUND_UP(k->size, PAGE_SECTORS)) { + while (bio->bi_vcnt < DIV_ROUND_UP(live_data_sectors, PAGE_SECTORS)) { struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt]; bv->bv_page = alloc_page(GFP_NOIO); @@ -210,7 +211,7 @@ int bch_bio_uncompress_inplace(struct cache_set *c, struct bio *bio, bio->bi_vcnt++; } - bio->bi_iter.bi_size = k->size << 9; + bio->bi_iter.bi_size = live_data_sectors << 9; copy_data: memcpy_to_bio(bio, bio->bi_iter, dst_data + (crc.offset << 9)); err: @@ -224,7 +225,7 @@ use_mempool: */ bch_bio_free_pages_pool(c, bio); - bch_bio_alloc_pages_pool(c, bio, k->size << 9); + bch_bio_alloc_pages_pool(c, bio, live_data_sectors << 9); goto copy_data; } @@ -252,59 +253,60 @@ err: return ret; } -static struct bio *__bio_compress(struct cache_set *c, - unsigned compression_type, - struct bio *src, - unsigned output_available, - int *input_consumed) +static int __bio_compress(struct cache_set *c, + struct bio *dst, size_t *dst_len, + struct bio *src, size_t *src_len, + unsigned compression_type) { - struct bio *dst; void *src_data = NULL, *dst_data = NULL; - unsigned src_bounced, dst_bounced; + unsigned src_bounced, dst_bounced, pad; int ret = -1; - BUG_ON(output_available > src->bi_iter.bi_size); - - output_available = min_t(unsigned, output_available, - BCH_COMPRESSED_EXTENT_MAX << 9); - - dst = bio_alloc_bioset(GFP_NOIO, - DIV_ROUND_UP(output_available, PAGE_SIZE), - &c->bio_write); - - bch_bio_alloc_pages_pool(c, dst, output_available); - dst_data = bio_map_or_bounce(c, dst, &dst_bounced, WRITE); src_data = bio_map_or_bounce(c, src, &src_bounced, READ); switch (compression_type) { case BCH_COMPRESSION_LZ4: { void *workspace; - size_t dst_size = dst->bi_iter.bi_size; + + *dst_len = dst->bi_iter.bi_size; + *src_len = src->bi_iter.bi_size; workspace = mempool_alloc(&c->lz4_workspace_pool, GFP_NOIO); +retry_compress: + ret = lz4_compress(src_data, *src_len, + dst_data, dst_len, + workspace); /* - * XXX: due to the way the interface to lz4_compress works, we - * can't consume more than output_available bytes of input (even - * though a lot more might fit after compressing) + * On error, the compressed data was bigger than dst_len, and + * -ret is the amount of data we were able to compress - round + * down to nearest block and try again: */ - ret = lz4_compress(src_data, min(output_available, - src->bi_iter.bi_size), - dst_data, &dst_size, workspace); + if (ret && round_down(-ret, block_bytes(c)) > *dst_len) { + BUG_ON(ret > 0); + + /* not supposed to happen */ + if (WARN_ON(-ret >= *src_len)) + goto err; + *src_len = round_down(-ret, block_bytes(c)); + if (!*src_len) + goto err; + + goto retry_compress; + } mempool_free(workspace, &c->lz4_workspace_pool); + if (ret) goto err; - - dst->bi_iter.bi_size = dst_size; - *input_consumed = output_available; break; } case BCH_COMPRESSION_GZIP: { void *workspace; z_stream strm; - workspace = kmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL), + workspace = kmalloc(zlib_deflate_workspacesize(MAX_WBITS, + DEF_MEM_LEVEL), GFP_NOIO|__GFP_NOWARN); if (!workspace) { mutex_lock(&c->zlib_workspace_lock); @@ -313,9 +315,10 @@ static struct bio *__bio_compress(struct cache_set *c, strm.workspace = workspace; strm.next_in = src_data; - strm.avail_in = output_available; + strm.avail_in = min(src->bi_iter.bi_size, + dst->bi_iter.bi_size); strm.next_out = dst_data; - strm.avail_out = output_available; + strm.avail_out = dst->bi_iter.bi_size; zlib_deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); @@ -342,100 +345,64 @@ zlib_err: if (ret) goto err; - BUG_ON(strm.total_in != output_available); - - dst->bi_iter.bi_size = strm.total_out; - *input_consumed = strm.total_in; + *dst_len = strm.total_out; + *src_len = strm.total_in; break; } default: BUG(); } - BUG_ON(!dst->bi_iter.bi_size); + BUG_ON(!*dst_len); + + /* Didn't get smaller: */ + if (round_up(*dst_len, block_bytes(c)) >= *src_len) { + ret = -1; + goto err; + } + + pad = round_up(*dst_len, block_bytes(c)) - *dst_len; + + memset(dst_data + *dst_len, 0, pad); + *dst_len += pad; if (dst_bounced) memcpy_to_bio(dst, dst->bi_iter, dst_data); -out: +err: bio_unmap_or_unbounce(c, src_data, src_bounced, READ); bio_unmap_or_unbounce(c, dst_data, dst_bounced, WRITE); - - if (!ret) - while (dst->bi_vcnt * PAGE_SIZE > - round_up(dst->bi_iter.bi_size, PAGE_SIZE)) - mempool_free(dst->bi_io_vec[--dst->bi_vcnt].bv_page, - &c->bio_bounce_pages); - - return dst; -err: - ret = -1; - *input_consumed = -1; - goto out; + return ret; } -struct bio *bch_bio_compress(struct cache_set *c, struct bio *src, - unsigned *compression_type, - unsigned output_available) +void bch_bio_compress(struct cache_set *c, + struct bio *dst, size_t *dst_len, + struct bio *src, size_t *src_len, + unsigned *compression_type) { - struct bio *dst = NULL; - int input_consumed; - - /* if it's only one block, don't bother trying to compress: */ - if (bio_sectors(src) <= c->sb.block_size) - *compression_type = BCH_COMPRESSION_NONE; - - switch (*compression_type) { - case BCH_COMPRESSION_NONE: - /* Just bounce it, for stable checksums: */ -copy: - if (!dst) - dst = bio_alloc_bioset(GFP_NOIO, - DIV_ROUND_UP(output_available, PAGE_SIZE), - &c->bio_write); - bch_bio_alloc_pages_pool(c, dst, output_available); - bio_copy_data(dst, src); - input_consumed = output_available; - goto advance; - case BCH_COMPRESSION_LZ4: - case BCH_COMPRESSION_GZIP: - dst = __bio_compress(c, *compression_type, src, - output_available, &input_consumed); - break; - default: - BUG(); - } - - if ((int) round_up(dst->bi_iter.bi_size, - block_bytes(c)) >= input_consumed) { - /* Failed to compress (didn't get smaller): */ - *compression_type = BCH_COMPRESSION_NONE; - goto copy; - } - - /* Pad to blocksize, and zero out padding: */ - while (dst->bi_iter.bi_size & (block_bytes(c) - 1)) { - unsigned idx = dst->bi_iter.bi_size >> PAGE_SHIFT; - unsigned offset = dst->bi_iter.bi_size & (PAGE_SIZE - 1); - unsigned bytes = (PAGE_SIZE - offset) & (block_bytes(c) - 1); - - if (idx < dst->bi_vcnt) { - struct bio_vec *bv = &dst->bi_io_vec[idx]; - - memset(page_address(bv->bv_page) + offset, 0, bytes); - } else { - dst->bi_io_vec[dst->bi_vcnt++] = (struct bio_vec) { - .bv_page = ZERO_PAGE(0), - .bv_len = PAGE_SIZE, - .bv_offset = 0, - }; - } - - dst->bi_iter.bi_size += bytes; - } -advance: - bio_advance(src, input_consumed); - - return dst; + unsigned orig_dst = dst->bi_iter.bi_size; + unsigned orig_src = src->bi_iter.bi_size; + + /* Don't consume more than BCH_COMPRESSED_EXTENT_MAX from @src: */ + src->bi_iter.bi_size = + min(src->bi_iter.bi_size, BCH_COMPRESSED_EXTENT_MAX << 9); + + /* Don't generate a bigger output than input: */ + dst->bi_iter.bi_size = + min(dst->bi_iter.bi_size, src->bi_iter.bi_size); + + /* If it's only one block, don't bother trying to compress: */ + if (*compression_type != BCH_COMPRESSION_NONE && + bio_sectors(src) > c->sb.block_size && + !__bio_compress(c, dst, dst_len, src, src_len, *compression_type)) + goto out; + + /* If compressing failed (didn't get smaller), just copy: */ + *compression_type = BCH_COMPRESSION_NONE; + *dst_len = *src_len = min(dst->bi_iter.bi_size, src->bi_iter.bi_size); + bio_copy_data(dst, src); +out: + dst->bi_iter.bi_size = orig_dst; + src->bi_iter.bi_size = orig_src; } void bch_compress_free(struct cache_set *c) diff --git a/drivers/md/bcache/compress.h b/drivers/md/bcache/compress.h index 2b5dded6f59f..02578ef73c9a 100644 --- a/drivers/md/bcache/compress.h +++ b/drivers/md/bcache/compress.h @@ -2,11 +2,11 @@ #define _BCACHE_COMPRESS_H int bch_bio_uncompress_inplace(struct cache_set *, struct bio *, - struct bkey *, struct bch_extent_crc64); + unsigned, struct bch_extent_crc64); int bch_bio_uncompress(struct cache_set *, struct bio *, struct bio *, struct bvec_iter, struct bch_extent_crc64); -struct bio *bch_bio_compress(struct cache_set *, struct bio *, - unsigned *, unsigned); +void bch_bio_compress(struct cache_set *, struct bio *, size_t *, + struct bio *, size_t *, unsigned *); void bch_compress_free(struct cache_set *); int bch_compress_init(struct cache_set *); diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index d0dd6df459d6..7219b658dd05 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -380,14 +380,41 @@ static void bch_write_endio(struct bio *bio) closure_put(cl); } +static void init_append_extent(struct bch_write_op *op, + unsigned compressed_size, + unsigned uncompressed_size, + unsigned compression_type, + u64 csum, unsigned csum_type, + struct open_bucket *ob) +{ + struct bkey_i_extent *e = bkey_extent_init(op->insert_keys.top); + + op->pos.offset += uncompressed_size; + e->k.p = op->pos; + e->k.size = uncompressed_size; + + bch_extent_crc_append(e, compressed_size, + uncompressed_size, + compression_type, + csum, csum_type); + + bch_alloc_sectors_append_ptrs(op->c, e, op->nr_replicas, + ob, compressed_size); + + bkey_extent_set_cached(&e->k, (op->flags & BCH_WRITE_CACHED)); + bch_keylist_push(&op->insert_keys); +} + static int bch_write_extent(struct bch_write_op *op, struct open_bucket *ob, - struct bkey_i_extent *e, struct bio *orig) { struct cache_set *c = op->c; struct bio *bio; struct bch_write_bio *wbio; + unsigned key_to_write_offset = op->insert_keys.top_p - + op->insert_keys.keys_p; + struct bkey_i *key_to_write; unsigned csum_type = c->opts.data_checksum; unsigned compression_type = op->compression_type; int ret; @@ -397,11 +424,11 @@ static int bch_write_extent(struct bch_write_op *op, /* Need to decompress data? */ if ((op->flags & BCH_WRITE_DATA_COMPRESSED) && - (op->crc.uncompressed_size != e->k.size || + (op->crc.uncompressed_size != op->size || op->crc.compressed_size > ob->sectors_free)) { int ret; - ret = bch_bio_uncompress_inplace(c, orig, &e->k, op->crc); + ret = bch_bio_uncompress_inplace(c, orig, op->size, op->crc); if (ret) return ret; @@ -409,15 +436,13 @@ static int bch_write_extent(struct bch_write_op *op, } if (op->flags & BCH_WRITE_DATA_COMPRESSED) { - bch_extent_crc_append(e, - op->crc.compressed_size, - op->crc.uncompressed_size, - op->crc.compression_type, - op->crc.csum, - op->crc.csum_type); - bch_alloc_sectors_done(op->c, op->wp, - e, op->nr_replicas, - ob, bio_sectors(orig)); + init_append_extent(op, + op->crc.compressed_size, + op->crc.uncompressed_size, + op->crc.compression_type, + op->crc.csum, + op->crc.csum_type, + ob); bio = orig; wbio = to_wbio(bio); @@ -428,90 +453,84 @@ static int bch_write_extent(struct bch_write_op *op, } else if (csum_type != BCH_CSUM_NONE || compression_type != BCH_COMPRESSION_NONE) { /* all units here in bytes */ - unsigned output_available, extra_input, - orig_input = orig->bi_iter.bi_size; + unsigned total_output = 0, output_available = + min(ob->sectors_free << 9, orig->bi_iter.bi_size); u64 csum; - /* XXX: decide extent size better: */ - output_available = min(e->k.size, - min(ob->sectors_free, - CRC32_EXTENT_SIZE_MAX)) << 9; - + bio = bio_alloc_bioset(GFP_NOIO, + DIV_ROUND_UP(output_available, PAGE_SIZE), + &c->bio_write); /* - * temporarily set input bio's size to the max we want to - * consume from it, in order to avoid overflow in the crc info + * XXX: can't use mempool for more than + * BCH_COMPRESSED_EXTENT_MAX worth of pages */ - extra_input = orig->bi_iter.bi_size > CRC32_EXTENT_SIZE_MAX << 9 - ? orig->bi_iter.bi_size - (CRC32_EXTENT_SIZE_MAX << 9) - : 0; - orig->bi_iter.bi_size -= extra_input; - - bio = bch_bio_compress(c, orig, - &compression_type, - output_available); + bch_bio_alloc_pages_pool(c, bio, output_available); + /* copy WRITE_SYNC flag */ bio->bi_opf = orig->bi_opf; - - orig->bi_iter.bi_size += extra_input; - - bio->bi_end_io = bch_write_endio; wbio = to_wbio(bio); wbio->orig = NULL; wbio->bounce = true; wbio->put_bio = true; - /* - * Set the (uncompressed) size of the key we're creating to the - * number of sectors we consumed from orig: - */ - bch_key_resize(&e->k, (orig_input - orig->bi_iter.bi_size) >> 9); + do { + unsigned fragment_compression_type = compression_type; + size_t dst_len, src_len; - /* - * XXX: could move checksumming out from under the open - * bucket lock - but compression is also being done - * under it - */ - csum = bch_checksum_bio(bio, csum_type); -#if 0 - if (compression_type != BCH_COMPRESSION_NONE) - pr_info("successfully compressed %u -> %u", - e->k.size, bio_sectors(bio)); -#endif - /* - * Add a bch_extent_crc header for the pointers that - * bch_alloc_sectors_done() is going to append: - */ - bch_extent_crc_append(e, bio_sectors(bio), e->k.size, - compression_type, - csum, csum_type); - bch_alloc_sectors_done(op->c, op->wp, - e, op->nr_replicas, - ob, bio_sectors(bio)); + bch_bio_compress(c, bio, &dst_len, + orig, &src_len, + &fragment_compression_type); - ret = orig->bi_iter.bi_size != 0; - } else { - if (e->k.size > ob->sectors_free) - bch_key_resize(&e->k, ob->sectors_free); + BUG_ON(!dst_len || dst_len > bio->bi_iter.bi_size); + BUG_ON(!src_len || src_len > orig->bi_iter.bi_size); + BUG_ON(dst_len & (block_bytes(c) - 1)); + BUG_ON(src_len & (block_bytes(c) - 1)); + + swap(bio->bi_iter.bi_size, dst_len); + csum = bch_checksum_bio(bio, csum_type); + swap(bio->bi_iter.bi_size, dst_len); + + init_append_extent(op, + dst_len >> 9, src_len >> 9, + fragment_compression_type, + csum, csum_type, ob); + + total_output += dst_len; + bio_advance(bio, dst_len); + bio_advance(orig, src_len); + } while (bio->bi_iter.bi_size && + orig->bi_iter.bi_size && + !bch_keylist_realloc(&op->insert_keys, + op->inline_keys, + ARRAY_SIZE(op->inline_keys), + BKEY_EXTENT_U64s_MAX)); + + BUG_ON(total_output > output_available); + + memset(&bio->bi_iter, 0, sizeof(bio->bi_iter)); + bio->bi_iter.bi_size = total_output; - BUG_ON(e->k.size > ob->sectors_free); /* - * We might need a checksum entry, if there's a previous - * checksum entry we need to override: + * Free unneeded pages after compressing: */ - bch_extent_crc_append(e, e->k.size, e->k.size, - compression_type, 0, csum_type); - bch_alloc_sectors_done(op->c, op->wp, - e, op->nr_replicas, - ob, e->k.size); + while (bio->bi_vcnt * PAGE_SIZE > + round_up(bio->bi_iter.bi_size, PAGE_SIZE)) + mempool_free(bio->bi_io_vec[--bio->bi_vcnt].bv_page, + &c->bio_bounce_pages); - bio = bio_next_split(orig, e->k.size, GFP_NOIO, - &op->c->bio_write); + ret = orig->bi_iter.bi_size != 0; + } else { + bio = bio_next_split(orig, ob->sectors_free, GFP_NOIO, + &c->bio_write); wbio = to_wbio(bio); wbio->orig = NULL; wbio->bounce = false; wbio->put_bio = bio != orig; + init_append_extent(op, bio_sectors(bio), bio_sectors(bio), + compression_type, 0, csum_type, ob); + ret = bio != orig; } @@ -520,10 +539,18 @@ static int bch_write_extent(struct bch_write_op *op, bio_set_op_attrs(bio, REQ_OP_WRITE, 0); closure_get(bio->bi_private); + + /* might have done a realloc... */ + + key_to_write = (void *) (op->insert_keys.keys_p + key_to_write_offset); + + if (!(op->flags & BCH_WRITE_CACHED)) + bch_check_mark_super(c, key_to_write, false); + #ifndef CONFIG_BCACHE_NO_IO - bch_submit_wbio_replicas(wbio, op->c, &e->k_i, false); + bch_submit_wbio_replicas(to_wbio(bio), c, key_to_write, false); #else - wbio->ca = NULL; + to_wbio(bio)->ca = NULL; bio_endio(bio); #endif return ret; @@ -554,8 +581,6 @@ static void __bch_write(struct closure *cl) bio->bi_opf &= ~(REQ_PREFLUSH|REQ_FUA); do { - struct bkey_i *k; - EBUG_ON(bio->bi_iter.bi_sector != op->pos.offset); EBUG_ON(!bio_sectors(bio)); @@ -569,16 +594,7 @@ static void __bch_write(struct closure *cl) BKEY_EXTENT_U64s_MAX)) continue_at(cl, bch_write_index, index_update_wq(op)); - k = op->insert_keys.top; - bkey_extent_init(k); - k->k.p = op->pos; - bch_key_resize(&k->k, - (op->flags & BCH_WRITE_DATA_COMPRESSED) - ? op->size - : bio_sectors(bio)); - - b = bch_alloc_sectors_start(c, op->wp, - bkey_i_to_extent(k), op->nr_replicas, + b = bch_alloc_sectors_start(c, op->wp, op->nr_replicas, op->alloc_reserve, (op->flags & BCH_WRITE_ALLOC_NOWAIT) ? NULL : cl); EBUG_ON(!b); @@ -622,20 +638,12 @@ static void __bch_write(struct closure *cl) b - c->open_buckets > U8_MAX); op->open_buckets[open_bucket_nr++] = b - c->open_buckets; - ret = bch_write_extent(op, b, bkey_i_to_extent(k), bio); - if (ret < 0) - goto err; - - op->pos.offset += k->k.size; - - bkey_extent_set_cached(&k->k, (op->flags & BCH_WRITE_CACHED)); - - if (!(op->flags & BCH_WRITE_CACHED)) - bch_check_mark_super(c, k, false); + ret = bch_write_extent(op, b, bio); - bch_keylist_push(&op->insert_keys); + bch_alloc_sectors_done(c, op->wp, b); - trace_bcache_cache_insert(&k->k); + if (ret < 0) + goto err; } while (ret); op->flags |= BCH_WRITE_DONE; @@ -733,7 +741,7 @@ void bch_write(struct closure *cl) if (!percpu_ref_tryget(&c->writes)) { __bcache_io_error(c, "read only"); op->error = -EROFS; - bch_disk_reservation_put(op->c, &op->res); + bch_disk_reservation_put(c, &op->res); closure_return(cl); } diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h index 4718009bf981..d4968c542849 100644 --- a/include/trace/events/bcache.h +++ b/include/trace/events/bcache.h @@ -235,11 +235,6 @@ DEFINE_EVENT(bcache_bio, bcache_read_retry, TP_ARGS(bio) ); -DEFINE_EVENT(bkey, bcache_cache_insert, - TP_PROTO(const struct bkey *k), - TP_ARGS(k) -); - DECLARE_EVENT_CLASS(page_alloc_fail, TP_PROTO(struct cache_set *c, u64 size), TP_ARGS(c, size), diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h index 2f1cc61be66e..44de20990b56 100644 --- a/include/uapi/linux/bcache.h +++ b/include/uapi/linux/bcache.h @@ -387,7 +387,7 @@ struct bch_extent_crc32 { #define CRC32_EXTENT_SIZE_MAX (1U << 7) /* 64k */ -#define BCH_COMPRESSED_EXTENT_MAX 128 +#define BCH_COMPRESSED_EXTENT_MAX 128U struct bch_extent_crc64 { #if defined(__LITTLE_ENDIAN_BITFIELD) |