xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c (revision 2b07b8e0f1a7f1e76f31db24a21a42cbb01d7b9c)
14d1cc41eSFrançois Revol /*
24d1cc41eSFrançois Revol  * Copyright 2006-2007, François Revol. All rights reserved.
34d1cc41eSFrançois Revol  * Distributed under the terms of the MIT License.
44d1cc41eSFrançois Revol  */
54d1cc41eSFrançois Revol 
64d1cc41eSFrançois Revol /*
7771c6b93SFrançois Revol  * nbd driver for Haiku
8771c6b93SFrançois Revol  *
9771c6b93SFrançois Revol  * Maps a Network Block Device as virtual partitions.
104d1cc41eSFrançois Revol  */
114d1cc41eSFrançois Revol 
12835ec57dSFrançois Revol #include <ByteOrder.h>
134d1cc41eSFrançois Revol #include <KernelExport.h>
144d1cc41eSFrançois Revol #include <Drivers.h>
15771c6b93SFrançois Revol #include <driver_settings.h>
16835ec57dSFrançois Revol #include <Errors.h>
17835ec57dSFrançois Revol #include <errno.h>
180f609eb2SFrançois Revol #include <stdio.h>
190f609eb2SFrançois Revol #include <stdlib.h>
2011902c74SFrançois Revol #include <string.h>
210f609eb2SFrançois Revol #include <unistd.h>
224d1cc41eSFrançois Revol #include <ksocket.h>
23771c6b93SFrançois Revol #include <netinet/in.h>
24771c6b93SFrançois Revol 
25ec8bd525SFrançois Revol //#define DEBUG 1
26637cbfeeSFrançois Revol 
277f66887bSFrançois Revol /* on the first open(), open ourselves for some seconds,
287f66887bSFrançois Revol  * to avoid trying to reconnect and failing on a 2nd open,
297f66887bSFrançois Revol  * as it happens with the python server.
307f66887bSFrançois Revol  */
317f66887bSFrançois Revol //#define MOUNT_KLUDGE
327f66887bSFrançois Revol 
33835ec57dSFrançois Revol 
34835ec57dSFrançois Revol /* names, ohh names... */
35835ec57dSFrançois Revol #ifndef SHUT_RDWR
36835ec57dSFrançois Revol #define SHUT_RDWR SHUTDOWN_BOTH
37835ec57dSFrançois Revol #endif
38835ec57dSFrançois Revol 
39637cbfeeSFrançois Revol /* locking support */
40771c6b93SFrançois Revol #ifdef __HAIKU__
41771c6b93SFrançois Revol #include <kernel/lock.h>
42771c6b93SFrançois Revol #else
43637cbfeeSFrançois Revol /* wrappers for R5 */
44771c6b93SFrançois Revol #ifndef _IMPEXP_KERNEL
45771c6b93SFrançois Revol #define _IMPEXP_KERNEL
46771c6b93SFrançois Revol #endif
47771c6b93SFrançois Revol #include "lock.h"
48*2b07b8e0SIngo Weinhold #define mutex lock
49*2b07b8e0SIngo Weinhold #define mutex_init new_lock
50*2b07b8e0SIngo Weinhold #define mutex_destroy free_lock
51*2b07b8e0SIngo Weinhold #define mutex_lock LOCK
52*2b07b8e0SIngo Weinhold #define mutex_unlock UNLOCK
53771c6b93SFrançois Revol #endif
544d1cc41eSFrançois Revol 
55ec8bd525SFrançois Revol #define DEBUG 1
56ec8bd525SFrançois Revol 
574d1cc41eSFrançois Revol #include "nbd.h"
584d1cc41eSFrançois Revol 
59771c6b93SFrançois Revol #define DRV "nbd"
60637cbfeeSFrançois Revol #define DP "nbd:"
614d1cc41eSFrançois Revol #define MAX_NBDS 4
624d1cc41eSFrançois Revol #define DEVICE_PREFIX "disk/virtual/nbd/"
63637cbfeeSFrançois Revol #define DEVICE_FMT DEVICE_PREFIX "%d/raw"
644d1cc41eSFrançois Revol #define DEVICE_NAME_MAX 32
654d1cc41eSFrançois Revol #define MAX_REQ_SIZE (32*1024*1024)
66a0062874SFrançois Revol #define BLKSIZE 512
674d1cc41eSFrançois Revol 
68637cbfeeSFrançois Revol /* debugging */
69637cbfeeSFrançois Revol #if DEBUG
70637cbfeeSFrançois Revol #define PRINT(a) dprintf a
71637cbfeeSFrançois Revol #define WHICH(dev) ((int)(dev - nbd_devices))
72637cbfeeSFrançois Revol #else
73637cbfeeSFrançois Revol #define PRINT(a)
74637cbfeeSFrançois Revol #endif
75637cbfeeSFrançois Revol 
764d1cc41eSFrançois Revol struct nbd_request_entry {
774d1cc41eSFrançois Revol 	struct nbd_request_entry *next;
783ca76df5SFrançois Revol 	struct nbd_request req; /* net byte order */
793ca76df5SFrançois Revol 	struct nbd_reply reply; /* net byte order */
803ca76df5SFrançois Revol 	sem_id sem;
813ca76df5SFrançois Revol 	bool replied;
823ca76df5SFrançois Revol 	bool discard;
833ca76df5SFrançois Revol 	uint64 handle;
843ca76df5SFrançois Revol 	uint32 type;
853ca76df5SFrançois Revol 	uint64 from;
864d1cc41eSFrançois Revol 	size_t len;
874d1cc41eSFrançois Revol 	void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */
884d1cc41eSFrançois Revol };
894d1cc41eSFrançois Revol 
904d1cc41eSFrançois Revol struct nbd_device {
917f66887bSFrançois Revol 	bool valid;
927f66887bSFrançois Revol 	bool readonly;
93771c6b93SFrançois Revol 	struct sockaddr_in server;
94*2b07b8e0SIngo Weinhold 	mutex ben;
954d1cc41eSFrançois Revol 	vint32 refcnt;
964d1cc41eSFrançois Revol 	uint64 req; /* next ID for requests */
974d1cc41eSFrançois Revol 	int sock;
984d1cc41eSFrançois Revol 	thread_id postoffice;
994d1cc41eSFrançois Revol 	uint64 size;
1004d1cc41eSFrançois Revol 	struct nbd_request_entry *reqs;
1017f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
1027f66887bSFrançois Revol 	int kludge;
1037f66887bSFrançois Revol #endif
1044d1cc41eSFrançois Revol };
1054d1cc41eSFrançois Revol 
1064d1cc41eSFrançois Revol typedef struct cookie {
1074d1cc41eSFrançois Revol 	struct nbd_device *dev;
1084d1cc41eSFrançois Revol 
1094d1cc41eSFrançois Revol } cookie_t;
1104d1cc41eSFrançois Revol 
1114d1cc41eSFrançois Revol /* data=NULL on read */
1123ca76df5SFrançois Revol status_t nbd_alloc_request(struct nbd_device *dev, struct nbd_request_entry **req, uint32 type, off_t from, size_t len, const char *data);
1133ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req);
1143ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req);
1153ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req);
1164d1cc41eSFrançois Revol 
117e96eef09SFrançois Revol struct nbd_device *nbd_find_device(const char* name);
118e96eef09SFrançois Revol 
1190f609eb2SFrançois Revol int32 nbd_postoffice(void *arg);
1200f609eb2SFrançois Revol status_t nbd_connect(struct nbd_device *dev);
1210f609eb2SFrançois Revol status_t nbd_teardown(struct nbd_device *dev);
1220f609eb2SFrançois Revol status_t nbd_post_request(struct nbd_device *dev, struct nbd_request_entry *req);
1230f609eb2SFrançois Revol 
1240f609eb2SFrançois Revol status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie);
1250f609eb2SFrançois Revol status_t nbd_close(cookie_t *cookie);
1260f609eb2SFrançois Revol status_t nbd_free(cookie_t *cookie);
1270f609eb2SFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len);
1280f609eb2SFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes);
1290f609eb2SFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes);
1300f609eb2SFrançois Revol 
131771c6b93SFrançois Revol KSOCKET_MODULE_DECL;
132771c6b93SFrançois Revol 
133637cbfeeSFrançois Revol /* HACK:
134637cbfeeSFrançois Revol  * In BONE at least, if connect() fails (EINTR or ETIMEDOUT)
135637cbfeeSFrançois Revol  * keeps locked pages around (likely a bone_data,
136637cbfeeSFrançois Revol  * until TCP gets the last ACK). If that happens, we snooze()
137637cbfeeSFrançois Revol  * in unload_driver() to let TCP timeout before the kernel
138637cbfeeSFrançois Revol  * tries to delete the image. */
139637cbfeeSFrançois Revol bool gDelayUnload = false;
140637cbfeeSFrançois Revol #define BONE_TEARDOWN_DELAY 60000000
141637cbfeeSFrançois Revol 
1420f609eb2SFrançois Revol #if 0
1437f66887bSFrançois Revol #pragma mark ==== support ====
1440f609eb2SFrançois Revol #endif
1457f66887bSFrançois Revol 
1467f66887bSFrançois Revol // move that to ksocket inlined
1477f66887bSFrançois Revol static int kinet_aton(const char *in, struct in_addr *addr)
1487f66887bSFrançois Revol {
1497f66887bSFrançois Revol 	int i;
1507f66887bSFrançois Revol 	unsigned long a;
1517f66887bSFrançois Revol 	uint32 inaddr = 0L;
1520f609eb2SFrançois Revol 	char *p = (char *)in;
1537f66887bSFrançois Revol 	for (i = 0; i < 4; i++) {
1547f66887bSFrançois Revol 		a = strtoul(p, &p, 10);
1557f66887bSFrançois Revol 		if (!p)
1567f66887bSFrançois Revol 			return -1;
1577f66887bSFrançois Revol 		inaddr = (inaddr >> 8) | ((a & 0x0ff) << 24);
1587f66887bSFrançois Revol 		*(uint32 *)addr = inaddr;
1597f66887bSFrançois Revol 		if (!*p)
1607f66887bSFrançois Revol 			return 0;
1617f66887bSFrançois Revol 		p++;
1627f66887bSFrançois Revol 	}
1637f66887bSFrançois Revol 	return 0;
1647f66887bSFrançois Revol }
1657f66887bSFrançois Revol 
1660f609eb2SFrançois Revol #if 0
1674d1cc41eSFrançois Revol #pragma mark ==== request manager ====
1680f609eb2SFrançois Revol #endif
1694d1cc41eSFrançois Revol 
1703ca76df5SFrançois Revol status_t nbd_alloc_request(struct nbd_device *dev, struct nbd_request_entry **req, uint32 type, off_t from, size_t len, const char *data)
1713ca76df5SFrançois Revol {
1723ca76df5SFrançois Revol 	bool w = (type == NBD_CMD_WRITE);
1733ca76df5SFrançois Revol 	struct nbd_request_entry *r;
1743ca76df5SFrançois Revol 	status_t err = EINVAL;
1753ca76df5SFrançois Revol 	uint64 handle;
1763ca76df5SFrançois Revol 	PRINT((DP ">%s(%ld, %Ld, %ld)\n", __FUNCTION__, type, from, len));
1773ca76df5SFrançois Revol 
1783ca76df5SFrançois Revol 	if (type != NBD_CMD_READ && type != NBD_CMD_WRITE && type != NBD_CMD_DISC)
1793ca76df5SFrançois Revol 		return err;
1803ca76df5SFrançois Revol 	if (!dev || !req || from < 0)
1813ca76df5SFrançois Revol 		return err;
1823ca76df5SFrançois Revol 
1833ca76df5SFrançois Revol 	//LOCK
184*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
1853ca76df5SFrançois Revol 	if (err)
1863ca76df5SFrançois Revol 		return err;
1873ca76df5SFrançois Revol 
1883ca76df5SFrançois Revol 	// atomic
1893ca76df5SFrançois Revol 	handle = dev->req++;
1903ca76df5SFrançois Revol 
1913ca76df5SFrançois Revol 
1923ca76df5SFrançois Revol 	//UNLOCK
193*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
1943ca76df5SFrançois Revol 
1953ca76df5SFrançois Revol 	err = ENOMEM;
1963ca76df5SFrançois Revol 	r = malloc(sizeof(struct nbd_request_entry) + (w ? 0 : len));
1973ca76df5SFrançois Revol 	if (r == NULL)
1983ca76df5SFrançois Revol 		goto err0;
1993ca76df5SFrançois Revol 	r->next = NULL;
2003ca76df5SFrançois Revol 	err = r->sem = create_sem(0, "nbd request sem");
2013ca76df5SFrançois Revol 	if (err < 0)
2023ca76df5SFrançois Revol 		goto err1;
2033ca76df5SFrançois Revol 
2043ca76df5SFrançois Revol 	r->replied = false;
2053ca76df5SFrançois Revol 	r->discard = false;
2063ca76df5SFrançois Revol 	r->handle = handle;
2073ca76df5SFrançois Revol 	r->type = type;
2083ca76df5SFrançois Revol 	r->from = from;
2093ca76df5SFrançois Revol 	r->len = len;
2103ca76df5SFrançois Revol 
2113ca76df5SFrançois Revol 	r->req.magic = B_HOST_TO_BENDIAN_INT32(NBD_REQUEST_MAGIC);
2123ca76df5SFrançois Revol 	r->req.type = B_HOST_TO_BENDIAN_INT32(type);
2133ca76df5SFrançois Revol 	r->req.handle = B_HOST_TO_BENDIAN_INT64(r->handle);
2143ca76df5SFrançois Revol 	r->req.from = B_HOST_TO_BENDIAN_INT64(r->from);
2153ca76df5SFrançois Revol 	r->req.len = B_HOST_TO_BENDIAN_INT32(len);
2163ca76df5SFrançois Revol 
2170f609eb2SFrançois Revol 	r->buffer = (void *)(w ? data : (((char *)r) + sizeof(struct nbd_request_entry)));
2183ca76df5SFrançois Revol 
2193ca76df5SFrançois Revol 	*req = r;
2203ca76df5SFrançois Revol 	return B_OK;
2213ca76df5SFrançois Revol 
2223ca76df5SFrançois Revol err1:
2233ca76df5SFrançois Revol 	free(r);
2243ca76df5SFrançois Revol err0:
2253ca76df5SFrançois Revol 	dprintf(DP " %s: error 0x%08lx\n", __FUNCTION__, err);
2263ca76df5SFrançois Revol 	return err;
2273ca76df5SFrançois Revol }
2283ca76df5SFrançois Revol 
2293ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req)
2303ca76df5SFrançois Revol {
2313ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
2323ca76df5SFrançois Revol 	req->next = dev->reqs;
2333ca76df5SFrançois Revol 	dev->reqs = req;
2343ca76df5SFrançois Revol 	return B_OK;
2353ca76df5SFrançois Revol }
2363ca76df5SFrançois Revol 
2373ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req)
2383ca76df5SFrançois Revol {
2393ca76df5SFrançois Revol 	struct nbd_request_entry *r, *prev;
2403ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, handle));
2413ca76df5SFrançois Revol 	r = dev->reqs;
2423ca76df5SFrançois Revol 	prev = NULL;
2433ca76df5SFrançois Revol 	while (r && r->handle != handle) {
2443ca76df5SFrançois Revol 		prev = r;
2453ca76df5SFrançois Revol 		r = r->next;
2463ca76df5SFrançois Revol 	}
2473ca76df5SFrançois Revol 	if (!r)
2483ca76df5SFrançois Revol 		return ENOENT;
2493ca76df5SFrançois Revol 
2503ca76df5SFrançois Revol 	if (prev)
2513ca76df5SFrançois Revol 		prev->next = r->next;
2523ca76df5SFrançois Revol 	else
2533ca76df5SFrançois Revol 		dev->reqs = r->next;
2543ca76df5SFrançois Revol 
2553ca76df5SFrançois Revol 	*req = r;
2563ca76df5SFrançois Revol 	return B_OK;
2573ca76df5SFrançois Revol }
2583ca76df5SFrançois Revol 
2593ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req)
2603ca76df5SFrançois Revol {
2613ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
2623ca76df5SFrançois Revol 	delete_sem(req->sem);
2633ca76df5SFrançois Revol 	free(req);
2643ca76df5SFrançois Revol 	return B_OK;
2653ca76df5SFrançois Revol }
2663ca76df5SFrançois Revol 
2673ca76df5SFrançois Revol 
2684d1cc41eSFrançois Revol 
2690f609eb2SFrançois Revol #if 0
2704d1cc41eSFrançois Revol #pragma mark ==== nbd handler ====
2710f609eb2SFrançois Revol #endif
2724d1cc41eSFrançois Revol 
273637cbfeeSFrançois Revol int32 nbd_postoffice(void *arg)
2744d1cc41eSFrançois Revol {
2754d1cc41eSFrançois Revol 	struct nbd_device *dev = (struct nbd_device *)arg;
2763ca76df5SFrançois Revol 	struct nbd_request_entry *req = NULL;
2773ca76df5SFrançois Revol 	struct nbd_reply reply;
2783ca76df5SFrançois Revol 	status_t err;
2793ca76df5SFrançois Revol 	const char *reason;
280637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
2814d1cc41eSFrançois Revol 
2823ca76df5SFrançois Revol 	for (;;) {
2833ca76df5SFrançois Revol 		reason = "recv";
2843ca76df5SFrançois Revol 		err = krecv(dev->sock, &reply, sizeof(reply), 0);
2853ca76df5SFrançois Revol 		if (err == -1 && errno < 0)
2863ca76df5SFrançois Revol 			err = errno;
2873ca76df5SFrançois Revol 		if (err < 0)
2883ca76df5SFrançois Revol 			goto err;
2893ca76df5SFrançois Revol 		reason = "recv:size";
2903ca76df5SFrançois Revol 		if (err < sizeof(reply))
2913ca76df5SFrançois Revol 			err = EINVAL;
2923ca76df5SFrançois Revol 		if (err < 0)
2933ca76df5SFrançois Revol 			goto err;
2943ca76df5SFrançois Revol 		reason = "magic";
2953ca76df5SFrançois Revol 		err = EINVAL;
2963ca76df5SFrançois Revol 		if (B_BENDIAN_TO_HOST_INT32(reply.magic) != NBD_REPLY_MAGIC)
2973ca76df5SFrançois Revol 			goto err;
2984d1cc41eSFrançois Revol 
2993ca76df5SFrançois Revol 		reason = "lock";
3003ca76df5SFrançois Revol 		//LOCK
301*2b07b8e0SIngo Weinhold 		err = mutex_lock(&dev->ben);
3023ca76df5SFrançois Revol 		if (err)
3033ca76df5SFrançois Revol 			goto err;
3043ca76df5SFrançois Revol 
3053ca76df5SFrançois Revol 		reason = "dequeue_request";
3063ca76df5SFrançois Revol 		err = nbd_dequeue_request(dev, B_BENDIAN_TO_HOST_INT64(reply.handle), &req);
3073ca76df5SFrançois Revol 
3083ca76df5SFrançois Revol 		//UNLOCK
309*2b07b8e0SIngo Weinhold 		mutex_unlock(&dev->ben);
3103ca76df5SFrançois Revol 
3113ca76df5SFrançois Revol 		if (!err && !req) {
3123ca76df5SFrançois Revol 			dprintf(DP "nbd_dequeue_rquest found NULL!\n");
3133ca76df5SFrançois Revol 			err = ENOENT;
3143ca76df5SFrançois Revol 		}
3153ca76df5SFrançois Revol 
3163ca76df5SFrançois Revol 		if (err == B_OK) {
3173ca76df5SFrançois Revol 			memcpy(&req->reply, &reply, sizeof(reply));
3183ca76df5SFrançois Revol 			if (req->type == NBD_CMD_READ) {
3193ca76df5SFrançois Revol 				err = 0;
3203ca76df5SFrançois Revol 				reason = "recv(data)";
3213ca76df5SFrançois Revol 				if (reply.error == 0)
3223ca76df5SFrançois Revol 					err = krecv(dev->sock, req->buffer, req->len, 0);
3233ca76df5SFrançois Revol 				if (err < 0)
3243ca76df5SFrançois Revol 					goto err;
3253ca76df5SFrançois Revol 				/* tell back how much we've got (?) */
3263ca76df5SFrançois Revol 				req->len = err;
3273ca76df5SFrançois Revol 			} else {
3283ca76df5SFrançois Revol 				if (reply.error)
3293ca76df5SFrançois Revol 					req->len = 0;
3303ca76df5SFrançois Revol 			}
3313ca76df5SFrançois Revol 
3323ca76df5SFrançois Revol 			reason = "lock";
3333ca76df5SFrançois Revol 			//LOCK
334*2b07b8e0SIngo Weinhold 			err = mutex_lock(&dev->ben);
3353ca76df5SFrançois Revol 			if (err)
3363ca76df5SFrançois Revol 				goto err;
3373ca76df5SFrançois Revol 
3383ca76df5SFrançois Revol 			// this also must be atomic!
3393ca76df5SFrançois Revol 			release_sem(req->sem);
3403ca76df5SFrançois Revol 			req->replied = true;
3413ca76df5SFrançois Revol 			if (req->discard)
3423ca76df5SFrançois Revol 				nbd_free_request(dev, req);
3433ca76df5SFrançois Revol 
3443ca76df5SFrançois Revol 			//UNLOCK
345*2b07b8e0SIngo Weinhold 			mutex_unlock(&dev->ben);
3463ca76df5SFrançois Revol 		}
3473ca76df5SFrançois Revol 
3483ca76df5SFrançois Revol 	}
3494d1cc41eSFrançois Revol 
350637cbfeeSFrançois Revol 	PRINT((DP "<%s\n", __FUNCTION__));
3514d1cc41eSFrançois Revol 	return 0;
3523ca76df5SFrançois Revol 
3533ca76df5SFrançois Revol err:
3543ca76df5SFrançois Revol 	dprintf(DP "%s: %s: error 0x%08lx\n", __FUNCTION__, reason, err);
3553ca76df5SFrançois Revol 	return err;
3564d1cc41eSFrançois Revol }
3574d1cc41eSFrançois Revol 
358771c6b93SFrançois Revol status_t nbd_connect(struct nbd_device *dev)
359771c6b93SFrançois Revol {
360637cbfeeSFrançois Revol 	struct nbd_init_packet initpkt;
361637cbfeeSFrançois Revol 	status_t err;
362637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
363771c6b93SFrançois Revol 
364637cbfeeSFrançois Revol 	PRINT((DP " %s: socket()\n", __FUNCTION__));
365637cbfeeSFrançois Revol 	err = dev->sock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
366637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
367637cbfeeSFrançois Revol 		err = errno;
368637cbfeeSFrançois Revol 	if (err < 0)
369637cbfeeSFrançois Revol 		goto err0;
370637cbfeeSFrançois Revol 
371637cbfeeSFrançois Revol 	PRINT((DP " %s: connect()\n", __FUNCTION__));
372637cbfeeSFrançois Revol 	err = kconnect(dev->sock, (struct sockaddr *)&dev->server, sizeof(dev->server));
373637cbfeeSFrançois Revol 	//err = ENOSYS;
374637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
375637cbfeeSFrançois Revol 		err = errno;
3760f609eb2SFrançois Revol 	/* HACK: avoid the kernel unloading us with locked pages from TCP */
377637cbfeeSFrançois Revol 	if (err)
378637cbfeeSFrançois Revol 		gDelayUnload = true;
379637cbfeeSFrançois Revol 	if (err)
380637cbfeeSFrançois Revol 		goto err1;
381637cbfeeSFrançois Revol 
382637cbfeeSFrançois Revol 	PRINT((DP " %s: recv(initpkt)\n", __FUNCTION__));
383637cbfeeSFrançois Revol 	err = krecv(dev->sock, &initpkt, sizeof(initpkt), 0);
384637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
385637cbfeeSFrançois Revol 		err = errno;
386637cbfeeSFrançois Revol 	if (err < sizeof(initpkt))
387637cbfeeSFrançois Revol 		goto err2;
388637cbfeeSFrançois Revol 	err = EINVAL;//EPROTO;
389637cbfeeSFrançois Revol 	if (memcmp(initpkt.passwd, NBD_INIT_PASSWD, sizeof(initpkt.passwd)))
390637cbfeeSFrançois Revol 		goto err3;
391637cbfeeSFrançois Revol 	if (B_BENDIAN_TO_HOST_INT64(initpkt.magic) != NBD_INIT_MAGIC)
392637cbfeeSFrançois Revol 		goto err3;
393637cbfeeSFrançois Revol 
394637cbfeeSFrançois Revol 	dev->size = B_BENDIAN_TO_HOST_INT64(initpkt.device_size);
395637cbfeeSFrançois Revol 
396637cbfeeSFrançois Revol 	dprintf(DP " %s: connected, device size %Ld bytes.\n", __FUNCTION__, dev->size);
397637cbfeeSFrançois Revol 
398637cbfeeSFrançois Revol 	err = dev->postoffice = spawn_kernel_thread(nbd_postoffice, "nbd postoffice", B_REAL_TIME_PRIORITY, dev);
399637cbfeeSFrançois Revol 	if (err < B_OK)
400637cbfeeSFrançois Revol 		goto err4;
401637cbfeeSFrançois Revol 	resume_thread(dev->postoffice);
402637cbfeeSFrançois Revol 
403637cbfeeSFrançois Revol 	PRINT((DP "<%s\n", __FUNCTION__));
404771c6b93SFrançois Revol 	return B_OK;
405637cbfeeSFrançois Revol 
406637cbfeeSFrançois Revol err4:
407637cbfeeSFrançois Revol 	dev->postoffice = -1;
408637cbfeeSFrançois Revol err3:
409637cbfeeSFrançois Revol err2:
410637cbfeeSFrançois Revol err1:
411637cbfeeSFrançois Revol 	kclosesocket(dev->sock);
412637cbfeeSFrançois Revol 	dev->sock = -1;
413637cbfeeSFrançois Revol err0:
414637cbfeeSFrançois Revol 	dprintf(DP "<%s: error 0x%08lx\n", __FUNCTION__, err);
415637cbfeeSFrançois Revol 	return err;
416771c6b93SFrançois Revol }
417771c6b93SFrançois Revol 
418771c6b93SFrançois Revol status_t nbd_teardown(struct nbd_device *dev)
419771c6b93SFrançois Revol {
420637cbfeeSFrançois Revol 	status_t err, ret;
421637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
422835ec57dSFrançois Revol 	kshutdown(dev->sock, SHUT_RDWR);
423637cbfeeSFrançois Revol 	kclosesocket(dev->sock);
424637cbfeeSFrançois Revol 	dev->sock = -1;
425637cbfeeSFrançois Revol 	err = wait_for_thread(dev->postoffice, &ret);
426771c6b93SFrançois Revol 	return B_OK;
427771c6b93SFrançois Revol }
428771c6b93SFrançois Revol 
4293ca76df5SFrançois Revol status_t nbd_post_request(struct nbd_device *dev, struct nbd_request_entry *req)
4303ca76df5SFrançois Revol {
4313ca76df5SFrançois Revol 	status_t err;
4323ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
4333ca76df5SFrançois Revol 
4343ca76df5SFrançois Revol 	err = ksend(dev->sock, &req->req, sizeof(req->req), 0);
4353ca76df5SFrançois Revol 	if (err < 0)
4363ca76df5SFrançois Revol 		return err;
4373ca76df5SFrançois Revol 
438ff517f43SFrançois Revol 	if (req->type == NBD_CMD_WRITE)
439ff517f43SFrançois Revol 		err = ksend(dev->sock, req->buffer, req->len, 0);
440ff517f43SFrançois Revol 	if (err < 0)
441ff517f43SFrançois Revol 		return err;
442ff517f43SFrançois Revol 	else
443ff517f43SFrançois Revol 		req->len = err;
444ff517f43SFrançois Revol 
4453ca76df5SFrançois Revol 	err = nbd_queue_request(dev, req);
4463ca76df5SFrançois Revol 	return err;
4473ca76df5SFrançois Revol }
4483ca76df5SFrançois Revol 
4493ca76df5SFrançois Revol 
4500f609eb2SFrançois Revol #if 0
4514d1cc41eSFrançois Revol #pragma mark ==== device hooks ====
4520f609eb2SFrançois Revol #endif
4534d1cc41eSFrançois Revol 
454e96eef09SFrançois Revol static struct nbd_device nbd_devices[MAX_NBDS];
455e96eef09SFrançois Revol 
4564d1cc41eSFrançois Revol status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie) {
457771c6b93SFrançois Revol 	status_t err;
4587f66887bSFrançois Revol 	int32 refcnt;
4597f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
4607f66887bSFrançois Revol 	int kfd;
4617f66887bSFrançois Revol #endif
462e96eef09SFrançois Revol 	struct nbd_device *dev = NULL;
4630f609eb2SFrançois Revol 	PRINT((DP ">%s(%s, %lx, )\n", __FUNCTION__, name, flags));
4644d1cc41eSFrançois Revol 	(void)name; (void)flags;
465e96eef09SFrançois Revol 	dev = nbd_find_device(name);
4667f66887bSFrançois Revol 	if (!dev || !dev->valid)
467e96eef09SFrançois Revol 		return ENOENT;
468771c6b93SFrançois Revol 	err = ENOMEM;
4694d1cc41eSFrançois Revol 	*cookie = (void*)malloc(sizeof(cookie_t));
470771c6b93SFrançois Revol 	if (*cookie == NULL)
4714d1cc41eSFrançois Revol 		goto err0;
4724d1cc41eSFrançois Revol 	memset(*cookie, 0, sizeof(cookie_t));
473e96eef09SFrançois Revol 	(*cookie)->dev = dev;
474*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
475771c6b93SFrançois Revol 	if (err)
476771c6b93SFrançois Revol 		goto err1;
477771c6b93SFrançois Revol 	/*  */
478771c6b93SFrançois Revol 	if (dev->sock < 0)
479771c6b93SFrançois Revol 		err = nbd_connect(dev);
480771c6b93SFrançois Revol 	if (err)
481771c6b93SFrançois Revol 		goto err2;
4827f66887bSFrançois Revol 	refcnt = dev->refcnt++;
4837f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
4847f66887bSFrançois Revol 	kfd = dev->kludge;
4857f66887bSFrançois Revol 	dev->kludge = -1;
4867f66887bSFrançois Revol #endif
487*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
4887f66887bSFrançois Revol 
4897f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
4907f66887bSFrançois Revol 	if (refcnt == 0) {
4917f66887bSFrançois Revol 		char buf[32];
4927f66887bSFrançois Revol 		sprintf(buf, "/dev/%s", name);
4937f66887bSFrançois Revol 		dev->kludge = open(buf, O_RDONLY);
4947f66887bSFrançois Revol 	} else if (kfd) {
4957f66887bSFrançois Revol 		close(kfd);
4967f66887bSFrançois Revol 	}
4977f66887bSFrançois Revol #endif
4987f66887bSFrançois Revol 
4994d1cc41eSFrançois Revol 	return B_OK;
500771c6b93SFrançois Revol 
501771c6b93SFrançois Revol err2:
502*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
503771c6b93SFrançois Revol err1:
504771c6b93SFrançois Revol 	free(*cookie);
5054d1cc41eSFrançois Revol err0:
506637cbfeeSFrançois Revol 	dprintf(DP " %s: error 0x%08lx\n", __FUNCTION__, err);
507771c6b93SFrançois Revol 	return err;
5084d1cc41eSFrançois Revol }
5094d1cc41eSFrançois Revol 
510771c6b93SFrançois Revol status_t nbd_close(cookie_t *cookie) {
511771c6b93SFrançois Revol 	struct nbd_device *dev = cookie->dev;
512771c6b93SFrançois Revol 	status_t err;
5137f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5147f66887bSFrançois Revol 	int kfd = -1;
5157f66887bSFrançois Revol #endif
516637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev)));
517771c6b93SFrançois Revol 
518*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
519771c6b93SFrançois Revol 	if (err)
520771c6b93SFrançois Revol 		return err;
521771c6b93SFrançois Revol 
522771c6b93SFrançois Revol 	// XXX: do something ?
5237f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5247f66887bSFrançois Revol 	kfd = dev->kludge;
5257f66887bSFrançois Revol 	dev->kludge = -1;
5267f66887bSFrançois Revol #endif
527771c6b93SFrançois Revol 
528*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
5297f66887bSFrançois Revol 
5307f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5317f66887bSFrançois Revol 	if (kfd > -1) {
5327f66887bSFrançois Revol 		close(kfd);
5337f66887bSFrançois Revol 	}
5347f66887bSFrançois Revol #endif
5354d1cc41eSFrançois Revol 	return B_OK;
5364d1cc41eSFrançois Revol }
5374d1cc41eSFrançois Revol 
5384d1cc41eSFrançois Revol status_t nbd_free(cookie_t *cookie) {
539771c6b93SFrançois Revol 	struct nbd_device *dev = cookie->dev;
540771c6b93SFrançois Revol 	status_t err;
541637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev)));
542771c6b93SFrançois Revol 
543*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
544771c6b93SFrançois Revol 	if (err)
545771c6b93SFrançois Revol 		return err;
546771c6b93SFrançois Revol 
547771c6b93SFrançois Revol 	if (--dev->refcnt == 0) {
548771c6b93SFrançois Revol 		err = nbd_teardown(dev);
549771c6b93SFrançois Revol 	}
550771c6b93SFrançois Revol 
551*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
552771c6b93SFrançois Revol 
5534d1cc41eSFrançois Revol 	free(cookie);
554771c6b93SFrançois Revol 	return err;
5554d1cc41eSFrançois Revol }
5564d1cc41eSFrançois Revol 
5574d1cc41eSFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) {
5580f609eb2SFrançois Revol 	PRINT((DP ">%s(%d, %lu, , %ld)\n", __FUNCTION__, WHICH(cookie->dev), op, len));
5594d1cc41eSFrançois Revol 	switch (op) {
5604d1cc41eSFrançois Revol 	case B_GET_DEVICE_SIZE: /* this one is broken anyway... */
5614d1cc41eSFrançois Revol 		if (data) {
5624d1cc41eSFrançois Revol 			*(size_t *)data = (size_t)cookie->dev->size;
5634d1cc41eSFrançois Revol 			return B_OK;
5644d1cc41eSFrançois Revol 		}
5654d1cc41eSFrançois Revol 		return EINVAL;
5664d1cc41eSFrançois Revol 	case B_SET_DEVICE_SIZE: /* broken */
5674d1cc41eSFrançois Revol 		return EINVAL;
5684d1cc41eSFrançois Revol 	case B_SET_NONBLOCKING_IO:
5694d1cc41eSFrançois Revol 		return EINVAL;
5704d1cc41eSFrançois Revol 	case B_SET_BLOCKING_IO:
5714d1cc41eSFrançois Revol 		return B_OK;
5724d1cc41eSFrançois Revol 	case B_GET_READ_STATUS:
5734d1cc41eSFrançois Revol 	case B_GET_WRITE_STATUS:
5744d1cc41eSFrançois Revol 		if (data) {
5754d1cc41eSFrançois Revol 			*(bool *)data = false;
5764d1cc41eSFrançois Revol 			return B_OK;
5774d1cc41eSFrançois Revol 		}
5784d1cc41eSFrançois Revol 		return EINVAL;
5794d1cc41eSFrançois Revol 	case B_GET_GEOMETRY:
5804d1cc41eSFrançois Revol 	case B_GET_BIOS_GEOMETRY:
5814d1cc41eSFrançois Revol 		if (data) {
5824d1cc41eSFrançois Revol 			device_geometry *geom = (device_geometry *)data;
583a0062874SFrançois Revol 			geom->bytes_per_sector = BLKSIZE;
5844d1cc41eSFrançois Revol 			geom->sectors_per_track = 1;
585a0062874SFrançois Revol 			geom->cylinder_count = cookie->dev->size / BLKSIZE;
5864d1cc41eSFrançois Revol 			geom->head_count = 1;
5874d1cc41eSFrançois Revol 			geom->device_type = B_DISK;
5884d1cc41eSFrançois Revol 			geom->removable = false;
589ff517f43SFrançois Revol 			geom->read_only = cookie->dev->readonly;
5904d1cc41eSFrançois Revol 			geom->write_once = false;
5914d1cc41eSFrançois Revol 			return B_OK;
5924d1cc41eSFrançois Revol 		}
5934d1cc41eSFrançois Revol 		return EINVAL;
5944d1cc41eSFrançois Revol 	case B_GET_MEDIA_STATUS:
5954d1cc41eSFrançois Revol 		if (data) {
5964d1cc41eSFrançois Revol 			*(status_t *)data = B_OK;
5974d1cc41eSFrançois Revol 			return B_OK;
5984d1cc41eSFrançois Revol 		}
5994d1cc41eSFrançois Revol 		return EINVAL;
6004d1cc41eSFrançois Revol 
6014d1cc41eSFrançois Revol 	case B_EJECT_DEVICE:
6024d1cc41eSFrançois Revol 	case B_LOAD_MEDIA:
603a0062874SFrançois Revol 		return B_BAD_VALUE;
6044d1cc41eSFrançois Revol 	case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */
605a0062874SFrançois Revol 		return B_OK;
6064d1cc41eSFrançois Revol 	default:
607a0062874SFrançois Revol 		return B_BAD_VALUE;
6084d1cc41eSFrançois Revol 	}
6094d1cc41eSFrançois Revol 	return B_NOT_ALLOWED;
6104d1cc41eSFrançois Revol }
6114d1cc41eSFrançois Revol 
6124d1cc41eSFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) {
6133ca76df5SFrançois Revol 	struct nbd_device *dev = cookie->dev;
6143ca76df5SFrançois Revol 	struct nbd_request_entry *req;
6153ca76df5SFrançois Revol 	status_t err, semerr;
616637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d, %Ld, , )\n", __FUNCTION__, WHICH(cookie->dev), position));
6173ca76df5SFrançois Revol 
6183ca76df5SFrançois Revol 	if (position < 0)
6193ca76df5SFrançois Revol 		return EINVAL;
6203ca76df5SFrançois Revol 	if (!data)
6213ca76df5SFrançois Revol 		return EINVAL;
6223ca76df5SFrançois Revol 
6233ca76df5SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_READ, position, *numbytes, NULL);
6243ca76df5SFrançois Revol 	if (err)
6253ca76df5SFrançois Revol 		goto err0;
6263ca76df5SFrançois Revol 
6273ca76df5SFrançois Revol 	//LOCK
628*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6293ca76df5SFrançois Revol 	if (err)
6303ca76df5SFrançois Revol 		goto err1;
6313ca76df5SFrançois Revol 
6323ca76df5SFrançois Revol 	err = nbd_post_request(dev, req);
6333ca76df5SFrançois Revol 
6343ca76df5SFrançois Revol 	//UNLOCK
635*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6363ca76df5SFrançois Revol 
6373ca76df5SFrançois Revol 	if (err)
6383ca76df5SFrançois Revol 		goto err2;
6393ca76df5SFrançois Revol 
6403ca76df5SFrançois Revol 
6413ca76df5SFrançois Revol 	semerr = acquire_sem(req->sem);
6423ca76df5SFrançois Revol 
6433ca76df5SFrançois Revol 	//LOCK
644*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6453ca76df5SFrançois Revol 	if(err)
6463ca76df5SFrançois Revol 		goto err3;
6473ca76df5SFrançois Revol 
6483ca76df5SFrançois Revol 	/* bad scenarii */
6493ca76df5SFrançois Revol 	if (!req->replied)
6503ca76df5SFrançois Revol 		req->discard = true;
6513ca76df5SFrançois Revol 	else if (semerr)
6523ca76df5SFrançois Revol 		nbd_free_request(dev, req);
6533ca76df5SFrançois Revol 
6543ca76df5SFrançois Revol 	//UNLOCK
655*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6563ca76df5SFrançois Revol 
6573ca76df5SFrançois Revol 	if (semerr == B_OK) {
6583ca76df5SFrançois Revol 		*numbytes = req->len;
6593ca76df5SFrançois Revol 		memcpy(data, req->buffer, req->len);
660ff517f43SFrançois Revol 		err = B_OK;
6613ca76df5SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
662ff517f43SFrançois Revol 			err = EIO;
663ff517f43SFrançois Revol 		nbd_free_request(dev, req);
664ff517f43SFrançois Revol 		return err;
6653ca76df5SFrançois Revol 	}
6663ca76df5SFrançois Revol 
6674d1cc41eSFrançois Revol 	*numbytes = 0;
6683ca76df5SFrançois Revol 	return semerr;
6693ca76df5SFrançois Revol 
6703ca76df5SFrançois Revol 
6713ca76df5SFrançois Revol err3:
6723ca76df5SFrançois Revol err2:
6733ca76df5SFrançois Revol err1:
6743ca76df5SFrançois Revol 	nbd_free_request(dev, req);
6753ca76df5SFrançois Revol err0:
6763ca76df5SFrançois Revol 	*numbytes = 0;
6773ca76df5SFrançois Revol 	return err;
6784d1cc41eSFrançois Revol }
6794d1cc41eSFrançois Revol 
6804d1cc41eSFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) {
681ff517f43SFrançois Revol 	struct nbd_device *dev = cookie->dev;
682ff517f43SFrançois Revol 	struct nbd_request_entry *req;
683ff517f43SFrançois Revol 	status_t err, semerr;
684ff517f43SFrançois Revol 	PRINT((DP ">%s(%d, %Ld, %ld, )\n", __FUNCTION__, WHICH(cookie->dev), position, *numbytes));
685ff517f43SFrançois Revol 
686ff517f43SFrançois Revol 	if (position < 0)
687ff517f43SFrançois Revol 		return EINVAL;
688ff517f43SFrançois Revol 	if (!data)
689ff517f43SFrançois Revol 		return EINVAL;
690ff517f43SFrançois Revol 	err = B_NOT_ALLOWED;
691ff517f43SFrançois Revol 	if (dev->readonly)
692ff517f43SFrançois Revol 		goto err0;
693ff517f43SFrançois Revol 
694ff517f43SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_WRITE, position, *numbytes, data);
695ff517f43SFrançois Revol 	if (err)
696ff517f43SFrançois Revol 		goto err0;
697ff517f43SFrançois Revol 
698ff517f43SFrançois Revol 	//LOCK
699*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
700ff517f43SFrançois Revol 	if (err)
701ff517f43SFrançois Revol 		goto err1;
702ff517f43SFrançois Revol 
703ff517f43SFrançois Revol 	/* sending request+data must be atomic */
704ff517f43SFrançois Revol 	err = nbd_post_request(dev, req);
705ff517f43SFrançois Revol 
706ff517f43SFrançois Revol 	//UNLOCK
707*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
708ff517f43SFrançois Revol 
709ff517f43SFrançois Revol 	if (err)
710ff517f43SFrançois Revol 		goto err2;
711ff517f43SFrançois Revol 
712ff517f43SFrançois Revol 
713ff517f43SFrançois Revol 	semerr = acquire_sem(req->sem);
714ff517f43SFrançois Revol 
715ff517f43SFrançois Revol 	//LOCK
716*2b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
717ff517f43SFrançois Revol 	if(err)
718ff517f43SFrançois Revol 		goto err3;
719ff517f43SFrançois Revol 
720ff517f43SFrançois Revol 	/* bad scenarii */
721ff517f43SFrançois Revol 	if (!req->replied)
722ff517f43SFrançois Revol 		req->discard = true;
723ff517f43SFrançois Revol 	else if (semerr)
724ff517f43SFrançois Revol 		nbd_free_request(dev, req);
725ff517f43SFrançois Revol 
726ff517f43SFrançois Revol 	//UNLOCK
727*2b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
728ff517f43SFrançois Revol 
729ff517f43SFrançois Revol 	if (semerr == B_OK) {
730ff517f43SFrançois Revol 		*numbytes = req->len;
731ff517f43SFrançois Revol 		err = B_OK;
732ff517f43SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
733ff517f43SFrançois Revol 			err = EIO;
734ff517f43SFrançois Revol 		nbd_free_request(dev, req);
735ff517f43SFrançois Revol 		return err;
736ff517f43SFrançois Revol 	}
737ff517f43SFrançois Revol 
7384d1cc41eSFrançois Revol 	*numbytes = 0;
739ff517f43SFrançois Revol 	return semerr;
740ff517f43SFrançois Revol 
741ff517f43SFrançois Revol 
742ff517f43SFrançois Revol err3:
743ff517f43SFrançois Revol err2:
744ff517f43SFrançois Revol err1:
745ff517f43SFrançois Revol 	nbd_free_request(dev, req);
746ff517f43SFrançois Revol err0:
747ff517f43SFrançois Revol 	*numbytes = 0;
748ff517f43SFrançois Revol 	return err;
7494d1cc41eSFrançois Revol }
7504d1cc41eSFrançois Revol 
7514d1cc41eSFrançois Revol device_hooks nbd_hooks={
7524d1cc41eSFrançois Revol 	(device_open_hook)nbd_open,
753ff517f43SFrançois Revol 	(device_close_hook)nbd_close,
7544d1cc41eSFrançois Revol 	(device_free_hook)nbd_free,
7554d1cc41eSFrançois Revol 	(device_control_hook)nbd_control,
7564d1cc41eSFrançois Revol 	(device_read_hook)nbd_read,
7574d1cc41eSFrançois Revol 	(device_write_hook)nbd_write,
7584d1cc41eSFrançois Revol 	NULL,
7594d1cc41eSFrançois Revol 	NULL,
7604d1cc41eSFrançois Revol 	NULL,
7614d1cc41eSFrançois Revol 	NULL
7624d1cc41eSFrançois Revol };
7634d1cc41eSFrançois Revol 
7640f609eb2SFrançois Revol #if 0
7654d1cc41eSFrançois Revol #pragma mark ==== driver hooks ====
7660f609eb2SFrançois Revol #endif
7674d1cc41eSFrançois Revol 
768ec8bd525SFrançois Revol int32 api_version = B_CUR_DRIVER_API_VERSION;
769ec8bd525SFrançois Revol 
770ff517f43SFrançois Revol static char *nbd_name[MAX_NBDS+1] = {
7714d1cc41eSFrançois Revol 	NULL
7724d1cc41eSFrançois Revol };
7734d1cc41eSFrançois Revol 
7744d1cc41eSFrançois Revol status_t
7754d1cc41eSFrançois Revol init_hardware (void)
7764d1cc41eSFrançois Revol {
777637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
7784d1cc41eSFrançois Revol 	return B_OK;
7794d1cc41eSFrançois Revol }
7804d1cc41eSFrançois Revol 
7814d1cc41eSFrançois Revol status_t
7824d1cc41eSFrançois Revol init_driver (void)
7834d1cc41eSFrançois Revol {
784771c6b93SFrançois Revol 	status_t err;
785771c6b93SFrançois Revol 	int i, j;
786771c6b93SFrançois Revol 	// XXX: load settings
787771c6b93SFrançois Revol 	void *handle;
788ff517f43SFrançois Revol 	char **names = nbd_name;
789637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
790771c6b93SFrançois Revol 
7917f66887bSFrançois Revol 	handle = load_driver_settings(DRV);
7927f66887bSFrançois Revol 	if (handle == NULL)
7937f66887bSFrançois Revol 		return ENOENT;
7947f66887bSFrançois Revol 	// XXX: test for boot args ?
7957f66887bSFrançois Revol 
7967f66887bSFrançois Revol 
797771c6b93SFrançois Revol 	err = ksocket_init();
798771c6b93SFrançois Revol 	if (err < B_OK)
799771c6b93SFrançois Revol 		return err;
800771c6b93SFrançois Revol 
8014d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8027f66887bSFrançois Revol 		nbd_devices[i].valid = false;
8037f66887bSFrançois Revol 		nbd_devices[i].readonly = false;
804*2b07b8e0SIngo Weinhold 		mutex_init(&nbd_devices[i].ben, "nbd lock");
805771c6b93SFrançois Revol 		nbd_devices[i].refcnt = 0;
806771c6b93SFrançois Revol 		nbd_devices[i].req = 0LL; /* next ID for requests */
807771c6b93SFrançois Revol 		nbd_devices[i].sock = -1;
808771c6b93SFrançois Revol 		nbd_devices[i].postoffice = -1;
809771c6b93SFrançois Revol 		nbd_devices[i].size = 0LL;
810771c6b93SFrançois Revol 		nbd_devices[i].reqs = NULL;
8117f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
8127f66887bSFrançois Revol 		nbd_devices[i].kludge = -1;
8137f66887bSFrançois Revol #endif
8144d1cc41eSFrançois Revol 		nbd_name[i] = NULL;
815ff517f43SFrançois Revol 	}
816771c6b93SFrançois Revol 
817771c6b93SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
818ff517f43SFrançois Revol 		const driver_settings *settings = get_driver_settings(handle);
819ff517f43SFrançois Revol 		driver_parameter *p = NULL;
820771c6b93SFrançois Revol 		char keyname[10];
8217f66887bSFrançois Revol 		sprintf(keyname, "%d", i);
8227f66887bSFrançois Revol 		for (j = 0; j < settings->parameter_count; j++)
8237f66887bSFrançois Revol 			if (!strcmp(settings->parameters[j].name, keyname))
8247f66887bSFrançois Revol 				p = &settings->parameters[j];
8257f66887bSFrançois Revol 		if (!p)
8267f66887bSFrançois Revol 			continue;
8277f66887bSFrançois Revol 		for (j = 0; j < p->parameter_count; j++) {
8287f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "readonly"))
8297f66887bSFrançois Revol 				nbd_devices[i].readonly = true;
8307f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "server")) {
8317f66887bSFrançois Revol 				if (p->parameters[j].value_count < 2)
8327f66887bSFrançois Revol 					continue;
833771c6b93SFrançois Revol 				nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in);
834771c6b93SFrançois Revol 				nbd_devices[i].server.sin_family = AF_INET;
8357f66887bSFrançois Revol 				kinet_aton(p->parameters[j].values[0], &nbd_devices[i].server.sin_addr);
8367f66887bSFrançois Revol 				nbd_devices[i].server.sin_port = htons(atoi(p->parameters[j].values[1]));
837ff517f43SFrançois Revol 				dprintf(DP " configured [%d]\n", i);
838ff517f43SFrançois Revol 				*(names) = malloc(DEVICE_NAME_MAX);
839ff517f43SFrançois Revol 				if (*(names) == NULL)
840ff517f43SFrançois Revol 					return ENOMEM;
841ff517f43SFrançois Revol 				sprintf(*(names++), DEVICE_FMT, i);
8427f66887bSFrançois Revol 				nbd_devices[i].valid = true;
843771c6b93SFrançois Revol 			}
8447f66887bSFrançois Revol 		}
8457f66887bSFrançois Revol 	}
846ff517f43SFrançois Revol 	*names = NULL;
847771c6b93SFrançois Revol 
848771c6b93SFrançois Revol 	unload_driver_settings(handle);
8494d1cc41eSFrançois Revol 	return B_OK;
8504d1cc41eSFrançois Revol }
8514d1cc41eSFrançois Revol 
8524d1cc41eSFrançois Revol void
8534d1cc41eSFrançois Revol uninit_driver (void)
8544d1cc41eSFrançois Revol {
855771c6b93SFrançois Revol 	status_t err;
8564d1cc41eSFrançois Revol 	int i;
857637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
8584d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8594d1cc41eSFrançois Revol 		free(nbd_name[i]);
860*2b07b8e0SIngo Weinhold 		mutex_destroy(&nbd_devices[i].ben);
8614d1cc41eSFrançois Revol 	}
862771c6b93SFrançois Revol 	err = ksocket_cleanup();
863637cbfeeSFrançois Revol 	/* HACK */
864637cbfeeSFrançois Revol 	if (gDelayUnload)
865637cbfeeSFrançois Revol 		snooze(BONE_TEARDOWN_DELAY);
8664d1cc41eSFrançois Revol }
8674d1cc41eSFrançois Revol 
8684d1cc41eSFrançois Revol const char**
8694d1cc41eSFrançois Revol publish_devices()
8704d1cc41eSFrançois Revol {
871637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
872ff517f43SFrançois Revol 	return (const char **)nbd_name;
8734d1cc41eSFrançois Revol }
8744d1cc41eSFrançois Revol 
8754d1cc41eSFrançois Revol device_hooks*
8764d1cc41eSFrançois Revol find_device(const char* name)
8774d1cc41eSFrançois Revol {
878637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
8794d1cc41eSFrançois Revol 	return &nbd_hooks;
8804d1cc41eSFrançois Revol }
881e96eef09SFrançois Revol 
882e96eef09SFrançois Revol struct nbd_device*
883e96eef09SFrançois Revol nbd_find_device(const char* name)
884e96eef09SFrançois Revol {
885e96eef09SFrançois Revol 	int i;
886637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
887e96eef09SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
888ff517f43SFrançois Revol 		char buf[DEVICE_NAME_MAX];
889ff517f43SFrançois Revol 		sprintf(buf, DEVICE_FMT, i);
890ff517f43SFrançois Revol 		if (!strcmp(buf, name))
891e96eef09SFrançois Revol 			return &nbd_devices[i];
892e96eef09SFrançois Revol 	}
893e96eef09SFrançois Revol 	return NULL;
894e96eef09SFrançois Revol }
895