xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c (revision eb5f36397841abfc740031fde56ca5e4dee9fdd3)
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 
12*eb5f3639SJerome Duval 
13835ec57dSFrançois Revol #include <ByteOrder.h>
144d1cc41eSFrançois Revol #include <KernelExport.h>
154d1cc41eSFrançois Revol #include <Drivers.h>
16771c6b93SFrançois Revol #include <driver_settings.h>
17835ec57dSFrançois Revol #include <Errors.h>
18835ec57dSFrançois Revol #include <errno.h>
190f609eb2SFrançois Revol #include <stdio.h>
200f609eb2SFrançois Revol #include <stdlib.h>
2111902c74SFrançois Revol #include <string.h>
220f609eb2SFrançois Revol #include <unistd.h>
234d1cc41eSFrançois Revol #include <ksocket.h>
24771c6b93SFrançois Revol #include <netinet/in.h>
25771c6b93SFrançois Revol 
26ec8bd525SFrançois Revol //#define DEBUG 1
27637cbfeeSFrançois Revol 
287f66887bSFrançois Revol /* on the first open(), open ourselves for some seconds,
297f66887bSFrançois Revol  * to avoid trying to reconnect and failing on a 2nd open,
307f66887bSFrançois Revol  * as it happens with the python server.
317f66887bSFrançois Revol  */
327f66887bSFrançois Revol //#define MOUNT_KLUDGE
337f66887bSFrançois Revol 
34835ec57dSFrançois Revol 
35835ec57dSFrançois Revol /* names, ohh names... */
36835ec57dSFrançois Revol #ifndef SHUT_RDWR
37835ec57dSFrançois Revol #define SHUT_RDWR SHUTDOWN_BOTH
38835ec57dSFrançois Revol #endif
39835ec57dSFrançois Revol 
40637cbfeeSFrançois Revol /* locking support */
41771c6b93SFrançois Revol #ifdef __HAIKU__
42771c6b93SFrançois Revol #include <kernel/lock.h>
43771c6b93SFrançois Revol #else
44637cbfeeSFrançois Revol /* wrappers for R5 */
45771c6b93SFrançois Revol #ifndef _IMPEXP_KERNEL
46771c6b93SFrançois Revol #define _IMPEXP_KERNEL
47771c6b93SFrançois Revol #endif
48771c6b93SFrançois Revol #include "lock.h"
492b07b8e0SIngo Weinhold #define mutex lock
502b07b8e0SIngo Weinhold #define mutex_init new_lock
512b07b8e0SIngo Weinhold #define mutex_destroy free_lock
522b07b8e0SIngo Weinhold #define mutex_lock LOCK
532b07b8e0SIngo Weinhold #define mutex_unlock UNLOCK
54771c6b93SFrançois Revol #endif
554d1cc41eSFrançois Revol 
56ec8bd525SFrançois Revol #define DEBUG 1
57ec8bd525SFrançois Revol 
584d1cc41eSFrançois Revol #include "nbd.h"
594d1cc41eSFrançois Revol 
60771c6b93SFrançois Revol #define DRV "nbd"
61637cbfeeSFrançois Revol #define DP "nbd:"
624d1cc41eSFrançois Revol #define MAX_NBDS 4
634d1cc41eSFrançois Revol #define DEVICE_PREFIX "disk/virtual/nbd/"
64637cbfeeSFrançois Revol #define DEVICE_FMT DEVICE_PREFIX "%d/raw"
654d1cc41eSFrançois Revol #define DEVICE_NAME_MAX 32
664d1cc41eSFrançois Revol #define MAX_REQ_SIZE (32*1024*1024)
67a0062874SFrançois Revol #define BLKSIZE 512
684d1cc41eSFrançois Revol 
69637cbfeeSFrançois Revol /* debugging */
70637cbfeeSFrançois Revol #if DEBUG
71637cbfeeSFrançois Revol #define PRINT(a) dprintf a
72637cbfeeSFrançois Revol #define WHICH(dev) ((int)(dev - nbd_devices))
73637cbfeeSFrançois Revol #else
74637cbfeeSFrançois Revol #define PRINT(a)
75637cbfeeSFrançois Revol #endif
76637cbfeeSFrançois Revol 
774d1cc41eSFrançois Revol struct nbd_request_entry {
784d1cc41eSFrançois Revol 	struct nbd_request_entry *next;
793ca76df5SFrançois Revol 	struct nbd_request req; /* net byte order */
803ca76df5SFrançois Revol 	struct nbd_reply reply; /* net byte order */
813ca76df5SFrançois Revol 	sem_id sem;
823ca76df5SFrançois Revol 	bool replied;
833ca76df5SFrançois Revol 	bool discard;
843ca76df5SFrançois Revol 	uint64 handle;
853ca76df5SFrançois Revol 	uint32 type;
863ca76df5SFrançois Revol 	uint64 from;
874d1cc41eSFrançois Revol 	size_t len;
884d1cc41eSFrançois Revol 	void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */
894d1cc41eSFrançois Revol };
904d1cc41eSFrançois Revol 
914d1cc41eSFrançois Revol struct nbd_device {
927f66887bSFrançois Revol 	bool valid;
937f66887bSFrançois Revol 	bool readonly;
94771c6b93SFrançois Revol 	struct sockaddr_in server;
952b07b8e0SIngo Weinhold 	mutex ben;
964d1cc41eSFrançois Revol 	vint32 refcnt;
974d1cc41eSFrançois Revol 	uint64 req; /* next ID for requests */
984d1cc41eSFrançois Revol 	int sock;
994d1cc41eSFrançois Revol 	thread_id postoffice;
1004d1cc41eSFrançois Revol 	uint64 size;
1014d1cc41eSFrançois Revol 	struct nbd_request_entry *reqs;
1027f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
1037f66887bSFrançois Revol 	int kludge;
1047f66887bSFrançois Revol #endif
1054d1cc41eSFrançois Revol };
1064d1cc41eSFrançois Revol 
1074d1cc41eSFrançois Revol typedef struct cookie {
1084d1cc41eSFrançois Revol 	struct nbd_device *dev;
1094d1cc41eSFrançois Revol 
1104d1cc41eSFrançois Revol } cookie_t;
1114d1cc41eSFrançois Revol 
1124d1cc41eSFrançois Revol /* data=NULL on read */
1133ca76df5SFranç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);
1143ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req);
1153ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req);
1163ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req);
1174d1cc41eSFrançois Revol 
118e96eef09SFrançois Revol struct nbd_device *nbd_find_device(const char* name);
119e96eef09SFrançois Revol 
1200f609eb2SFrançois Revol int32 nbd_postoffice(void *arg);
1210f609eb2SFrançois Revol status_t nbd_connect(struct nbd_device *dev);
1220f609eb2SFrançois Revol status_t nbd_teardown(struct nbd_device *dev);
1230f609eb2SFrançois Revol status_t nbd_post_request(struct nbd_device *dev, struct nbd_request_entry *req);
1240f609eb2SFrançois Revol 
1250f609eb2SFrançois Revol status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie);
1260f609eb2SFrançois Revol status_t nbd_close(cookie_t *cookie);
1270f609eb2SFrançois Revol status_t nbd_free(cookie_t *cookie);
1280f609eb2SFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len);
1290f609eb2SFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes);
1300f609eb2SFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes);
1310f609eb2SFrançois Revol 
132771c6b93SFrançois Revol KSOCKET_MODULE_DECL;
133771c6b93SFrançois Revol 
134637cbfeeSFrançois Revol /* HACK:
135637cbfeeSFrançois Revol  * In BONE at least, if connect() fails (EINTR or ETIMEDOUT)
136637cbfeeSFrançois Revol  * keeps locked pages around (likely a bone_data,
137637cbfeeSFrançois Revol  * until TCP gets the last ACK). If that happens, we snooze()
138637cbfeeSFrançois Revol  * in unload_driver() to let TCP timeout before the kernel
139637cbfeeSFrançois Revol  * tries to delete the image. */
140637cbfeeSFrançois Revol bool gDelayUnload = false;
141637cbfeeSFrançois Revol #define BONE_TEARDOWN_DELAY 60000000
142637cbfeeSFrançois Revol 
1430f609eb2SFrançois Revol #if 0
1447f66887bSFrançois Revol #pragma mark ==== support ====
1450f609eb2SFrançois Revol #endif
1467f66887bSFrançois Revol 
1477f66887bSFrançois Revol // move that to ksocket inlined
1487f66887bSFrançois Revol static int kinet_aton(const char *in, struct in_addr *addr)
1497f66887bSFrançois Revol {
1507f66887bSFrançois Revol 	int i;
1517f66887bSFrançois Revol 	unsigned long a;
1527f66887bSFrançois Revol 	uint32 inaddr = 0L;
1530f609eb2SFrançois Revol 	char *p = (char *)in;
1547f66887bSFrançois Revol 	for (i = 0; i < 4; i++) {
1557f66887bSFrançois Revol 		a = strtoul(p, &p, 10);
1567f66887bSFrançois Revol 		if (!p)
1577f66887bSFrançois Revol 			return -1;
1587f66887bSFrançois Revol 		inaddr = (inaddr >> 8) | ((a & 0x0ff) << 24);
1597f66887bSFrançois Revol 		*(uint32 *)addr = inaddr;
1607f66887bSFrançois Revol 		if (!*p)
1617f66887bSFrançois Revol 			return 0;
1627f66887bSFrançois Revol 		p++;
1637f66887bSFrançois Revol 	}
1647f66887bSFrançois Revol 	return 0;
1657f66887bSFrançois Revol }
1667f66887bSFrançois Revol 
1670f609eb2SFrançois Revol #if 0
1684d1cc41eSFrançois Revol #pragma mark ==== request manager ====
1690f609eb2SFrançois Revol #endif
1704d1cc41eSFrançois Revol 
1713ca76df5SFranç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)
1723ca76df5SFrançois Revol {
1733ca76df5SFrançois Revol 	bool w = (type == NBD_CMD_WRITE);
1743ca76df5SFrançois Revol 	struct nbd_request_entry *r;
1753ca76df5SFrançois Revol 	status_t err = EINVAL;
1763ca76df5SFrançois Revol 	uint64 handle;
1773ca76df5SFrançois Revol 	PRINT((DP ">%s(%ld, %Ld, %ld)\n", __FUNCTION__, type, from, len));
1783ca76df5SFrançois Revol 
1793ca76df5SFrançois Revol 	if (type != NBD_CMD_READ && type != NBD_CMD_WRITE && type != NBD_CMD_DISC)
1803ca76df5SFrançois Revol 		return err;
1813ca76df5SFrançois Revol 	if (!dev || !req || from < 0)
1823ca76df5SFrançois Revol 		return err;
1833ca76df5SFrançois Revol 
1843ca76df5SFrançois Revol 	//LOCK
1852b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
1863ca76df5SFrançois Revol 	if (err)
1873ca76df5SFrançois Revol 		return err;
1883ca76df5SFrançois Revol 
1893ca76df5SFrançois Revol 	// atomic
1903ca76df5SFrançois Revol 	handle = dev->req++;
1913ca76df5SFrançois Revol 
1923ca76df5SFrançois Revol 
1933ca76df5SFrançois Revol 	//UNLOCK
1942b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
1953ca76df5SFrançois Revol 
1963ca76df5SFrançois Revol 	err = ENOMEM;
1973ca76df5SFrançois Revol 	r = malloc(sizeof(struct nbd_request_entry) + (w ? 0 : len));
1983ca76df5SFrançois Revol 	if (r == NULL)
1993ca76df5SFrançois Revol 		goto err0;
2003ca76df5SFrançois Revol 	r->next = NULL;
2013ca76df5SFrançois Revol 	err = r->sem = create_sem(0, "nbd request sem");
2023ca76df5SFrançois Revol 	if (err < 0)
2033ca76df5SFrançois Revol 		goto err1;
2043ca76df5SFrançois Revol 
2053ca76df5SFrançois Revol 	r->replied = false;
2063ca76df5SFrançois Revol 	r->discard = false;
2073ca76df5SFrançois Revol 	r->handle = handle;
2083ca76df5SFrançois Revol 	r->type = type;
2093ca76df5SFrançois Revol 	r->from = from;
2103ca76df5SFrançois Revol 	r->len = len;
2113ca76df5SFrançois Revol 
2123ca76df5SFrançois Revol 	r->req.magic = B_HOST_TO_BENDIAN_INT32(NBD_REQUEST_MAGIC);
2133ca76df5SFrançois Revol 	r->req.type = B_HOST_TO_BENDIAN_INT32(type);
2143ca76df5SFrançois Revol 	r->req.handle = B_HOST_TO_BENDIAN_INT64(r->handle);
2153ca76df5SFrançois Revol 	r->req.from = B_HOST_TO_BENDIAN_INT64(r->from);
2163ca76df5SFrançois Revol 	r->req.len = B_HOST_TO_BENDIAN_INT32(len);
2173ca76df5SFrançois Revol 
2180f609eb2SFrançois Revol 	r->buffer = (void *)(w ? data : (((char *)r) + sizeof(struct nbd_request_entry)));
2193ca76df5SFrançois Revol 
2203ca76df5SFrançois Revol 	*req = r;
2213ca76df5SFrançois Revol 	return B_OK;
2223ca76df5SFrançois Revol 
2233ca76df5SFrançois Revol err1:
2243ca76df5SFrançois Revol 	free(r);
2253ca76df5SFrançois Revol err0:
2263ca76df5SFrançois Revol 	dprintf(DP " %s: error 0x%08lx\n", __FUNCTION__, err);
2273ca76df5SFrançois Revol 	return err;
2283ca76df5SFrançois Revol }
2293ca76df5SFrançois Revol 
230*eb5f3639SJerome Duval 
2313ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req)
2323ca76df5SFrançois Revol {
2333ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
2343ca76df5SFrançois Revol 	req->next = dev->reqs;
2353ca76df5SFrançois Revol 	dev->reqs = req;
2363ca76df5SFrançois Revol 	return B_OK;
2373ca76df5SFrançois Revol }
2383ca76df5SFrançois Revol 
239*eb5f3639SJerome Duval 
2403ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req)
2413ca76df5SFrançois Revol {
2423ca76df5SFrançois Revol 	struct nbd_request_entry *r, *prev;
2433ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, handle));
2443ca76df5SFrançois Revol 	r = dev->reqs;
2453ca76df5SFrançois Revol 	prev = NULL;
2463ca76df5SFrançois Revol 	while (r && r->handle != handle) {
2473ca76df5SFrançois Revol 		prev = r;
2483ca76df5SFrançois Revol 		r = r->next;
2493ca76df5SFrançois Revol 	}
2503ca76df5SFrançois Revol 	if (!r)
2513ca76df5SFrançois Revol 		return ENOENT;
2523ca76df5SFrançois Revol 
2533ca76df5SFrançois Revol 	if (prev)
2543ca76df5SFrançois Revol 		prev->next = r->next;
2553ca76df5SFrançois Revol 	else
2563ca76df5SFrançois Revol 		dev->reqs = r->next;
2573ca76df5SFrançois Revol 
2583ca76df5SFrançois Revol 	*req = r;
2593ca76df5SFrançois Revol 	return B_OK;
2603ca76df5SFrançois Revol }
2613ca76df5SFrançois Revol 
262*eb5f3639SJerome Duval 
2633ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req)
2643ca76df5SFrançois Revol {
2653ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
2663ca76df5SFrançois Revol 	delete_sem(req->sem);
2673ca76df5SFrançois Revol 	free(req);
2683ca76df5SFrançois Revol 	return B_OK;
2693ca76df5SFrançois Revol }
2703ca76df5SFrançois Revol 
2713ca76df5SFrançois Revol 
2720f609eb2SFrançois Revol #if 0
2734d1cc41eSFrançois Revol #pragma mark ==== nbd handler ====
2740f609eb2SFrançois Revol #endif
2754d1cc41eSFrançois Revol 
276637cbfeeSFrançois Revol int32 nbd_postoffice(void *arg)
2774d1cc41eSFrançois Revol {
2784d1cc41eSFrançois Revol 	struct nbd_device *dev = (struct nbd_device *)arg;
2793ca76df5SFrançois Revol 	struct nbd_request_entry *req = NULL;
2803ca76df5SFrançois Revol 	struct nbd_reply reply;
2813ca76df5SFrançois Revol 	status_t err;
2823ca76df5SFrançois Revol 	const char *reason;
283637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
2844d1cc41eSFrançois Revol 
2853ca76df5SFrançois Revol 	for (;;) {
2863ca76df5SFrançois Revol 		reason = "recv";
2873ca76df5SFrançois Revol 		err = krecv(dev->sock, &reply, sizeof(reply), 0);
2883ca76df5SFrançois Revol 		if (err == -1 && errno < 0)
2893ca76df5SFrançois Revol 			err = errno;
2903ca76df5SFrançois Revol 		if (err < 0)
2913ca76df5SFrançois Revol 			goto err;
2923ca76df5SFrançois Revol 		reason = "recv:size";
2933ca76df5SFrançois Revol 		if (err < sizeof(reply))
2943ca76df5SFrançois Revol 			err = EINVAL;
2953ca76df5SFrançois Revol 		if (err < 0)
2963ca76df5SFrançois Revol 			goto err;
2973ca76df5SFrançois Revol 		reason = "magic";
2983ca76df5SFrançois Revol 		err = EINVAL;
2993ca76df5SFrançois Revol 		if (B_BENDIAN_TO_HOST_INT32(reply.magic) != NBD_REPLY_MAGIC)
3003ca76df5SFrançois Revol 			goto err;
3014d1cc41eSFrançois Revol 
3023ca76df5SFrançois Revol 		reason = "lock";
3033ca76df5SFrançois Revol 		//LOCK
3042b07b8e0SIngo Weinhold 		err = mutex_lock(&dev->ben);
3053ca76df5SFrançois Revol 		if (err)
3063ca76df5SFrançois Revol 			goto err;
3073ca76df5SFrançois Revol 
3083ca76df5SFrançois Revol 		reason = "dequeue_request";
3093ca76df5SFrançois Revol 		err = nbd_dequeue_request(dev, B_BENDIAN_TO_HOST_INT64(reply.handle), &req);
3103ca76df5SFrançois Revol 
3113ca76df5SFrançois Revol 		//UNLOCK
3122b07b8e0SIngo Weinhold 		mutex_unlock(&dev->ben);
3133ca76df5SFrançois Revol 
3143ca76df5SFrançois Revol 		if (!err && !req) {
3153ca76df5SFrançois Revol 			dprintf(DP "nbd_dequeue_rquest found NULL!\n");
3163ca76df5SFrançois Revol 			err = ENOENT;
3173ca76df5SFrançois Revol 		}
3183ca76df5SFrançois Revol 
3193ca76df5SFrançois Revol 		if (err == B_OK) {
3203ca76df5SFrançois Revol 			memcpy(&req->reply, &reply, sizeof(reply));
3213ca76df5SFrançois Revol 			if (req->type == NBD_CMD_READ) {
3223ca76df5SFrançois Revol 				err = 0;
3233ca76df5SFrançois Revol 				reason = "recv(data)";
3243ca76df5SFrançois Revol 				if (reply.error == 0)
3253ca76df5SFrançois Revol 					err = krecv(dev->sock, req->buffer, req->len, 0);
3263ca76df5SFrançois Revol 				if (err < 0)
3273ca76df5SFrançois Revol 					goto err;
3283ca76df5SFrançois Revol 				/* tell back how much we've got (?) */
3293ca76df5SFrançois Revol 				req->len = err;
3303ca76df5SFrançois Revol 			} else {
3313ca76df5SFrançois Revol 				if (reply.error)
3323ca76df5SFrançois Revol 					req->len = 0;
3333ca76df5SFrançois Revol 			}
3343ca76df5SFrançois Revol 
3353ca76df5SFrançois Revol 			reason = "lock";
3363ca76df5SFrançois Revol 			//LOCK
3372b07b8e0SIngo Weinhold 			err = mutex_lock(&dev->ben);
3383ca76df5SFrançois Revol 			if (err)
3393ca76df5SFrançois Revol 				goto err;
3403ca76df5SFrançois Revol 
3413ca76df5SFrançois Revol 			// this also must be atomic!
3423ca76df5SFrançois Revol 			release_sem(req->sem);
3433ca76df5SFrançois Revol 			req->replied = true;
3443ca76df5SFrançois Revol 			if (req->discard)
3453ca76df5SFrançois Revol 				nbd_free_request(dev, req);
3463ca76df5SFrançois Revol 
3473ca76df5SFrançois Revol 			//UNLOCK
3482b07b8e0SIngo Weinhold 			mutex_unlock(&dev->ben);
3493ca76df5SFrançois Revol 		}
3503ca76df5SFrançois Revol 
3513ca76df5SFrançois Revol 	}
3524d1cc41eSFrançois Revol 
353637cbfeeSFrançois Revol 	PRINT((DP "<%s\n", __FUNCTION__));
3544d1cc41eSFrançois Revol 	return 0;
3553ca76df5SFrançois Revol 
3563ca76df5SFrançois Revol err:
3573ca76df5SFrançois Revol 	dprintf(DP "%s: %s: error 0x%08lx\n", __FUNCTION__, reason, err);
3583ca76df5SFrançois Revol 	return err;
3594d1cc41eSFrançois Revol }
3604d1cc41eSFrançois Revol 
361*eb5f3639SJerome Duval 
362771c6b93SFrançois Revol status_t nbd_connect(struct nbd_device *dev)
363771c6b93SFrançois Revol {
364637cbfeeSFrançois Revol 	struct nbd_init_packet initpkt;
365637cbfeeSFrançois Revol 	status_t err;
366637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
367771c6b93SFrançois Revol 
368637cbfeeSFrançois Revol 	PRINT((DP " %s: socket()\n", __FUNCTION__));
369637cbfeeSFrançois Revol 	err = dev->sock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
370637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
371637cbfeeSFrançois Revol 		err = errno;
372637cbfeeSFrançois Revol 	if (err < 0)
373637cbfeeSFrançois Revol 		goto err0;
374637cbfeeSFrançois Revol 
375637cbfeeSFrançois Revol 	PRINT((DP " %s: connect()\n", __FUNCTION__));
376637cbfeeSFrançois Revol 	err = kconnect(dev->sock, (struct sockaddr *)&dev->server, sizeof(dev->server));
377637cbfeeSFrançois Revol 	//err = ENOSYS;
378637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
379637cbfeeSFrançois Revol 		err = errno;
3800f609eb2SFrançois Revol 	/* HACK: avoid the kernel unloading us with locked pages from TCP */
381637cbfeeSFrançois Revol 	if (err)
382637cbfeeSFrançois Revol 		gDelayUnload = true;
383637cbfeeSFrançois Revol 	if (err)
384637cbfeeSFrançois Revol 		goto err1;
385637cbfeeSFrançois Revol 
386637cbfeeSFrançois Revol 	PRINT((DP " %s: recv(initpkt)\n", __FUNCTION__));
387637cbfeeSFrançois Revol 	err = krecv(dev->sock, &initpkt, sizeof(initpkt), 0);
388637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
389637cbfeeSFrançois Revol 		err = errno;
390637cbfeeSFrançois Revol 	if (err < sizeof(initpkt))
391637cbfeeSFrançois Revol 		goto err2;
392637cbfeeSFrançois Revol 	err = EINVAL;//EPROTO;
393637cbfeeSFrançois Revol 	if (memcmp(initpkt.passwd, NBD_INIT_PASSWD, sizeof(initpkt.passwd)))
394637cbfeeSFrançois Revol 		goto err3;
395637cbfeeSFrançois Revol 	if (B_BENDIAN_TO_HOST_INT64(initpkt.magic) != NBD_INIT_MAGIC)
396637cbfeeSFrançois Revol 		goto err3;
397637cbfeeSFrançois Revol 
398637cbfeeSFrançois Revol 	dev->size = B_BENDIAN_TO_HOST_INT64(initpkt.device_size);
399637cbfeeSFrançois Revol 
400637cbfeeSFrançois Revol 	dprintf(DP " %s: connected, device size %Ld bytes.\n", __FUNCTION__, dev->size);
401637cbfeeSFrançois Revol 
402637cbfeeSFrançois Revol 	err = dev->postoffice = spawn_kernel_thread(nbd_postoffice, "nbd postoffice", B_REAL_TIME_PRIORITY, dev);
403637cbfeeSFrançois Revol 	if (err < B_OK)
404637cbfeeSFrançois Revol 		goto err4;
405637cbfeeSFrançois Revol 	resume_thread(dev->postoffice);
406637cbfeeSFrançois Revol 
407637cbfeeSFrançois Revol 	PRINT((DP "<%s\n", __FUNCTION__));
408771c6b93SFrançois Revol 	return B_OK;
409637cbfeeSFrançois Revol 
410637cbfeeSFrançois Revol err4:
411637cbfeeSFrançois Revol 	dev->postoffice = -1;
412637cbfeeSFrançois Revol err3:
413637cbfeeSFrançois Revol err2:
414637cbfeeSFrançois Revol err1:
415637cbfeeSFrançois Revol 	kclosesocket(dev->sock);
416637cbfeeSFrançois Revol 	dev->sock = -1;
417637cbfeeSFrançois Revol err0:
418637cbfeeSFrançois Revol 	dprintf(DP "<%s: error 0x%08lx\n", __FUNCTION__, err);
419637cbfeeSFrançois Revol 	return err;
420771c6b93SFrançois Revol }
421771c6b93SFrançois Revol 
422*eb5f3639SJerome Duval 
423771c6b93SFrançois Revol status_t nbd_teardown(struct nbd_device *dev)
424771c6b93SFrançois Revol {
425*eb5f3639SJerome Duval 	status_t ret;
426637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
427835ec57dSFrançois Revol 	kshutdown(dev->sock, SHUT_RDWR);
428637cbfeeSFrançois Revol 	kclosesocket(dev->sock);
429637cbfeeSFrançois Revol 	dev->sock = -1;
430*eb5f3639SJerome Duval 	wait_for_thread(dev->postoffice, &ret);
431771c6b93SFrançois Revol 	return B_OK;
432771c6b93SFrançois Revol }
433771c6b93SFrançois Revol 
434*eb5f3639SJerome Duval 
4353ca76df5SFrançois Revol status_t nbd_post_request(struct nbd_device *dev, struct nbd_request_entry *req)
4363ca76df5SFrançois Revol {
4373ca76df5SFrançois Revol 	status_t err;
4383ca76df5SFrançois Revol 	PRINT((DP ">%s(handle:%Ld)\n", __FUNCTION__, req->handle));
4393ca76df5SFrançois Revol 
4403ca76df5SFrançois Revol 	err = ksend(dev->sock, &req->req, sizeof(req->req), 0);
4413ca76df5SFrançois Revol 	if (err < 0)
4423ca76df5SFrançois Revol 		return err;
4433ca76df5SFrançois Revol 
444ff517f43SFrançois Revol 	if (req->type == NBD_CMD_WRITE)
445ff517f43SFrançois Revol 		err = ksend(dev->sock, req->buffer, req->len, 0);
446ff517f43SFrançois Revol 	if (err < 0)
447ff517f43SFrançois Revol 		return err;
448ff517f43SFrançois Revol 	else
449ff517f43SFrançois Revol 		req->len = err;
450ff517f43SFrançois Revol 
4513ca76df5SFrançois Revol 	err = nbd_queue_request(dev, req);
4523ca76df5SFrançois Revol 	return err;
4533ca76df5SFrançois Revol }
4543ca76df5SFrançois Revol 
4553ca76df5SFrançois Revol 
4560f609eb2SFrançois Revol #if 0
4574d1cc41eSFrançois Revol #pragma mark ==== device hooks ====
4580f609eb2SFrançois Revol #endif
4594d1cc41eSFrançois Revol 
460e96eef09SFrançois Revol static struct nbd_device nbd_devices[MAX_NBDS];
461e96eef09SFrançois Revol 
4624d1cc41eSFrançois Revol status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie) {
463771c6b93SFrançois Revol 	status_t err;
4647f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
465*eb5f3639SJerome Duval 	int32 refcnt;
4667f66887bSFrançois Revol 	int kfd;
4677f66887bSFrançois Revol #endif
468e96eef09SFrançois Revol 	struct nbd_device *dev = NULL;
4690f609eb2SFrançois Revol 	PRINT((DP ">%s(%s, %lx, )\n", __FUNCTION__, name, flags));
4704d1cc41eSFrançois Revol 	(void)name; (void)flags;
471e96eef09SFrançois Revol 	dev = nbd_find_device(name);
4727f66887bSFrançois Revol 	if (!dev || !dev->valid)
473e96eef09SFrançois Revol 		return ENOENT;
474771c6b93SFrançois Revol 	err = ENOMEM;
4754d1cc41eSFrançois Revol 	*cookie = (void*)malloc(sizeof(cookie_t));
476771c6b93SFrançois Revol 	if (*cookie == NULL)
4774d1cc41eSFrançois Revol 		goto err0;
4784d1cc41eSFrançois Revol 	memset(*cookie, 0, sizeof(cookie_t));
479e96eef09SFrançois Revol 	(*cookie)->dev = dev;
4802b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
481771c6b93SFrançois Revol 	if (err)
482771c6b93SFrançois Revol 		goto err1;
483771c6b93SFrançois Revol 	/*  */
484771c6b93SFrançois Revol 	if (dev->sock < 0)
485771c6b93SFrançois Revol 		err = nbd_connect(dev);
486771c6b93SFrançois Revol 	if (err)
487771c6b93SFrançois Revol 		goto err2;
4887f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
489*eb5f3639SJerome Duval 	refcnt = dev->refcnt++;
4907f66887bSFrançois Revol 	kfd = dev->kludge;
4917f66887bSFrançois Revol 	dev->kludge = -1;
4927f66887bSFrançois Revol #endif
4932b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
4947f66887bSFrançois Revol 
4957f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
4967f66887bSFrançois Revol 	if (refcnt == 0) {
4977f66887bSFrançois Revol 		char buf[32];
4987f66887bSFrançois Revol 		sprintf(buf, "/dev/%s", name);
4997f66887bSFrançois Revol 		dev->kludge = open(buf, O_RDONLY);
5007f66887bSFrançois Revol 	} else if (kfd) {
5017f66887bSFrançois Revol 		close(kfd);
5027f66887bSFrançois Revol 	}
5037f66887bSFrançois Revol #endif
5047f66887bSFrançois Revol 
5054d1cc41eSFrançois Revol 	return B_OK;
506771c6b93SFrançois Revol 
507771c6b93SFrançois Revol err2:
5082b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
509771c6b93SFrançois Revol err1:
510771c6b93SFrançois Revol 	free(*cookie);
5114d1cc41eSFrançois Revol err0:
512637cbfeeSFrançois Revol 	dprintf(DP " %s: error 0x%08lx\n", __FUNCTION__, err);
513771c6b93SFrançois Revol 	return err;
5144d1cc41eSFrançois Revol }
5154d1cc41eSFrançois Revol 
516*eb5f3639SJerome Duval 
517771c6b93SFrançois Revol status_t nbd_close(cookie_t *cookie) {
518771c6b93SFrançois Revol 	struct nbd_device *dev = cookie->dev;
519771c6b93SFrançois Revol 	status_t err;
5207f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5217f66887bSFrançois Revol 	int kfd = -1;
5227f66887bSFrançois Revol #endif
523637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev)));
524771c6b93SFrançois Revol 
5252b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
526771c6b93SFrançois Revol 	if (err)
527771c6b93SFrançois Revol 		return err;
528771c6b93SFrançois Revol 
529771c6b93SFrançois Revol 	// XXX: do something ?
5307f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5317f66887bSFrançois Revol 	kfd = dev->kludge;
5327f66887bSFrançois Revol 	dev->kludge = -1;
5337f66887bSFrançois Revol #endif
534771c6b93SFrançois Revol 
5352b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
5367f66887bSFrançois Revol 
5377f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
5387f66887bSFrançois Revol 	if (kfd > -1) {
5397f66887bSFrançois Revol 		close(kfd);
5407f66887bSFrançois Revol 	}
5417f66887bSFrançois Revol #endif
5424d1cc41eSFrançois Revol 	return B_OK;
5434d1cc41eSFrançois Revol }
5444d1cc41eSFrançois Revol 
545*eb5f3639SJerome Duval 
5464d1cc41eSFrançois Revol status_t nbd_free(cookie_t *cookie) {
547771c6b93SFrançois Revol 	struct nbd_device *dev = cookie->dev;
548771c6b93SFrançois Revol 	status_t err;
549637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev)));
550771c6b93SFrançois Revol 
5512b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
552771c6b93SFrançois Revol 	if (err)
553771c6b93SFrançois Revol 		return err;
554771c6b93SFrançois Revol 
555771c6b93SFrançois Revol 	if (--dev->refcnt == 0) {
556771c6b93SFrançois Revol 		err = nbd_teardown(dev);
557771c6b93SFrançois Revol 	}
558771c6b93SFrançois Revol 
5592b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
560771c6b93SFrançois Revol 
5614d1cc41eSFrançois Revol 	free(cookie);
562771c6b93SFrançois Revol 	return err;
5634d1cc41eSFrançois Revol }
5644d1cc41eSFrançois Revol 
565*eb5f3639SJerome Duval 
5664d1cc41eSFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) {
5670f609eb2SFrançois Revol 	PRINT((DP ">%s(%d, %lu, , %ld)\n", __FUNCTION__, WHICH(cookie->dev), op, len));
5684d1cc41eSFrançois Revol 	switch (op) {
5694d1cc41eSFrançois Revol 	case B_GET_DEVICE_SIZE: /* this one is broken anyway... */
5704d1cc41eSFrançois Revol 		if (data) {
5714d1cc41eSFrançois Revol 			*(size_t *)data = (size_t)cookie->dev->size;
5724d1cc41eSFrançois Revol 			return B_OK;
5734d1cc41eSFrançois Revol 		}
5744d1cc41eSFrançois Revol 		return EINVAL;
5754d1cc41eSFrançois Revol 	case B_SET_DEVICE_SIZE: /* broken */
5764d1cc41eSFrançois Revol 		return EINVAL;
5774d1cc41eSFrançois Revol 	case B_SET_NONBLOCKING_IO:
5784d1cc41eSFrançois Revol 		return EINVAL;
5794d1cc41eSFrançois Revol 	case B_SET_BLOCKING_IO:
5804d1cc41eSFrançois Revol 		return B_OK;
5814d1cc41eSFrançois Revol 	case B_GET_READ_STATUS:
5824d1cc41eSFrançois Revol 	case B_GET_WRITE_STATUS:
5834d1cc41eSFrançois Revol 		if (data) {
5844d1cc41eSFrançois Revol 			*(bool *)data = false;
5854d1cc41eSFrançois Revol 			return B_OK;
5864d1cc41eSFrançois Revol 		}
5874d1cc41eSFrançois Revol 		return EINVAL;
5884d1cc41eSFrançois Revol 	case B_GET_GEOMETRY:
5894d1cc41eSFrançois Revol 	case B_GET_BIOS_GEOMETRY:
5904d1cc41eSFrançois Revol 		if (data) {
5914d1cc41eSFrançois Revol 			device_geometry *geom = (device_geometry *)data;
592a0062874SFrançois Revol 			geom->bytes_per_sector = BLKSIZE;
5934d1cc41eSFrançois Revol 			geom->sectors_per_track = 1;
594a0062874SFrançois Revol 			geom->cylinder_count = cookie->dev->size / BLKSIZE;
5954d1cc41eSFrançois Revol 			geom->head_count = 1;
5964d1cc41eSFrançois Revol 			geom->device_type = B_DISK;
5974d1cc41eSFrançois Revol 			geom->removable = false;
598ff517f43SFrançois Revol 			geom->read_only = cookie->dev->readonly;
5994d1cc41eSFrançois Revol 			geom->write_once = false;
6004d1cc41eSFrançois Revol 			return B_OK;
6014d1cc41eSFrançois Revol 		}
6024d1cc41eSFrançois Revol 		return EINVAL;
6034d1cc41eSFrançois Revol 	case B_GET_MEDIA_STATUS:
6044d1cc41eSFrançois Revol 		if (data) {
6054d1cc41eSFrançois Revol 			*(status_t *)data = B_OK;
6064d1cc41eSFrançois Revol 			return B_OK;
6074d1cc41eSFrançois Revol 		}
6084d1cc41eSFrançois Revol 		return EINVAL;
6094d1cc41eSFrançois Revol 
6104d1cc41eSFrançois Revol 	case B_EJECT_DEVICE:
6114d1cc41eSFrançois Revol 	case B_LOAD_MEDIA:
612a0062874SFrançois Revol 		return B_BAD_VALUE;
6134d1cc41eSFrançois Revol 	case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */
614a0062874SFrançois Revol 		return B_OK;
6154d1cc41eSFrançois Revol 	default:
616a0062874SFrançois Revol 		return B_BAD_VALUE;
6174d1cc41eSFrançois Revol 	}
6184d1cc41eSFrançois Revol 	return B_NOT_ALLOWED;
6194d1cc41eSFrançois Revol }
6204d1cc41eSFrançois Revol 
621*eb5f3639SJerome Duval 
6224d1cc41eSFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) {
6233ca76df5SFrançois Revol 	struct nbd_device *dev = cookie->dev;
6243ca76df5SFrançois Revol 	struct nbd_request_entry *req;
6253ca76df5SFrançois Revol 	status_t err, semerr;
626637cbfeeSFrançois Revol 	PRINT((DP ">%s(%d, %Ld, , )\n", __FUNCTION__, WHICH(cookie->dev), position));
6273ca76df5SFrançois Revol 
6283ca76df5SFrançois Revol 	if (position < 0)
6293ca76df5SFrançois Revol 		return EINVAL;
6303ca76df5SFrançois Revol 	if (!data)
6313ca76df5SFrançois Revol 		return EINVAL;
6323ca76df5SFrançois Revol 
6333ca76df5SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_READ, position, *numbytes, NULL);
6343ca76df5SFrançois Revol 	if (err)
6353ca76df5SFrançois Revol 		goto err0;
6363ca76df5SFrançois Revol 
6373ca76df5SFrançois Revol 	//LOCK
6382b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6393ca76df5SFrançois Revol 	if (err)
6403ca76df5SFrançois Revol 		goto err1;
6413ca76df5SFrançois Revol 
6423ca76df5SFrançois Revol 	err = nbd_post_request(dev, req);
6433ca76df5SFrançois Revol 
6443ca76df5SFrançois Revol 	//UNLOCK
6452b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6463ca76df5SFrançois Revol 
6473ca76df5SFrançois Revol 	if (err)
6483ca76df5SFrançois Revol 		goto err2;
6493ca76df5SFrançois Revol 
6503ca76df5SFrançois Revol 
6513ca76df5SFrançois Revol 	semerr = acquire_sem(req->sem);
6523ca76df5SFrançois Revol 
6533ca76df5SFrançois Revol 	//LOCK
6542b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6553ca76df5SFrançois Revol 	if(err)
6563ca76df5SFrançois Revol 		goto err3;
6573ca76df5SFrançois Revol 
6583ca76df5SFrançois Revol 	/* bad scenarii */
6593ca76df5SFrançois Revol 	if (!req->replied)
6603ca76df5SFrançois Revol 		req->discard = true;
6613ca76df5SFrançois Revol 	else if (semerr)
6623ca76df5SFrançois Revol 		nbd_free_request(dev, req);
6633ca76df5SFrançois Revol 
6643ca76df5SFrançois Revol 	//UNLOCK
6652b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6663ca76df5SFrançois Revol 
6673ca76df5SFrançois Revol 	if (semerr == B_OK) {
6683ca76df5SFrançois Revol 		*numbytes = req->len;
6693ca76df5SFrançois Revol 		memcpy(data, req->buffer, req->len);
670ff517f43SFrançois Revol 		err = B_OK;
6713ca76df5SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
672ff517f43SFrançois Revol 			err = EIO;
673ff517f43SFrançois Revol 		nbd_free_request(dev, req);
674ff517f43SFrançois Revol 		return err;
6753ca76df5SFrançois Revol 	}
6763ca76df5SFrançois Revol 
6774d1cc41eSFrançois Revol 	*numbytes = 0;
6783ca76df5SFrançois Revol 	return semerr;
6793ca76df5SFrançois Revol 
6803ca76df5SFrançois Revol 
6813ca76df5SFrançois Revol err3:
6823ca76df5SFrançois Revol err2:
6833ca76df5SFrançois Revol err1:
6843ca76df5SFrançois Revol 	nbd_free_request(dev, req);
6853ca76df5SFrançois Revol err0:
6863ca76df5SFrançois Revol 	*numbytes = 0;
6873ca76df5SFrançois Revol 	return err;
6884d1cc41eSFrançois Revol }
6894d1cc41eSFrançois Revol 
690*eb5f3639SJerome Duval 
6914d1cc41eSFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) {
692ff517f43SFrançois Revol 	struct nbd_device *dev = cookie->dev;
693ff517f43SFrançois Revol 	struct nbd_request_entry *req;
694ff517f43SFrançois Revol 	status_t err, semerr;
695ff517f43SFrançois Revol 	PRINT((DP ">%s(%d, %Ld, %ld, )\n", __FUNCTION__, WHICH(cookie->dev), position, *numbytes));
696ff517f43SFrançois Revol 
697ff517f43SFrançois Revol 	if (position < 0)
698ff517f43SFrançois Revol 		return EINVAL;
699ff517f43SFrançois Revol 	if (!data)
700ff517f43SFrançois Revol 		return EINVAL;
701ff517f43SFrançois Revol 	err = B_NOT_ALLOWED;
702ff517f43SFrançois Revol 	if (dev->readonly)
703ff517f43SFrançois Revol 		goto err0;
704ff517f43SFrançois Revol 
705ff517f43SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_WRITE, position, *numbytes, data);
706ff517f43SFrançois Revol 	if (err)
707ff517f43SFrançois Revol 		goto err0;
708ff517f43SFrançois Revol 
709ff517f43SFrançois Revol 	//LOCK
7102b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
711ff517f43SFrançois Revol 	if (err)
712ff517f43SFrançois Revol 		goto err1;
713ff517f43SFrançois Revol 
714ff517f43SFrançois Revol 	/* sending request+data must be atomic */
715ff517f43SFrançois Revol 	err = nbd_post_request(dev, req);
716ff517f43SFrançois Revol 
717ff517f43SFrançois Revol 	//UNLOCK
7182b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
719ff517f43SFrançois Revol 
720ff517f43SFrançois Revol 	if (err)
721ff517f43SFrançois Revol 		goto err2;
722ff517f43SFrançois Revol 
723ff517f43SFrançois Revol 
724ff517f43SFrançois Revol 	semerr = acquire_sem(req->sem);
725ff517f43SFrançois Revol 
726ff517f43SFrançois Revol 	//LOCK
7272b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
728ff517f43SFrançois Revol 	if(err)
729ff517f43SFrançois Revol 		goto err3;
730ff517f43SFrançois Revol 
731ff517f43SFrançois Revol 	/* bad scenarii */
732ff517f43SFrançois Revol 	if (!req->replied)
733ff517f43SFrançois Revol 		req->discard = true;
734ff517f43SFrançois Revol 	else if (semerr)
735ff517f43SFrançois Revol 		nbd_free_request(dev, req);
736ff517f43SFrançois Revol 
737ff517f43SFrançois Revol 	//UNLOCK
7382b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
739ff517f43SFrançois Revol 
740ff517f43SFrançois Revol 	if (semerr == B_OK) {
741ff517f43SFrançois Revol 		*numbytes = req->len;
742ff517f43SFrançois Revol 		err = B_OK;
743ff517f43SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
744ff517f43SFrançois Revol 			err = EIO;
745ff517f43SFrançois Revol 		nbd_free_request(dev, req);
746ff517f43SFrançois Revol 		return err;
747ff517f43SFrançois Revol 	}
748ff517f43SFrançois Revol 
7494d1cc41eSFrançois Revol 	*numbytes = 0;
750ff517f43SFrançois Revol 	return semerr;
751ff517f43SFrançois Revol 
752ff517f43SFrançois Revol 
753ff517f43SFrançois Revol err3:
754ff517f43SFrançois Revol err2:
755ff517f43SFrançois Revol err1:
756ff517f43SFrançois Revol 	nbd_free_request(dev, req);
757ff517f43SFrançois Revol err0:
758ff517f43SFrançois Revol 	*numbytes = 0;
759ff517f43SFrançois Revol 	return err;
7604d1cc41eSFrançois Revol }
7614d1cc41eSFrançois Revol 
762*eb5f3639SJerome Duval 
7634d1cc41eSFrançois Revol device_hooks nbd_hooks={
7644d1cc41eSFrançois Revol 	(device_open_hook)nbd_open,
765ff517f43SFrançois Revol 	(device_close_hook)nbd_close,
7664d1cc41eSFrançois Revol 	(device_free_hook)nbd_free,
7674d1cc41eSFrançois Revol 	(device_control_hook)nbd_control,
7684d1cc41eSFrançois Revol 	(device_read_hook)nbd_read,
7694d1cc41eSFrançois Revol 	(device_write_hook)nbd_write,
7704d1cc41eSFrançois Revol 	NULL,
7714d1cc41eSFrançois Revol 	NULL,
7724d1cc41eSFrançois Revol 	NULL,
7734d1cc41eSFrançois Revol 	NULL
7744d1cc41eSFrançois Revol };
7754d1cc41eSFrançois Revol 
7760f609eb2SFrançois Revol #if 0
7774d1cc41eSFrançois Revol #pragma mark ==== driver hooks ====
7780f609eb2SFrançois Revol #endif
7794d1cc41eSFrançois Revol 
780ec8bd525SFrançois Revol int32 api_version = B_CUR_DRIVER_API_VERSION;
781ec8bd525SFrançois Revol 
782ff517f43SFrançois Revol static char *nbd_name[MAX_NBDS+1] = {
7834d1cc41eSFrançois Revol 	NULL
7844d1cc41eSFrançois Revol };
7854d1cc41eSFrançois Revol 
786*eb5f3639SJerome Duval 
7874d1cc41eSFrançois Revol status_t
7884d1cc41eSFrançois Revol init_hardware (void)
7894d1cc41eSFrançois Revol {
790637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
7914d1cc41eSFrançois Revol 	return B_OK;
7924d1cc41eSFrançois Revol }
7934d1cc41eSFrançois Revol 
794*eb5f3639SJerome Duval 
7954d1cc41eSFrançois Revol status_t
7964d1cc41eSFrançois Revol init_driver (void)
7974d1cc41eSFrançois Revol {
798771c6b93SFrançois Revol 	status_t err;
799771c6b93SFrançois Revol 	int i, j;
800771c6b93SFrançois Revol 	// XXX: load settings
801771c6b93SFrançois Revol 	void *handle;
802ff517f43SFrançois Revol 	char **names = nbd_name;
803637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
804771c6b93SFrançois Revol 
8057f66887bSFrançois Revol 	handle = load_driver_settings(DRV);
8067f66887bSFrançois Revol 	if (handle == NULL)
8077f66887bSFrançois Revol 		return ENOENT;
8087f66887bSFrançois Revol 	// XXX: test for boot args ?
8097f66887bSFrançois Revol 
8107f66887bSFrançois Revol 
811771c6b93SFrançois Revol 	err = ksocket_init();
812771c6b93SFrançois Revol 	if (err < B_OK)
813771c6b93SFrançois Revol 		return err;
814771c6b93SFrançois Revol 
8154d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8167f66887bSFrançois Revol 		nbd_devices[i].valid = false;
8177f66887bSFrançois Revol 		nbd_devices[i].readonly = false;
8182b07b8e0SIngo Weinhold 		mutex_init(&nbd_devices[i].ben, "nbd lock");
819771c6b93SFrançois Revol 		nbd_devices[i].refcnt = 0;
820771c6b93SFrançois Revol 		nbd_devices[i].req = 0LL; /* next ID for requests */
821771c6b93SFrançois Revol 		nbd_devices[i].sock = -1;
822771c6b93SFrançois Revol 		nbd_devices[i].postoffice = -1;
823771c6b93SFrançois Revol 		nbd_devices[i].size = 0LL;
824771c6b93SFrançois Revol 		nbd_devices[i].reqs = NULL;
8257f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
8267f66887bSFrançois Revol 		nbd_devices[i].kludge = -1;
8277f66887bSFrançois Revol #endif
8284d1cc41eSFrançois Revol 		nbd_name[i] = NULL;
829ff517f43SFrançois Revol 	}
830771c6b93SFrançois Revol 
831771c6b93SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
832ff517f43SFrançois Revol 		const driver_settings *settings = get_driver_settings(handle);
833ff517f43SFrançois Revol 		driver_parameter *p = NULL;
834771c6b93SFrançois Revol 		char keyname[10];
8357f66887bSFrançois Revol 		sprintf(keyname, "%d", i);
8367f66887bSFrançois Revol 		for (j = 0; j < settings->parameter_count; j++)
8377f66887bSFrançois Revol 			if (!strcmp(settings->parameters[j].name, keyname))
8387f66887bSFrançois Revol 				p = &settings->parameters[j];
8397f66887bSFrançois Revol 		if (!p)
8407f66887bSFrançois Revol 			continue;
8417f66887bSFrançois Revol 		for (j = 0; j < p->parameter_count; j++) {
8427f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "readonly"))
8437f66887bSFrançois Revol 				nbd_devices[i].readonly = true;
8447f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "server")) {
8457f66887bSFrançois Revol 				if (p->parameters[j].value_count < 2)
8467f66887bSFrançois Revol 					continue;
847771c6b93SFrançois Revol 				nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in);
848771c6b93SFrançois Revol 				nbd_devices[i].server.sin_family = AF_INET;
8497f66887bSFrançois Revol 				kinet_aton(p->parameters[j].values[0], &nbd_devices[i].server.sin_addr);
8507f66887bSFrançois Revol 				nbd_devices[i].server.sin_port = htons(atoi(p->parameters[j].values[1]));
851ff517f43SFrançois Revol 				dprintf(DP " configured [%d]\n", i);
852ff517f43SFrançois Revol 				*(names) = malloc(DEVICE_NAME_MAX);
853ff517f43SFrançois Revol 				if (*(names) == NULL)
854ff517f43SFrançois Revol 					return ENOMEM;
855ff517f43SFrançois Revol 				sprintf(*(names++), DEVICE_FMT, i);
8567f66887bSFrançois Revol 				nbd_devices[i].valid = true;
857771c6b93SFrançois Revol 			}
8587f66887bSFrançois Revol 		}
8597f66887bSFrançois Revol 	}
860ff517f43SFrançois Revol 	*names = NULL;
861771c6b93SFrançois Revol 
862771c6b93SFrançois Revol 	unload_driver_settings(handle);
8634d1cc41eSFrançois Revol 	return B_OK;
8644d1cc41eSFrançois Revol }
8654d1cc41eSFrançois Revol 
866*eb5f3639SJerome Duval 
8674d1cc41eSFrançois Revol void
8684d1cc41eSFrançois Revol uninit_driver (void)
8694d1cc41eSFrançois Revol {
8704d1cc41eSFrançois Revol 	int i;
871637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
8724d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8734d1cc41eSFrançois Revol 		free(nbd_name[i]);
8742b07b8e0SIngo Weinhold 		mutex_destroy(&nbd_devices[i].ben);
8754d1cc41eSFrançois Revol 	}
876*eb5f3639SJerome Duval 	ksocket_cleanup();
877637cbfeeSFrançois Revol 	/* HACK */
878637cbfeeSFrançois Revol 	if (gDelayUnload)
879637cbfeeSFrançois Revol 		snooze(BONE_TEARDOWN_DELAY);
8804d1cc41eSFrançois Revol }
8814d1cc41eSFrançois Revol 
882*eb5f3639SJerome Duval 
8834d1cc41eSFrançois Revol const char**
8844d1cc41eSFrançois Revol publish_devices()
8854d1cc41eSFrançois Revol {
886637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
887ff517f43SFrançois Revol 	return (const char **)nbd_name;
8884d1cc41eSFrançois Revol }
8894d1cc41eSFrançois Revol 
890*eb5f3639SJerome Duval 
8914d1cc41eSFrançois Revol device_hooks*
8924d1cc41eSFrançois Revol find_device(const char* name)
8934d1cc41eSFrançois Revol {
894637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
8954d1cc41eSFrançois Revol 	return &nbd_hooks;
8964d1cc41eSFrançois Revol }
897e96eef09SFrançois Revol 
898*eb5f3639SJerome Duval 
899e96eef09SFrançois Revol struct nbd_device*
900e96eef09SFrançois Revol nbd_find_device(const char* name)
901e96eef09SFrançois Revol {
902e96eef09SFrançois Revol 	int i;
903637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
904e96eef09SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
905ff517f43SFrançois Revol 		char buf[DEVICE_NAME_MAX];
906ff517f43SFrançois Revol 		sprintf(buf, DEVICE_FMT, i);
907ff517f43SFrançois Revol 		if (!strcmp(buf, name))
908e96eef09SFrançois Revol 			return &nbd_devices[i];
909e96eef09SFrançois Revol 	}
910e96eef09SFrançois Revol 	return NULL;
911e96eef09SFrançois Revol }
912*eb5f3639SJerome Duval 
913