1// SPDX-License-Identifier: GPL-2.0
2/*
3 * drivers/hyperhold/hp_core.c
4 *
5 * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd.
6 */
7
8 #define pr_fmt(fmt) "[HYPERHOLD]" fmt
9
10#include <linux/module.h>
11#include <linux/blkdev.h>
12#include <linux/sysctl.h>
13
14#include "hyperhold.h"
15#include "hp_device.h"
16#include "hp_space.h"
17#include "hp_iotab.h"
18
19#define HP_DFLT_DEVICE "/dev/by-name/hyperhold"
20#define HP_DFLT_EXT_SIZE (1 << 15)
21#define HP_DEV_NAME_LEN 256
22#define HP_STATE_LEN 10
23
24#define CHECK(cond, ...) ((cond) || (pr_err(__VA_ARGS__), false))
25#define CHECK_BOUND(var, min, max) \
26	CHECK((var) >= (min) && (var) <= (max), \
27		"%s %u out of bounds %u ~ %u!\n", #var, (var), (min), (max))
28#define CHECK_INITED CHECK(hyperhold.inited, "hyperhold is not enable!\n")
29#define CHECK_ENABLE (CHECK_INITED && CHECK(hyperhold.enable, "hyperhold is readonly!\n"))
30
31struct hyperhold {
32	bool enable;
33	bool inited;
34
35	char device_name[HP_DEV_NAME_LEN];
36	u32 extent_size;
37	u32 enable_soft_crypt;
38
39	struct hp_device dev;
40	struct hp_space spc;
41
42	struct workqueue_struct *read_wq;
43	struct workqueue_struct *write_wq;
44
45	struct mutex init_lock;
46};
47
48struct hyperhold hyperhold;
49
50atomic64_t mem_used = ATOMIC64_INIT(0);
51#ifdef CONFIG_HYPERHOLD_DEBUG
52/*
53 * return the memory overhead of hyperhold module
54 */
55u64 hyperhold_memory_used(void)
56{
57	return atomic64_read(&mem_used) + hpio_memory() + space_memory();
58}
59#endif
60
61void hyperhold_disable(bool force)
62{
63	if (!CHECK_INITED)
64		return;
65	if (!force && !CHECK_ENABLE)
66		return;
67
68	mutex_lock(&hyperhold.init_lock);
69	hyperhold.enable = false;
70	if (!wait_for_space_empty(&hyperhold.spc, force))
71		goto out;
72	hyperhold.inited = false;
73	wait_for_iotab_empty();
74	destroy_workqueue(hyperhold.read_wq);
75	destroy_workqueue(hyperhold.write_wq);
76	deinit_space(&hyperhold.spc);
77	crypto_deinit(&hyperhold.dev);
78	unbind_bdev(&hyperhold.dev);
79out:
80	if (hyperhold.inited)
81		pr_info("hyperhold is disabled, read only.\n");
82	else
83		pr_info("hyperhold is totally disabled!\n");
84	mutex_unlock(&hyperhold.init_lock);
85}
86EXPORT_SYMBOL(hyperhold_disable);
87
88void hyperhold_enable(void)
89{
90	bool enable = true;
91
92	if (hyperhold.inited)
93		goto out;
94
95	mutex_lock(&hyperhold.init_lock);
96	if (hyperhold.inited)
97		goto unlock;
98	if (!bind_bdev(&hyperhold.dev, hyperhold.device_name))
99		goto err1;
100	if (!crypto_init(&hyperhold.dev, hyperhold.enable_soft_crypt))
101		goto err2;
102	if (!init_space(&hyperhold.spc, hyperhold.dev.dev_size, hyperhold.extent_size))
103		goto err3;
104	hyperhold.read_wq = alloc_workqueue("hyperhold_read", WQ_HIGHPRI | WQ_UNBOUND, 0);
105	if (!hyperhold.read_wq)
106		goto err4;
107	hyperhold.write_wq = alloc_workqueue("hyperhold_write", 0, 0);
108	if (!hyperhold.write_wq)
109		goto err5;
110	hyperhold.inited = true;
111	goto unlock;
112err5:
113	destroy_workqueue(hyperhold.read_wq);
114err4:
115	deinit_space(&hyperhold.spc);
116err3:
117	crypto_deinit(&hyperhold.dev);
118err2:
119	unbind_bdev(&hyperhold.dev);
120err1:
121	enable = false;
122unlock:
123	mutex_unlock(&hyperhold.init_lock);
124out:
125	if (enable) {
126		hyperhold.enable = true;
127		pr_info("hyperhold is enabled.\n");
128	} else {
129		hyperhold.enable = false;
130		pr_err("hyperhold enable failed!\n");
131	}
132}
133EXPORT_SYMBOL(hyperhold_enable);
134
135static int enable_sysctl_handler(struct ctl_table *table, int write,
136				 void *buffer, size_t *lenp, loff_t *ppos)
137{
138	const struct cred *cred = current_cred();
139	char *filter_buf;
140
141	filter_buf = strstrip((char *)buffer);
142	if (write) {
143		if (!uid_eq(cred->euid, GLOBAL_MEMMGR_UID) &&
144			!uid_eq(cred->euid, GLOBAL_ROOT_UID)) {
145			pr_err("no permission to enable/disable eswap!\n");
146			return 0;
147		}
148		if (!strcmp(filter_buf, "enable"))
149			hyperhold_enable();
150		else if (!strcmp(filter_buf, "disable"))
151			hyperhold_disable(false);
152		else if (!strcmp(filter_buf, "force_disable"))
153			hyperhold_disable(true);
154	} else {
155		if (*lenp < HP_STATE_LEN || *ppos) {
156			*lenp = 0;
157			return 0;
158		}
159		if (hyperhold.enable)
160			strcpy(buffer, "enable\n");
161		else if (hyperhold.inited)
162			strcpy(buffer, "readonly\n");
163		else
164			strcpy(buffer, "disable\n");
165		*lenp = strlen(buffer);
166		*ppos += *lenp;
167#ifdef CONFIG_HYPERHOLD_DEBUG
168		pr_info("hyperhold memory overhead = %llu.\n", hyperhold_memory_used());
169#endif
170	}
171	return 0;
172}
173
174static int device_sysctl_handler(struct ctl_table *table, int write,
175				 void *buffer, size_t *lenp, loff_t *ppos)
176{
177	int ret;
178
179	mutex_lock(&hyperhold.init_lock);
180	if (write && hyperhold.inited) {
181		pr_err("hyperhold device is busy!\n");
182		ret = -EBUSY;
183		goto unlock;
184	}
185	ret = proc_dostring(table, write, buffer, lenp, ppos);
186	if (write && !ret) {
187		hyperhold.enable_soft_crypt = 1;
188		pr_info("device changed, default enable soft crypt.\n");
189	}
190unlock:
191	mutex_unlock(&hyperhold.init_lock);
192
193	return ret;
194}
195
196static int extent_sysctl_handler(struct ctl_table *table, int write,
197				 void *buffer, size_t *lenp, loff_t *ppos)
198{
199	int ret;
200
201	mutex_lock(&hyperhold.init_lock);
202	if (write && hyperhold.inited) {
203		pr_err("hyperhold device is busy!\n");
204		ret = -EBUSY;
205		goto unlock;
206	}
207	ret = proc_douintvec(table, write, buffer, lenp, ppos);
208unlock:
209	mutex_unlock(&hyperhold.init_lock);
210
211	return ret;
212}
213
214static int crypto_sysctl_handler(struct ctl_table *table, int write,
215				 void *buffer, size_t *lenp, loff_t *ppos)
216{
217	int ret;
218
219	mutex_lock(&hyperhold.init_lock);
220	if (write && hyperhold.inited) {
221		pr_err("hyperhold device is busy!\n");
222		ret = -EBUSY;
223		goto unlock;
224	}
225	ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
226unlock:
227	mutex_unlock(&hyperhold.init_lock);
228
229	return ret;
230}
231
232static struct ctl_table_header *hp_sysctl_header;
233static struct ctl_table hp_table[] = {
234	{
235		.procname = "enable",
236		.mode = 0666,
237		.proc_handler = enable_sysctl_handler,
238	},
239	{
240		.procname = "device",
241		.data = &hyperhold.device_name,
242		.maxlen = sizeof(hyperhold.device_name),
243		.mode = 0644,
244		.proc_handler = device_sysctl_handler,
245	},
246	{
247		.procname = "extent_size",
248		.data = &hyperhold.extent_size,
249		.maxlen = sizeof(hyperhold.extent_size),
250		.mode = 0644,
251		.proc_handler = extent_sysctl_handler,
252	},
253	{
254		.procname = "soft_crypt",
255		.data = &hyperhold.enable_soft_crypt,
256		.maxlen = sizeof(hyperhold.enable_soft_crypt),
257		.mode = 0644,
258		.proc_handler = crypto_sysctl_handler,
259		.extra1 = SYSCTL_ZERO,
260		.extra2 = SYSCTL_ONE,
261	},
262	{}
263};
264static struct ctl_table hp_kernel_table[] = {
265	{
266		.procname = "hyperhold",
267		.mode = 0555,
268		.child = hp_table,
269	},
270	{}
271};
272static struct ctl_table hp_sys_table[] = {
273	{
274		.procname = "kernel",
275		.mode = 0555,
276		.child = hp_kernel_table,
277	},
278	{}
279};
280
281bool is_hyperhold_enable(void)
282{
283	return hyperhold.enable;
284}
285
286static int __init hyperhold_init(void)
287{
288	strcpy(hyperhold.device_name, HP_DFLT_DEVICE);
289	hyperhold.extent_size = HP_DFLT_EXT_SIZE;
290	hyperhold.enable_soft_crypt = 1;
291	mutex_init(&hyperhold.init_lock);
292	hp_sysctl_header = register_sysctl_table(hp_sys_table);
293	if (!hp_sysctl_header) {
294		pr_err("register hyperhold sysctl table failed!\n");
295		return -EINVAL;
296	}
297
298	return 0;
299}
300
301static void __exit hyperhold_exit(void)
302{
303	unregister_sysctl_table(hp_sysctl_header);
304	hyperhold_disable(true);
305}
306
307static struct hp_space *space_of(u32 eid)
308{
309	return &hyperhold.spc;
310}
311
312/* replace this func for multi devices */
313static struct hp_device *device_of(u32 eid)
314{
315	return &hyperhold.dev;
316}
317
318/* replace this func for multi devices */
319u32 hyperhold_nr_extent(void)
320{
321	if (!CHECK_INITED)
322		return 0;
323
324	return hyperhold.spc.nr_ext;
325}
326EXPORT_SYMBOL(hyperhold_nr_extent);
327
328u32 hyperhold_extent_size(u32 eid)
329{
330	struct hp_space *spc = NULL;
331
332	if (!CHECK_INITED)
333		return 0;
334	spc = space_of(eid);
335	if (!CHECK(spc, "invalid eid %u!\n", eid))
336		return 0;
337
338	return spc->ext_size;
339}
340EXPORT_SYMBOL(hyperhold_extent_size);
341
342/* replace this func for multi devices */
343long hyperhold_address(u32 eid, u32 offset)
344{
345	struct hp_space *spc = NULL;
346
347	if (!CHECK_INITED)
348		return -EINVAL;
349	spc = space_of(eid);
350	if (!CHECK(spc, "invalid eid %u!\n", eid))
351		return -EINVAL;
352	if (!CHECK_BOUND(offset, 0, spc->ext_size - 1))
353		return -EINVAL;
354
355	return (u64)eid * spc->ext_size + offset;
356}
357EXPORT_SYMBOL(hyperhold_address);
358
359/* replace this func for multi devices */
360int hyperhold_addr_extent(u64 addr)
361{
362	struct hp_space *spc = NULL;
363	u32 eid;
364
365	if (!CHECK_INITED)
366		return -EINVAL;
367	eid = div_u64(addr, hyperhold.spc.ext_size);
368	spc = space_of(eid);
369	if (!CHECK(spc, "invalid eid %u!\n", eid))
370		return -EINVAL;
371
372	return eid;
373}
374EXPORT_SYMBOL(hyperhold_addr_extent);
375
376/* replace this func for multi devices */
377int hyperhold_addr_offset(u64 addr)
378{
379	if (!CHECK_INITED)
380		return -EINVAL;
381
382	return do_div(addr, hyperhold.spc.ext_size);
383}
384EXPORT_SYMBOL(hyperhold_addr_offset);
385
386/* replace this func for multi devices */
387int hyperhold_alloc_extent(void)
388{
389	if (!CHECK_ENABLE)
390		return -EINVAL;
391
392	return alloc_eid(&hyperhold.spc);
393}
394EXPORT_SYMBOL(hyperhold_alloc_extent);
395
396void hyperhold_free_extent(u32 eid)
397{
398	struct hp_space *spc = NULL;
399
400	if (!CHECK_INITED)
401		return;
402	spc = space_of(eid);
403	if (!CHECK(spc, "invalid eid %u!\n", eid))
404		return;
405
406	free_eid(spc, eid);
407}
408EXPORT_SYMBOL(hyperhold_free_extent);
409
410void hyperhold_should_free_extent(u32 eid)
411{
412	struct hpio *hpio = NULL;
413	struct hp_space *spc = NULL;
414
415	if (!CHECK_INITED)
416		return;
417	spc = space_of(eid);
418	if (!CHECK(spc, "invalid eid %u", eid))
419		return;
420
421	hpio = hpio_get(eid);
422	if (!hpio) {
423		free_eid(spc, eid);
424		return;
425	}
426	hpio->free_extent = hyperhold_free_extent;
427	hpio_put(hpio);
428}
429EXPORT_SYMBOL(hyperhold_should_free_extent);
430
431/*
432 * alloc hpio struct for r/w extent at @eid, will fill hpio with new alloced
433 * pages if @new_page. @return NULL on fail.
434 */
435struct hpio *hyperhold_io_alloc(u32 eid, gfp_t gfp, unsigned int op, bool new_page)
436{
437	struct hpio *hpio = NULL;
438	struct hp_space *spc;
439	u32 nr_page;
440
441	if (!CHECK_ENABLE)
442		return NULL;
443	spc = space_of(eid);
444	if (!CHECK(spc, "invalid eid  %u!\n", eid))
445		return NULL;
446
447	nr_page = spc->ext_size / PAGE_SIZE;
448	hpio = hpio_alloc(nr_page, gfp, op, new_page);
449	if (!hpio)
450		goto err;
451	hpio->eid = eid;
452
453	return hpio;
454err:
455	hpio_free(hpio);
456
457	return NULL;
458}
459EXPORT_SYMBOL(hyperhold_io_alloc);
460
461void hyperhold_io_free(struct hpio *hpio)
462{
463	if (!CHECK_INITED)
464		return;
465	if (!CHECK(hpio, "hpio is null!\n"))
466		return;
467
468	hpio_free(hpio);
469}
470EXPORT_SYMBOL(hyperhold_io_free);
471
472/*
473 * find exist read hpio of the extent @eid in iotab and inc its refcnt,
474 * alloc a new hpio and insert it into iotab if there is no hpio for @eid
475 */
476struct hpio *hyperhold_io_get(u32 eid, gfp_t gfp, unsigned int op)
477{
478	struct hp_space *spc = NULL;
479	u32 nr_page;
480
481	if (!CHECK_INITED)
482		return NULL;
483	spc = space_of(eid);
484	if (!CHECK(spc, "invalid eid %u", eid))
485		return NULL;
486
487	nr_page = spc->ext_size / PAGE_SIZE;
488	return hpio_get_alloc(eid, nr_page, gfp, op);
489}
490EXPORT_SYMBOL(hyperhold_io_get);
491
492bool hyperhold_io_put(struct hpio *hpio)
493{
494	if (!CHECK_INITED)
495		return false;
496	if (!CHECK(hpio, "hpio is null!\n"))
497		return false;
498
499	return hpio_put(hpio);
500}
501EXPORT_SYMBOL(hyperhold_io_put);
502
503/*
504 * notify all threads waiting for this hpio
505 */
506void hyperhold_io_complete(struct hpio *hpio)
507{
508	if (!CHECK_INITED)
509		return;
510	if (!CHECK(hpio, "hpio is null!\n"))
511		return;
512
513	hpio_complete(hpio);
514}
515EXPORT_SYMBOL(hyperhold_io_complete);
516
517void hyperhold_io_wait(struct hpio *hpio)
518{
519	if (!CHECK_INITED)
520		return;
521	if (!CHECK(hpio, "hpio is null!\n"))
522		return;
523
524	hpio_wait(hpio);
525}
526EXPORT_SYMBOL(hyperhold_io_wait);
527
528bool hyperhold_io_success(struct hpio *hpio)
529{
530	if (!CHECK_INITED)
531		return false;
532	if (!CHECK(hpio, "hpio is null!\n"))
533		return false;
534
535	return hpio_get_state(hpio) == HPIO_DONE;
536}
537EXPORT_SYMBOL(hyperhold_io_success);
538
539int hyperhold_io_extent(struct hpio *hpio)
540{
541	if (!CHECK_INITED)
542		return -EINVAL;
543	if (!CHECK(hpio, "hpio is null!\n"))
544		return -EINVAL;
545
546	return hpio->eid;
547}
548EXPORT_SYMBOL(hyperhold_io_extent);
549
550int hyperhold_io_operate(struct hpio *hpio)
551{
552	if (!CHECK_INITED)
553		return -EINVAL;
554	if (!CHECK(hpio, "hpio is null!\n"))
555		return -EINVAL;
556
557	return hpio->op;
558}
559EXPORT_SYMBOL(hyperhold_io_operate);
560
561struct page *hyperhold_io_page(struct hpio *hpio, u32 index)
562{
563	if (!CHECK_INITED)
564		return NULL;
565	if (!CHECK(hpio, "hpio is null!\n"))
566		return NULL;
567	if (!CHECK_BOUND(index, 0, hpio->nr_page - 1))
568		return NULL;
569
570	return hpio->pages[index];
571}
572EXPORT_SYMBOL(hyperhold_io_page);
573
574bool hyperhold_io_add_page(struct hpio *hpio, u32 index, struct page *page)
575{
576	if (!CHECK_INITED)
577		return false;
578	if (!CHECK(hpio, "hpio is null!\n"))
579		return false;
580	if (!CHECK(page, "page is null!\n"))
581		return false;
582	if (!CHECK_BOUND(index, 0, hpio->nr_page - 1))
583		return false;
584
585	get_page(page);
586	atomic64_add(PAGE_SIZE, &mem_used);
587	BUG_ON(hpio->pages[index]);
588	hpio->pages[index] = page;
589
590	return true;
591}
592EXPORT_SYMBOL(hyperhold_io_add_page);
593
594u32 hyperhold_io_nr_page(struct hpio *hpio)
595{
596	if (!CHECK_INITED)
597		return 0;
598	if (!CHECK(hpio, "hpio is null!\n"))
599		return 0;
600
601	return hpio->nr_page;
602}
603EXPORT_SYMBOL(hyperhold_io_nr_page);
604
605void *hyperhold_io_private(struct hpio *hpio)
606{
607	if (!CHECK_INITED)
608		return NULL;
609	if (!CHECK(hpio, "hpio is null!\n"))
610		return NULL;
611
612	return hpio->private;
613}
614EXPORT_SYMBOL(hyperhold_io_private);
615
616static struct page *get_encrypted_page(struct hp_device *dev, struct page *page, unsigned int op)
617{
618	struct page *encrypted_page = NULL;
619
620	if (!dev->ctfm) {
621		encrypted_page = page;
622		get_page(encrypted_page);
623		goto out;
624	}
625
626	encrypted_page = alloc_page(GFP_NOIO);
627	if (!encrypted_page) {
628		pr_err("alloc encrypted page failed!\n");
629		goto out;
630	}
631	encrypted_page->index = page->index;
632
633	/* just alloc a new page for read */
634	if (!op_is_write(op))
635		goto out;
636
637	/* encrypt page for write */
638	if (soft_crypt_page(dev->ctfm, encrypted_page, page, HP_DEV_ENCRYPT)) {
639		put_page(encrypted_page);
640		encrypted_page = NULL;
641	}
642out:
643	return encrypted_page;
644}
645
646static void put_encrypted_pages(struct bio *bio)
647{
648	struct bio_vec *bv = NULL;
649	struct bvec_iter_all iter;
650
651	bio_for_each_segment_all(bv, bio, iter)
652		put_page(bv->bv_page);
653}
654
655static void hp_endio_work(struct work_struct *work)
656{
657	struct hpio *hpio = container_of(work, struct hpio, endio_work);
658	struct hp_device *dev = NULL;
659	struct bio_vec *bv = NULL;
660	struct bvec_iter_all iter;
661	struct page *page = NULL;
662	u32 ext_size;
663	sector_t sec;
664	int i;
665
666	if (op_is_write(hpio->op))
667		goto endio;
668	ext_size = space_of(hpio->eid)->ext_size;
669	dev = device_of(hpio->eid);
670	sec = hpio->eid * ext_size / dev->sec_size;
671	i = 0;
672	bio_for_each_segment_all(bv, hpio->bio, iter) {
673		page = bv->bv_page;
674		BUG_ON(i >= hpio->nr_page);
675		BUG_ON(!hpio->pages[i]);
676		if (dev->ctfm)
677			BUG_ON(soft_crypt_page(dev->ctfm, hpio->pages[i], page, HP_DEV_DECRYPT));
678		sec += PAGE_SIZE / dev->sec_size;
679		i++;
680	}
681endio:
682	put_encrypted_pages(hpio->bio);
683	bio_put(hpio->bio);
684	if (hpio->endio)
685		hpio->endio(hpio);
686}
687
688static void hpio_endio(struct bio *bio)
689{
690	struct hpio *hpio = bio->bi_private;
691	struct workqueue_struct *wq = NULL;
692
693	pr_info("hpio %p for eid %u returned %d.\n",
694			hpio, hpio->eid, bio->bi_status);
695	hpio_set_state(hpio, bio->bi_status ? HPIO_FAIL : HPIO_DONE);
696	wq = op_is_write(hpio->op) ? hyperhold.write_wq : hyperhold.read_wq;
697	queue_work(wq, &hpio->endio_work);
698	atomic64_sub(sizeof(struct bio), &mem_used);
699}
700
701static int hpio_submit(struct hpio *hpio)
702{
703	struct hp_device *dev = NULL;
704	struct bio *bio = NULL;
705	struct page *page = NULL;
706	u32 ext_size;
707	sector_t sec;
708	int i;
709
710	bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
711	if (!bio) {
712		pr_err("bio alloc failed!\n");
713		return -ENOMEM;
714	}
715	atomic64_add(sizeof(struct bio), &mem_used);
716
717	dev = device_of(hpio->eid);
718	bio_set_op_attrs(bio, hpio->op, 0);
719	bio_set_dev(bio, dev->bdev);
720
721	ext_size = space_of(hpio->eid)->ext_size;
722	sec = div_u64((u64)hpio->eid * ext_size, dev->sec_size);
723	bio->bi_iter.bi_sector = sec;
724	for (i = 0; i < hpio->nr_page; i++) {
725		if (!hpio->pages[i])
726			break;
727		hpio->pages[i]->index = sec;
728		page = get_encrypted_page(dev, hpio->pages[i], hpio->op);
729		if (!page)
730			goto err;
731		if (!bio_add_page(bio, page, PAGE_SIZE, 0)) {
732			put_page(page);
733			goto err;
734		}
735		sec += PAGE_SIZE / dev->sec_size;
736	}
737
738	if (dev->blk_key)
739		inline_crypt_bio(dev->blk_key, bio);
740	bio->bi_private = hpio;
741	bio->bi_end_io = hpio_endio;
742	hpio->bio = bio;
743	submit_bio(bio);
744	pr_info("submit hpio %p for eid %u.\n", hpio, hpio->eid);
745
746	return 0;
747err:
748	put_encrypted_pages(bio);
749	bio_put(bio);
750	atomic64_sub(sizeof(struct bio), &mem_used);
751	return -EIO;
752}
753
754static int rw_extent_async(struct hpio *hpio, hp_endio endio, void *priv, unsigned int op)
755{
756	int ret = 0;
757
758	if (!hpio_change_state(hpio, HPIO_INIT, HPIO_SUBMIT))
759		return -EAGAIN;
760
761	hpio->private = priv;
762	hpio->endio = endio;
763	INIT_WORK(&hpio->endio_work, hp_endio_work);
764
765	ret = hpio_submit(hpio);
766	if (ret) {
767		hpio_set_state(hpio, HPIO_FAIL);
768		hpio_complete(hpio);
769	}
770
771	return ret;
772}
773
774int hyperhold_write_async(struct hpio *hpio, hp_endio endio, void *priv)
775{
776	if (!CHECK_ENABLE) {
777		hpio_set_state(hpio, HPIO_FAIL);
778		hpio_complete(hpio);
779		return -EINVAL;
780	}
781
782	BUG_ON(!op_is_write(hpio->op));
783
784	return rw_extent_async(hpio, endio, priv, REQ_OP_WRITE);
785}
786EXPORT_SYMBOL(hyperhold_write_async);
787
788int hyperhold_read_async(struct hpio *hpio, hp_endio endio, void *priv)
789{
790	if (!CHECK_INITED) {
791		hpio_set_state(hpio, HPIO_FAIL);
792		hpio_complete(hpio);
793		return -EINVAL;
794	}
795
796	if (op_is_write(hpio->op))
797		return -EAGAIN;
798
799	return rw_extent_async(hpio, endio, priv, REQ_OP_READ);
800}
801EXPORT_SYMBOL(hyperhold_read_async);
802
803module_init(hyperhold_init)
804module_exit(hyperhold_exit)
805