1+ #include " spdknvme-wrapper.h"
2+ #include < photon/common/alog-stdstring.h>
3+ #include < photon/common/expirecontainer.h>
4+ #include < photon/thread/thread.h>
5+ #include < photon/thread/thread11.h>
6+
7+ #include < unordered_map>
8+
9+
10+ namespace photon {
11+ namespace spdk {
12+
13+ struct nvme_qpair {
14+ bool is_complete = false ;
15+ struct spdk_nvme_qpair * qpair = nullptr ;
16+ photon::join_handle* jh = nullptr ;
17+
18+ nvme_qpair (struct spdk_nvme_ctrlr * ctrlr, struct spdk_nvme_io_qpair_opts * opts, size_t opts_size) {
19+ assert (ctrlr != nullptr );
20+ LOG_DEBUG (" nvme qpair get into constructor" );
21+ qpair = spdk_nvme_ctrlr_alloc_io_qpair (ctrlr, opts, opts_size);
22+ LOG_DEBUG (" after spdk alloc io qpair" );
23+ jh = thread_enable_join (thread_create11 ([this ]{
24+ while (!is_complete) {
25+ spdk_nvme_qpair_process_completions (qpair, 0 );
26+ thread_yield ();
27+ }
28+ }));
29+ LOG_DEBUG (" nvme qpair get out constructor" );
30+ }
31+
32+ ~nvme_qpair () {
33+ LOG_DEBUG (" nvme qpair get into destructor" );
34+ is_complete = true ;
35+ LOG_DEBUG (" before join" );
36+ thread_join (jh);
37+ LOG_DEBUG (" after join" );
38+ spdk_nvme_ctrlr_free_io_qpair (qpair);
39+ LOG_DEBUG (" nvme qpair get out destructor" );
40+ }
41+ };
42+
43+ using qpm = ObjectCache<struct spdk_nvme_ctrlr *, struct nvme_qpair *>;
44+ static qpm* get_qpair_manager () {
45+ thread_local qpm* qpair_manager = nullptr ;
46+ if (qpair_manager == nullptr ) {
47+ qpair_manager = new qpm (3000000 );
48+ auto destroy_qpair_manager = []{
49+ if (qpair_manager) {
50+ delete qpair_manager;
51+ }
52+ };
53+ photon::fini_hook (destroy_qpair_manager);
54+ }
55+ return qpair_manager;
56+ }
57+
58+
59+ struct CBContextBase {
60+ int rc = 0 ;
61+ Awaiter<PhotonContext> awaiter;
62+ static void cb_fn (void *cb_ctx, const struct spdk_nvme_cpl *cpl);
63+
64+ // for vector io
65+ struct iovec *iov; // origin iov
66+ int iovcnt; // origin iovcnt
67+ IOVector iovec;
68+ static void reset_sgl_fn (void *cb_ctx, uint32_t offset);
69+ static int next_sge_fn (void *cb_ctx, void **address, uint32_t *length);
70+ };
71+ void CBContextBase::cb_fn (void *cb_ctx, const struct spdk_nvme_cpl *cpl) {
72+ auto ctx = static_cast <CBContextBase*>(cb_ctx);
73+ if (spdk_nvme_cpl_is_error (cpl)) {
74+ LOG_ERROR (" error: `" , spdk_nvme_cpl_get_status_string (&cpl->status ));
75+ ctx->rc = -1 ;
76+ }
77+ ctx->awaiter .resume ();
78+ }
79+
80+ void CBContextBase::reset_sgl_fn (void *cb_ctx, uint32_t offset) {
81+ LOG_DEBUG (" get into reset_sgl_fn" , VALUE (offset));
82+ auto ctx = static_cast <CBContextBase*>(cb_ctx);
83+ ctx->iovec .assign (ctx->iov , ctx->iovcnt );
84+ ctx->iovec .extract_front (offset);
85+ }
86+
87+ int CBContextBase::next_sge_fn (void *cb_ctx, void **address, uint32_t *length) {
88+ auto ctx = static_cast <CBContextBase*>(cb_ctx);
89+ if (ctx->iovec .empty ()) {
90+ LOG_ERROR_RETURN (0 , -1 , " ctx->iov_view is empty" );
91+ }
92+ *address = ctx->iovec .front ().iov_base ;
93+ *length = ctx->iovec .front ().iov_len ;
94+ LOG_DEBUG (" get into next_sge_fn" , VALUE (*length));
95+ ctx->iovec .pop_front ();
96+ return 0 ;
97+ }
98+
99+ int nvme_env_init () {
100+ struct spdk_env_opts opts;
101+ spdk_env_opts_init (&opts);
102+ opts.name = " photon_spdk_nvme_pcie" ;
103+
104+ int rc = 0 ;
105+ if ((rc = spdk_env_init (&opts)) < 0 ) {
106+ LOG_ERROR_RETURN (0 , rc, " spdk_env_init failed" );
107+ }
108+ return rc;
109+ }
110+
111+ void nvme_env_fini () {
112+ LOG_DEBUG (" get into nvme_env_fini" );
113+ spdk_env_fini ();
114+ LOG_DEBUG (" get out nvme_env_fini" );
115+ }
116+
117+ struct spdk_nvme_ctrlr * nvme_probe_attach (const char * trid_str) {
118+ auto probe_cb = [](void *cb_ctx, const struct spdk_nvme_transport_id *trid, struct spdk_nvme_ctrlr_opts *opts) -> bool {
119+ LOG_INFO (" probe_cb: do attach in default " , VALUE (trid->traddr ));
120+ return true ;
121+ };
122+
123+ auto attach_cb = [](void *cb_ctx, const struct spdk_nvme_transport_id *trid, struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) {
124+ LOG_INFO (" attach_cb: attach " , VALUE (trid->traddr ));
125+ auto ret_ctrlr = (struct spdk_nvme_ctrlr **)cb_ctx;
126+ *ret_ctrlr = ctrlr;
127+ };
128+
129+ struct spdk_nvme_transport_id trid;
130+ spdk_nvme_transport_id_parse (&trid, trid_str);
131+
132+ struct spdk_nvme_ctrlr *ctrlr = nullptr ;
133+ spdk_nvme_probe (&trid, &ctrlr, probe_cb, attach_cb, nullptr );
134+ return ctrlr;
135+ }
136+
137+ int nvme_detach (struct spdk_nvme_ctrlr * ctrlr) {
138+ LOG_DEBUG (" get into nvme_detach" );
139+ spdk_nvme_detach (ctrlr);
140+ LOG_DEBUG (" get out nvme_detach" );
141+ return 0 ;
142+ }
143+
144+ struct spdk_nvme_ns * nvme_get_namespace (struct spdk_nvme_ctrlr * ctrlr, uint32_t nsid) {
145+ return spdk_nvme_ctrlr_get_ns (ctrlr, nsid);
146+ }
147+
148+ struct spdk_nvme_qpair * nvme_ctrlr_alloc_io_qpair (struct spdk_nvme_ctrlr * ctrlr, struct spdk_nvme_io_qpair_opts * opts, size_t opts_size) {
149+ LOG_DEBUG (" before acquired qpair" );
150+ auto m_qpair = get_qpair_manager ()->acquire (ctrlr, [&]() -> struct nvme_qpair * {
151+ LOG_DEBUG (" before new struct nvme_qpair" );
152+ return new nvme_qpair(ctrlr, opts, opts_size);
153+ });
154+ LOG_DEBUG (" after acquired qpair" );
155+ if (m_qpair != nullptr ) {
156+ return m_qpair->qpair ;
157+ }
158+ else {
159+ LOG_ERROR_RETURN (0 , nullptr , " failed to allocate qpair" );
160+ }
161+ }
162+
163+ int nvme_ctrlr_free_io_qpair (struct spdk_nvme_ctrlr * ctrlr, struct spdk_nvme_qpair * qpair) {
164+ LOG_DEBUG (" before release qpair" );
165+ get_qpair_manager ()->release (ctrlr, true );
166+ LOG_DEBUG (" after release qpair" );
167+ return 0 ;
168+ }
169+
170+ typedef int (*spdk_nvme_ns_cmd_rw) (struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload, uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags);
171+
172+ typedef int (*spdk_nvme_ns_cmd_rwv) (struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t lba, uint32_t lba_count, spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags, spdk_nvme_req_reset_sgl_cb reset_sgl_fn, spdk_nvme_req_next_sge_cb next_sge_fn);
173+
174+ static int io_helper (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, void * buffer, uint64_t lba, uint32_t lba_count, uint32_t io_flags, spdk_nvme_ns_cmd_rw rw_fn) {
175+ CBContextBase ctx;
176+ int rc = rw_fn (ns, qpair, buffer, lba, lba_count, CBContextBase::cb_fn, &ctx, io_flags);
177+ if (rc != 0 ) return rc;
178+ ctx.awaiter .suspend ();
179+ return ctx.rc ;
180+ }
181+
182+ int nvme_ns_cmd_write (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, void * buffer, uint64_t lba, uint32_t lba_count, uint32_t io_flags) {
183+ return io_helper (ns, qpair, buffer, lba, lba_count, io_flags, &spdk_nvme_ns_cmd_write);
184+ }
185+
186+ int nvme_ns_cmd_read (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, void * buffer, uint64_t lba, uint32_t lba_count, uint32_t io_flags) {
187+ return io_helper (ns, qpair, buffer, lba, lba_count, io_flags, &spdk_nvme_ns_cmd_read);
188+ }
189+
190+ static int vec_io_helper (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, struct iovec *iov, int iovcnt, uint64_t lba, uint32_t lba_count, uint32_t io_flags, spdk_nvme_ns_cmd_rwv rwv_fn) {
191+ CBContextBase ctx;
192+ ctx.iov = iov;
193+ ctx.iovcnt = iovcnt;
194+ int rc = rwv_fn (ns, qpair, lba, lba_count, CBContextBase::cb_fn, &ctx, io_flags, CBContextBase::reset_sgl_fn, CBContextBase::next_sge_fn);
195+ if (rc != 0 ) return rc;
196+ ctx.awaiter .suspend ();
197+ return ctx.rc ;
198+ }
199+
200+ int nvme_ns_cmd_writev (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, struct iovec *iov, int iovcnt, uint64_t lba, uint32_t lba_count, uint32_t io_flags) {
201+ return vec_io_helper (ns, qpair, iov, iovcnt, lba, lba_count, io_flags, &spdk_nvme_ns_cmd_writev);
202+ }
203+
204+ int nvme_ns_cmd_readv (struct spdk_nvme_ns * ns, struct spdk_nvme_qpair * qpair, struct iovec *iov, int iovcnt, uint64_t lba, uint32_t lba_count, uint32_t io_flags) {
205+ return vec_io_helper (ns, qpair, iov, iovcnt, lba, lba_count, io_flags, &spdk_nvme_ns_cmd_readv);
206+ }
207+
208+ } // namespace spdk
209+ } // namespace photon
0 commit comments