1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _BCACHEFS_IO_READ_H
3#define _BCACHEFS_IO_READ_H
4
5#include "bkey_buf.h"
6
7struct bch_read_bio {
8	struct bch_fs		*c;
9	u64			start_time;
10	u64			submit_time;
11
12	/*
13	 * Reads will often have to be split, and if the extent being read from
14	 * was checksummed or compressed we'll also have to allocate bounce
15	 * buffers and copy the data back into the original bio.
16	 *
17	 * If we didn't have to split, we have to save and restore the original
18	 * bi_end_io - @split below indicates which:
19	 */
20	union {
21	struct bch_read_bio	*parent;
22	bio_end_io_t		*end_io;
23	};
24
25	/*
26	 * Saved copy of bio->bi_iter, from submission time - allows us to
27	 * resubmit on IO error, and also to copy data back to the original bio
28	 * when we're bouncing:
29	 */
30	struct bvec_iter	bvec_iter;
31
32	unsigned		offset_into_extent;
33
34	u16			flags;
35	union {
36	struct {
37	u16			bounce:1,
38				split:1,
39				kmalloc:1,
40				have_ioref:1,
41				narrow_crcs:1,
42				hole:1,
43				retry:2,
44				context:2;
45	};
46	u16			_state;
47	};
48
49	struct bch_devs_list	devs_have;
50
51	struct extent_ptr_decoded pick;
52
53	/*
54	 * pos we read from - different from data_pos for indirect extents:
55	 */
56	u32			subvol;
57	struct bpos		read_pos;
58
59	/*
60	 * start pos of data we read (may not be pos of data we want) - for
61	 * promote, narrow extents paths:
62	 */
63	enum btree_id		data_btree;
64	struct bpos		data_pos;
65	struct bversion		version;
66
67	struct promote_op	*promote;
68
69	struct bch_io_opts	opts;
70
71	struct work_struct	work;
72
73	struct bio		bio;
74};
75
76#define to_rbio(_bio)		container_of((_bio), struct bch_read_bio, bio)
77
78struct bch_devs_mask;
79struct cache_promote_op;
80struct extent_ptr_decoded;
81
82int __bch2_read_indirect_extent(struct btree_trans *, unsigned *,
83				struct bkey_buf *);
84
85static inline int bch2_read_indirect_extent(struct btree_trans *trans,
86					    enum btree_id *data_btree,
87					    unsigned *offset_into_extent,
88					    struct bkey_buf *k)
89{
90	if (k->k->k.type != KEY_TYPE_reflink_p)
91		return 0;
92
93	*data_btree = BTREE_ID_reflink;
94	return __bch2_read_indirect_extent(trans, offset_into_extent, k);
95}
96
97enum bch_read_flags {
98	BCH_READ_RETRY_IF_STALE		= 1 << 0,
99	BCH_READ_MAY_PROMOTE		= 1 << 1,
100	BCH_READ_USER_MAPPED		= 1 << 2,
101	BCH_READ_NODECODE		= 1 << 3,
102	BCH_READ_LAST_FRAGMENT		= 1 << 4,
103
104	/* internal: */
105	BCH_READ_MUST_BOUNCE		= 1 << 5,
106	BCH_READ_MUST_CLONE		= 1 << 6,
107	BCH_READ_IN_RETRY		= 1 << 7,
108};
109
110int __bch2_read_extent(struct btree_trans *, struct bch_read_bio *,
111		       struct bvec_iter, struct bpos, enum btree_id,
112		       struct bkey_s_c, unsigned,
113		       struct bch_io_failures *, unsigned);
114
115static inline void bch2_read_extent(struct btree_trans *trans,
116			struct bch_read_bio *rbio, struct bpos read_pos,
117			enum btree_id data_btree, struct bkey_s_c k,
118			unsigned offset_into_extent, unsigned flags)
119{
120	__bch2_read_extent(trans, rbio, rbio->bio.bi_iter, read_pos,
121			   data_btree, k, offset_into_extent, NULL, flags);
122}
123
124void __bch2_read(struct bch_fs *, struct bch_read_bio *, struct bvec_iter,
125		 subvol_inum, struct bch_io_failures *, unsigned flags);
126
127static inline void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
128			     subvol_inum inum)
129{
130	struct bch_io_failures failed = { .nr = 0 };
131
132	BUG_ON(rbio->_state);
133
134	rbio->c = c;
135	rbio->start_time = local_clock();
136	rbio->subvol = inum.subvol;
137
138	__bch2_read(c, rbio, rbio->bio.bi_iter, inum, &failed,
139		    BCH_READ_RETRY_IF_STALE|
140		    BCH_READ_MAY_PROMOTE|
141		    BCH_READ_USER_MAPPED);
142}
143
144static inline struct bch_read_bio *rbio_init(struct bio *bio,
145					     struct bch_io_opts opts)
146{
147	struct bch_read_bio *rbio = to_rbio(bio);
148
149	rbio->_state	= 0;
150	rbio->promote	= NULL;
151	rbio->opts	= opts;
152	return rbio;
153}
154
155void bch2_fs_io_read_exit(struct bch_fs *);
156int bch2_fs_io_read_init(struct bch_fs *);
157
158#endif /* _BCACHEFS_IO_READ_H */
159