+// SPDX-License-Identifier: GPL-2.0
/*
* random utiility code, for bcache but in theory not specific to bcache
*
const char * const list[], u64 flags)
{
unsigned bit, nr = 0;
+ bool first = true;
if (out->pos != out->end)
*out->pos = '\0';
nr++;
while (flags && (bit = __ffs(flags)) < nr) {
- pr_buf(out, "%s,", list[bit]);
+ if (!first)
+ pr_buf(out, ",");
+ first = false;
+ pr_buf(out, "%s", list[bit]);
flags ^= 1 << bit;
}
}
/* misc: */
-void bch2_bio_map(struct bio *bio, void *base)
+void bch2_bio_map(struct bio *bio, void *base, size_t size)
{
- size_t size = bio->bi_iter.bi_size;
- struct bio_vec *bv = bio->bi_io_vec;
-
- BUG_ON(!bio->bi_iter.bi_size);
- BUG_ON(bio->bi_vcnt);
- BUG_ON(!bio->bi_max_vecs);
-
- bv->bv_offset = base ? offset_in_page(base) : 0;
- goto start;
-
- for (; size; bio->bi_vcnt++, bv++) {
- BUG_ON(bio->bi_vcnt >= bio->bi_max_vecs);
-
- bv->bv_offset = 0;
-start: bv->bv_len = min_t(size_t, PAGE_SIZE - bv->bv_offset,
- size);
- if (base) {
- bv->bv_page = is_vmalloc_addr(base)
+ while (size) {
+ struct page *page = is_vmalloc_addr(base)
? vmalloc_to_page(base)
: virt_to_page(base);
+ unsigned offset = offset_in_page(base);
+ unsigned len = min_t(size_t, PAGE_SIZE - offset, size);
- base += bv->bv_len;
- }
-
- size -= bv->bv_len;
+ BUG_ON(!bio_add_page(bio, page, len, offset));
+ size -= len;
+ base += len;
}
}
-int bch2_bio_alloc_pages(struct bio *bio, gfp_t gfp_mask)
+int bch2_bio_alloc_pages(struct bio *bio, size_t size, gfp_t gfp_mask)
{
- int i;
- struct bio_vec *bv;
+ while (size) {
+ struct page *page = alloc_page(gfp_mask);
+ unsigned len = min(PAGE_SIZE, size);
- bio_for_each_segment_all(bv, bio, i) {
- bv->bv_page = alloc_page(gfp_mask);
- if (!bv->bv_page) {
- while (--bv >= bio->bi_io_vec)
- __free_page(bv->bv_page);
+ if (!page)
return -ENOMEM;
- }
+
+ BUG_ON(!bio_add_page(bio, page, len, 0));
+ size -= len;
}
return 0;
return rand;
}
-void memcpy_to_bio(struct bio *dst, struct bvec_iter dst_iter, void *src)
+void memcpy_to_bio(struct bio *dst, struct bvec_iter dst_iter, const void *src)
{
struct bio_vec bv;
struct bvec_iter iter;
kfree(test_array);
}
#endif
+
+/*
+ * Accumulate percpu counters onto one cpu's copy - only valid when access
+ * against any percpu counter is guarded against
+ */
+u64 *bch2_acc_percpu_u64s(u64 __percpu *p, unsigned nr)
+{
+ u64 *ret;
+ int cpu;
+
+ preempt_disable();
+ ret = this_cpu_ptr(p);
+ preempt_enable();
+
+ for_each_possible_cpu(cpu) {
+ u64 *i = per_cpu_ptr(p, cpu);
+
+ if (i != ret) {
+ acc_u64s(ret, i, nr);
+ memset(i, 0, nr * sizeof(u64));
+ }
+ }
+
+ return ret;
+}