]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: bch2_account_io_completion()
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 28 Feb 2025 19:07:22 +0000 (14:07 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 15 Mar 2025 01:02:16 +0000 (21:02 -0400)
We need to start accounting successes for every IO, not just failures,
so introduce a unified hook for io completion accounting and convert
io_read.c.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/error.h
fs/bcachefs/io_read.c
fs/bcachefs/io_write.h

index b3cc69f29fd99db74583a81fcc66dd3998a849cf..e055b606fb6f68754823fbfb4f371acf20aad828 100644 (file)
@@ -216,6 +216,26 @@ void bch2_io_error_work(struct work_struct *);
 /* Does the error handling without logging a message */
 void bch2_io_error(struct bch_dev *, enum bch_member_error_type);
 
+#ifndef CONFIG_BCACHEFS_NO_LATENCY_ACCT
+void bch2_latency_acct(struct bch_dev *, u64, int);
+#else
+static inline void bch2_latency_acct(struct bch_dev *ca, u64 submit_time, int rw) {}
+#endif
+
+static inline void bch2_account_io_completion(struct bch_dev *ca,
+                                             enum bch_member_error_type type,
+                                             u64 submit_time, bool success)
+{
+       if (unlikely(!ca))
+               return;
+
+       if (type != BCH_MEMBER_ERROR_checksum)
+               bch2_latency_acct(ca, submit_time, type);
+
+       if (!success)
+               bch2_io_error(ca, type);
+}
+
 #define bch2_dev_io_err_on(cond, ca, _type, ...)                       \
 ({                                                                     \
        bool _ret = (cond);                                             \
index f97716e525563d0a3f22a506e75fba0e20728f70..70e5c5a32d01870aed2770acf36ae2d755a7c5ca 100644 (file)
@@ -524,12 +524,10 @@ static void bch2_read_io_err(struct work_struct *work)
        bch2_read_err_msg(c, &buf, rbio, rbio->read_pos);
        prt_printf(&buf, "data read error: %s", bch2_blk_status_to_str(bio->bi_status));
 
-       if (ca) {
-               bch2_io_error(ca, BCH_MEMBER_ERROR_read);
+       if (ca)
                bch_err_ratelimited(ca, "%s", buf.buf);
-       } else {
+       else
                bch_err_ratelimited(c, "%s", buf.buf);
-       }
 
        printbuf_exit(&buf);
        bch2_rbio_error(rbio, READ_RETRY_AVOID, bio->bi_status);
@@ -614,12 +612,10 @@ static void bch2_read_csum_err(struct work_struct *work)
        bch2_csum_err_msg(&buf, crc.csum_type, rbio->pick.crc.csum, csum);
 
        struct bch_dev *ca = rbio->have_ioref ? bch2_dev_have_ref(c, rbio->pick.ptr.dev) : NULL;
-       if (ca) {
-               bch2_io_error(ca, BCH_MEMBER_ERROR_checksum);
+       if (ca)
                bch_err_ratelimited(ca, "%s", buf.buf);
-       } else {
+       else
                bch_err_ratelimited(c, "%s", buf.buf);
-       }
 
        bch2_rbio_error(rbio, READ_RETRY_AVOID, BLK_STS_IOERR);
        printbuf_exit(&buf);
@@ -671,6 +667,7 @@ static void __bch2_read_endio(struct work_struct *work)
        struct bch_read_bio *rbio =
                container_of(work, struct bch_read_bio, work);
        struct bch_fs *c        = rbio->c;
+       struct bch_dev *ca = rbio->have_ioref ? bch2_dev_have_ref(c, rbio->pick.ptr.dev) : NULL;
        struct bio *src         = &rbio->bio;
        struct bio *dst         = &bch2_rbio_parent(rbio)->bio;
        struct bvec_iter dst_iter = rbio->bvec_iter;
@@ -692,7 +689,22 @@ static void __bch2_read_endio(struct work_struct *work)
        }
 
        csum = bch2_checksum_bio(c, crc.csum_type, nonce, src);
-       if (bch2_crc_cmp(csum, rbio->pick.crc.csum) && !c->opts.no_data_io)
+       bool csum_good = !bch2_crc_cmp(csum, rbio->pick.crc.csum) || c->opts.no_data_io;
+
+       /*
+        * Checksum error: if the bio wasn't bounced, we may have been
+        * reading into buffers owned by userspace (that userspace can
+        * scribble over) - retry the read, bouncing it this time:
+        */
+       if (!csum_good && !rbio->bounce && (rbio->flags & BCH_READ_user_mapped)) {
+               rbio->flags |= BCH_READ_must_bounce;
+               bch2_rbio_error(rbio, READ_RETRY, BLK_STS_IOERR);
+               goto out;
+       }
+
+       bch2_account_io_completion(ca, BCH_MEMBER_ERROR_checksum, 0, csum_good);
+
+       if (!csum_good)
                goto csum_err;
 
        /*
@@ -765,17 +777,6 @@ out:
        memalloc_nofs_restore(nofs_flags);
        return;
 csum_err:
-       /*
-        * Checksum error: if the bio wasn't bounced, we may have been
-        * reading into buffers owned by userspace (that userspace can
-        * scribble over) - retry the read, bouncing it this time:
-        */
-       if (!rbio->bounce && (rbio->flags & BCH_READ_user_mapped)) {
-               rbio->flags |= BCH_READ_must_bounce;
-               bch2_rbio_error(rbio, READ_RETRY, BLK_STS_IOERR);
-               goto out;
-       }
-
        bch2_rbio_punt(rbio, bch2_read_csum_err, RBIO_CONTEXT_UNBOUND, system_unbound_wq);
        goto out;
 decompression_err:
@@ -795,8 +796,8 @@ static void bch2_read_endio(struct bio *bio)
        struct workqueue_struct *wq = NULL;
        enum rbio_context context = RBIO_CONTEXT_NULL;
 
-       if (ca)
-               bch2_latency_acct(ca, rbio->submit_time, READ);
+       bch2_account_io_completion(ca, BCH_MEMBER_ERROR_read,
+                                  rbio->submit_time, !bio->bi_status);
 
        if (!rbio->split)
                rbio->bio.bi_end_io = rbio->end_io;
index bf942566a8eba8e1d18eb48467d441aac60c3805..6277305377528bf4c3b7dd518b3fe8c357d0c8f5 100644 (file)
 void bch2_bio_free_pages_pool(struct bch_fs *, struct bio *);
 void bch2_bio_alloc_pages_pool(struct bch_fs *, struct bio *, size_t);
 
-#ifndef CONFIG_BCACHEFS_NO_LATENCY_ACCT
-void bch2_latency_acct(struct bch_dev *, u64, int);
-#else
-static inline void bch2_latency_acct(struct bch_dev *ca, u64 submit_time, int rw) {}
-#endif
-
 void bch2_submit_wbio_replicas(struct bch_write_bio *, struct bch_fs *,
                               enum bch_data_type, const struct bkey_i *, bool);