xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
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 
12eb5f3639SJerome 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 
564d1cc41eSFrançois Revol #include "nbd.h"
574d1cc41eSFrançois Revol 
58771c6b93SFrançois Revol #define DRV "nbd"
59637cbfeeSFrançois Revol #define DP "nbd:"
604d1cc41eSFrançois Revol #define MAX_NBDS 4
614d1cc41eSFrançois Revol #define DEVICE_PREFIX "disk/virtual/nbd/"
62637cbfeeSFrançois Revol #define DEVICE_FMT DEVICE_PREFIX "%d/raw"
634d1cc41eSFrançois Revol #define DEVICE_NAME_MAX 32
644d1cc41eSFrançois Revol #define MAX_REQ_SIZE (32*1024*1024)
65a0062874SFrançois Revol #define BLKSIZE 512
664d1cc41eSFrançois Revol 
67637cbfeeSFrançois Revol /* debugging */
68637cbfeeSFrançois Revol #if DEBUG
69637cbfeeSFrançois Revol #define PRINT(a) dprintf a
70637cbfeeSFrançois Revol #define WHICH(dev) ((int)(dev - nbd_devices))
71637cbfeeSFrançois Revol #else
72637cbfeeSFrançois Revol #define PRINT(a)
73637cbfeeSFrançois Revol #endif
74637cbfeeSFrançois Revol 
754d1cc41eSFrançois Revol struct nbd_request_entry {
764d1cc41eSFrançois Revol 	struct nbd_request_entry *next;
773ca76df5SFrançois Revol 	struct nbd_request req; /* net byte order */
783ca76df5SFrançois Revol 	struct nbd_reply reply; /* net byte order */
793ca76df5SFrançois Revol 	sem_id sem;
803ca76df5SFrançois Revol 	bool replied;
813ca76df5SFrançois Revol 	bool discard;
823ca76df5SFrançois Revol 	uint64 handle;
833ca76df5SFrançois Revol 	uint32 type;
843ca76df5SFrançois Revol 	uint64 from;
854d1cc41eSFrançois Revol 	size_t len;
864d1cc41eSFrançois Revol 	void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */
874d1cc41eSFrançois Revol };
884d1cc41eSFrançois Revol 
894d1cc41eSFrançois Revol struct nbd_device {
907f66887bSFrançois Revol 	bool valid;
917f66887bSFrançois Revol 	bool readonly;
92771c6b93SFrançois Revol 	struct sockaddr_in server;
932b07b8e0SIngo Weinhold 	mutex ben;
944d1cc41eSFrançois Revol 	vint32 refcnt;
954d1cc41eSFrançois Revol 	uint64 req; /* next ID for requests */
964d1cc41eSFrançois Revol 	int sock;
974d1cc41eSFrançois Revol 	thread_id postoffice;
984d1cc41eSFrançois Revol 	uint64 size;
994d1cc41eSFrançois Revol 	struct nbd_request_entry *reqs;
1007f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
1017f66887bSFrançois Revol 	int kludge;
1027f66887bSFrançois Revol #endif
1034d1cc41eSFrançois Revol };
1044d1cc41eSFrançois Revol 
1054d1cc41eSFrançois Revol typedef struct cookie {
1064d1cc41eSFrançois Revol 	struct nbd_device *dev;
1074d1cc41eSFrançois Revol 
1084d1cc41eSFrançois Revol } cookie_t;
1094d1cc41eSFrançois Revol 
1104d1cc41eSFrançois Revol /* data=NULL on read */
1113ca76df5SFranç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);
1123ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req);
1133ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req);
1143ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req);
1154d1cc41eSFrançois Revol 
116e96eef09SFrançois Revol struct nbd_device *nbd_find_device(const char* name);
117e96eef09SFrançois Revol 
1180f609eb2SFrançois Revol int32 nbd_postoffice(void *arg);
1190f609eb2SFrançois Revol status_t nbd_connect(struct nbd_device *dev);
1200f609eb2SFrançois Revol status_t nbd_teardown(struct nbd_device *dev);
1210f609eb2SFrançois Revol status_t nbd_post_request(struct nbd_device *dev, struct nbd_request_entry *req);
1220f609eb2SFrançois Revol 
1230f609eb2SFrançois Revol status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie);
1240f609eb2SFrançois Revol status_t nbd_close(cookie_t *cookie);
1250f609eb2SFrançois Revol status_t nbd_free(cookie_t *cookie);
1260f609eb2SFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len);
1270f609eb2SFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes);
1280f609eb2SFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes);
1290f609eb2SFrançois Revol 
130771c6b93SFrançois Revol KSOCKET_MODULE_DECL;
131771c6b93SFrançois Revol 
132637cbfeeSFrançois Revol /* HACK:
133637cbfeeSFrançois Revol  * In BONE at least, if connect() fails (EINTR or ETIMEDOUT)
134637cbfeeSFrançois Revol  * keeps locked pages around (likely a bone_data,
135637cbfeeSFrançois Revol  * until TCP gets the last ACK). If that happens, we snooze()
136637cbfeeSFrançois Revol  * in unload_driver() to let TCP timeout before the kernel
137637cbfeeSFrançois Revol  * tries to delete the image. */
138637cbfeeSFrançois Revol bool gDelayUnload = false;
139637cbfeeSFrançois Revol #define BONE_TEARDOWN_DELAY 60000000
140637cbfeeSFrançois Revol 
1410f609eb2SFrançois Revol #if 0
1427f66887bSFrançois Revol #pragma mark ==== support ====
1430f609eb2SFrançois Revol #endif
1447f66887bSFrançois Revol 
1457f66887bSFrançois Revol // move that to ksocket inlined
kinet_aton(const char * in,struct in_addr * addr)1467f66887bSFrançois Revol static int kinet_aton(const char *in, struct in_addr *addr)
1477f66887bSFrançois Revol {
1487f66887bSFrançois Revol 	int i;
1497f66887bSFrançois Revol 	unsigned long a;
1507f66887bSFrançois Revol 	uint32 inaddr = 0L;
1510f609eb2SFrançois Revol 	char *p = (char *)in;
1527f66887bSFrançois Revol 	for (i = 0; i < 4; i++) {
1537f66887bSFrançois Revol 		a = strtoul(p, &p, 10);
1547f66887bSFrançois Revol 		if (!p)
1557f66887bSFrançois Revol 			return -1;
1567f66887bSFrançois Revol 		inaddr = (inaddr >> 8) | ((a & 0x0ff) << 24);
1577f66887bSFrançois Revol 		*(uint32 *)addr = inaddr;
1587f66887bSFrançois Revol 		if (!*p)
1597f66887bSFrançois Revol 			return 0;
1607f66887bSFrançois Revol 		p++;
1617f66887bSFrançois Revol 	}
1627f66887bSFrançois Revol 	return 0;
1637f66887bSFrançois Revol }
1647f66887bSFrançois Revol 
1650f609eb2SFrançois Revol #if 0
1664d1cc41eSFrançois Revol #pragma mark ==== request manager ====
1670f609eb2SFrançois Revol #endif
1684d1cc41eSFrançois Revol 
nbd_alloc_request(struct nbd_device * dev,struct nbd_request_entry ** req,uint32 type,off_t from,size_t len,const char * data)1693ca76df5SFranç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)
1703ca76df5SFrançois Revol {
1713ca76df5SFrançois Revol 	bool w = (type == NBD_CMD_WRITE);
1723ca76df5SFrançois Revol 	struct nbd_request_entry *r;
1733ca76df5SFrançois Revol 	status_t err = EINVAL;
1743ca76df5SFrançois Revol 	uint64 handle;
1754e159473SJérôme Duval 	PRINT((DP ">%s(%" B_PRIu32 ", %" B_PRIdOFF ", %ld)\n", __FUNCTION__, type,
1764e159473SJérôme Duval 		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
1842b07b8e0SIngo 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
1932b07b8e0SIngo 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:
2254e159473SJérôme Duval 	dprintf(DP " %s: error 0x%08" B_PRIx32 "\n", __FUNCTION__, err);
2263ca76df5SFrançois Revol 	return err;
2273ca76df5SFrançois Revol }
2283ca76df5SFrançois Revol 
229eb5f3639SJerome Duval 
nbd_queue_request(struct nbd_device * dev,struct nbd_request_entry * req)2303ca76df5SFrançois Revol status_t nbd_queue_request(struct nbd_device *dev, struct nbd_request_entry *req)
2313ca76df5SFrançois Revol {
2324e159473SJérôme Duval 	PRINT((DP ">%s(handle:%" B_PRIu64 ")\n", __FUNCTION__, req->handle));
2333ca76df5SFrançois Revol 	req->next = dev->reqs;
2343ca76df5SFrançois Revol 	dev->reqs = req;
2353ca76df5SFrançois Revol 	return B_OK;
2363ca76df5SFrançois Revol }
2373ca76df5SFrançois Revol 
238eb5f3639SJerome Duval 
nbd_dequeue_request(struct nbd_device * dev,uint64 handle,struct nbd_request_entry ** req)2393ca76df5SFrançois Revol status_t nbd_dequeue_request(struct nbd_device *dev, uint64 handle, struct nbd_request_entry **req)
2403ca76df5SFrançois Revol {
2413ca76df5SFrançois Revol 	struct nbd_request_entry *r, *prev;
2424e159473SJérôme Duval 	PRINT((DP ">%s(handle:%" B_PRIu64 ")\n", __FUNCTION__, handle));
2433ca76df5SFrançois Revol 	r = dev->reqs;
2443ca76df5SFrançois Revol 	prev = NULL;
2453ca76df5SFrançois Revol 	while (r && r->handle != handle) {
2463ca76df5SFrançois Revol 		prev = r;
2473ca76df5SFrançois Revol 		r = r->next;
2483ca76df5SFrançois Revol 	}
2493ca76df5SFrançois Revol 	if (!r)
2503ca76df5SFrançois Revol 		return ENOENT;
2513ca76df5SFrançois Revol 
2523ca76df5SFrançois Revol 	if (prev)
2533ca76df5SFrançois Revol 		prev->next = r->next;
2543ca76df5SFrançois Revol 	else
2553ca76df5SFrançois Revol 		dev->reqs = r->next;
2563ca76df5SFrançois Revol 
2573ca76df5SFrançois Revol 	*req = r;
2583ca76df5SFrançois Revol 	return B_OK;
2593ca76df5SFrançois Revol }
2603ca76df5SFrançois Revol 
261eb5f3639SJerome Duval 
nbd_free_request(struct nbd_device * dev,struct nbd_request_entry * req)2623ca76df5SFrançois Revol status_t nbd_free_request(struct nbd_device *dev, struct nbd_request_entry *req)
2633ca76df5SFrançois Revol {
2644e159473SJérôme Duval 	PRINT((DP ">%s(handle:%" B_PRIu64 ")\n", __FUNCTION__, req->handle));
2653ca76df5SFrançois Revol 	delete_sem(req->sem);
2663ca76df5SFrançois Revol 	free(req);
2673ca76df5SFrançois Revol 	return B_OK;
2683ca76df5SFrançois Revol }
2693ca76df5SFrançois Revol 
2703ca76df5SFrançois Revol 
2710f609eb2SFrançois Revol #if 0
2724d1cc41eSFrançois Revol #pragma mark ==== nbd handler ====
2730f609eb2SFrançois Revol #endif
2744d1cc41eSFrançois Revol 
nbd_postoffice(void * arg)275637cbfeeSFrançois Revol int32 nbd_postoffice(void *arg)
2764d1cc41eSFrançois Revol {
2774d1cc41eSFrançois Revol 	struct nbd_device *dev = (struct nbd_device *)arg;
2783ca76df5SFrançois Revol 	struct nbd_request_entry *req = NULL;
2793ca76df5SFrançois Revol 	struct nbd_reply reply;
2803ca76df5SFrançois Revol 	status_t err;
2813ca76df5SFrançois Revol 	const char *reason;
282637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
2834d1cc41eSFrançois Revol 
2843ca76df5SFrançois Revol 	for (;;) {
2853ca76df5SFrançois Revol 		reason = "recv";
2863ca76df5SFrançois Revol 		err = krecv(dev->sock, &reply, sizeof(reply), 0);
2873ca76df5SFrançois Revol 		if (err == -1 && errno < 0)
2883ca76df5SFrançois Revol 			err = errno;
2893ca76df5SFrançois Revol 		if (err < 0)
2903ca76df5SFrançois Revol 			goto err;
2913ca76df5SFrançois Revol 		reason = "recv:size";
29207d5dba0SJim906 		if (err < (status_t)sizeof(reply))
2933ca76df5SFrançois Revol 			err = EINVAL;
2943ca76df5SFrançois Revol 		if (err < 0)
2953ca76df5SFrançois Revol 			goto err;
2963ca76df5SFrançois Revol 		reason = "magic";
2973ca76df5SFrançois Revol 		err = EINVAL;
2983ca76df5SFrançois Revol 		if (B_BENDIAN_TO_HOST_INT32(reply.magic) != NBD_REPLY_MAGIC)
2993ca76df5SFrançois Revol 			goto err;
3004d1cc41eSFrançois Revol 
3013ca76df5SFrançois Revol 		reason = "lock";
3023ca76df5SFrançois Revol 		//LOCK
3032b07b8e0SIngo Weinhold 		err = mutex_lock(&dev->ben);
3043ca76df5SFrançois Revol 		if (err)
3053ca76df5SFrançois Revol 			goto err;
3063ca76df5SFrançois Revol 
3073ca76df5SFrançois Revol 		reason = "dequeue_request";
3083ca76df5SFrançois Revol 		err = nbd_dequeue_request(dev, B_BENDIAN_TO_HOST_INT64(reply.handle), &req);
3093ca76df5SFrançois Revol 
3103ca76df5SFrançois Revol 		//UNLOCK
3112b07b8e0SIngo Weinhold 		mutex_unlock(&dev->ben);
3123ca76df5SFrançois Revol 
3133ca76df5SFrançois Revol 		if (!err && !req) {
3143ca76df5SFrançois Revol 			dprintf(DP "nbd_dequeue_rquest found NULL!\n");
3153ca76df5SFrançois Revol 			err = ENOENT;
3163ca76df5SFrançois Revol 		}
3173ca76df5SFrançois Revol 
3183ca76df5SFrançois Revol 		if (err == B_OK) {
3193ca76df5SFrançois Revol 			memcpy(&req->reply, &reply, sizeof(reply));
3203ca76df5SFrançois Revol 			if (req->type == NBD_CMD_READ) {
3213ca76df5SFrançois Revol 				err = 0;
3223ca76df5SFrançois Revol 				reason = "recv(data)";
3233ca76df5SFrançois Revol 				if (reply.error == 0)
3243ca76df5SFrançois Revol 					err = krecv(dev->sock, req->buffer, req->len, 0);
3253ca76df5SFrançois Revol 				if (err < 0)
3263ca76df5SFrançois Revol 					goto err;
3273ca76df5SFrançois Revol 				/* tell back how much we've got (?) */
3283ca76df5SFrançois Revol 				req->len = err;
3293ca76df5SFrançois Revol 			} else {
3303ca76df5SFrançois Revol 				if (reply.error)
3313ca76df5SFrançois Revol 					req->len = 0;
3323ca76df5SFrançois Revol 			}
3333ca76df5SFrançois Revol 
3343ca76df5SFrançois Revol 			reason = "lock";
3353ca76df5SFrançois Revol 			//LOCK
3362b07b8e0SIngo Weinhold 			err = mutex_lock(&dev->ben);
3373ca76df5SFrançois Revol 			if (err)
3383ca76df5SFrançois Revol 				goto err;
3393ca76df5SFrançois Revol 
3403ca76df5SFrançois Revol 			// this also must be atomic!
3413ca76df5SFrançois Revol 			release_sem(req->sem);
3423ca76df5SFrançois Revol 			req->replied = true;
3433ca76df5SFrançois Revol 			if (req->discard)
3443ca76df5SFrançois Revol 				nbd_free_request(dev, req);
3453ca76df5SFrançois Revol 
3463ca76df5SFrançois Revol 			//UNLOCK
3472b07b8e0SIngo Weinhold 			mutex_unlock(&dev->ben);
3483ca76df5SFrançois Revol 		}
3493ca76df5SFrançois Revol 
3503ca76df5SFrançois Revol 	}
3514d1cc41eSFrançois Revol 
352637cbfeeSFrançois Revol 	PRINT((DP "<%s\n", __FUNCTION__));
3534d1cc41eSFrançois Revol 	return 0;
3543ca76df5SFrançois Revol 
3553ca76df5SFrançois Revol err:
3564e159473SJérôme Duval 	dprintf(DP "%s: %s: error 0x%08" B_PRIx32 "\n", __FUNCTION__, reason, err);
3573ca76df5SFrançois Revol 	return err;
3584d1cc41eSFrançois Revol }
3594d1cc41eSFrançois Revol 
360eb5f3639SJerome Duval 
nbd_connect(struct nbd_device * dev)361771c6b93SFrançois Revol status_t nbd_connect(struct nbd_device *dev)
362771c6b93SFrançois Revol {
363637cbfeeSFrançois Revol 	struct nbd_init_packet initpkt;
364637cbfeeSFrançois Revol 	status_t err;
365637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
366771c6b93SFrançois Revol 
367637cbfeeSFrançois Revol 	PRINT((DP " %s: socket()\n", __FUNCTION__));
368637cbfeeSFrançois Revol 	err = dev->sock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
369637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
370637cbfeeSFrançois Revol 		err = errno;
371637cbfeeSFrançois Revol 	if (err < 0)
372637cbfeeSFrançois Revol 		goto err0;
373637cbfeeSFrançois Revol 
374637cbfeeSFrançois Revol 	PRINT((DP " %s: connect()\n", __FUNCTION__));
375637cbfeeSFrançois Revol 	err = kconnect(dev->sock, (struct sockaddr *)&dev->server, sizeof(dev->server));
376637cbfeeSFrançois Revol 	//err = ENOSYS;
377637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
378637cbfeeSFrançois Revol 		err = errno;
3790f609eb2SFrançois Revol 	/* HACK: avoid the kernel unloading us with locked pages from TCP */
380637cbfeeSFrançois Revol 	if (err)
381637cbfeeSFrançois Revol 		gDelayUnload = true;
382637cbfeeSFrançois Revol 	if (err)
383637cbfeeSFrançois Revol 		goto err1;
384637cbfeeSFrançois Revol 
385637cbfeeSFrançois Revol 	PRINT((DP " %s: recv(initpkt)\n", __FUNCTION__));
386637cbfeeSFrançois Revol 	err = krecv(dev->sock, &initpkt, sizeof(initpkt), 0);
387637cbfeeSFrançois Revol 	if (err == -1 && errno < 0)
388637cbfeeSFrançois Revol 		err = errno;
38907d5dba0SJim906 	if (err < (status_t)sizeof(initpkt))
390637cbfeeSFrançois Revol 		goto err2;
391637cbfeeSFrançois Revol 	err = EINVAL;//EPROTO;
392637cbfeeSFrançois Revol 	if (memcmp(initpkt.passwd, NBD_INIT_PASSWD, sizeof(initpkt.passwd)))
393637cbfeeSFrançois Revol 		goto err3;
394637cbfeeSFrançois Revol 	if (B_BENDIAN_TO_HOST_INT64(initpkt.magic) != NBD_INIT_MAGIC)
395637cbfeeSFrançois Revol 		goto err3;
396637cbfeeSFrançois Revol 
397637cbfeeSFrançois Revol 	dev->size = B_BENDIAN_TO_HOST_INT64(initpkt.device_size);
398637cbfeeSFrançois Revol 
3994e159473SJérôme Duval 	dprintf(DP " %s: connected, device size %" B_PRIu64 " bytes.\n",
4004e159473SJérôme Duval 		__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:
4184e159473SJérôme Duval 	dprintf(DP "<%s: error 0x%08" B_PRIx32 "\n", __FUNCTION__, err);
419637cbfeeSFrançois Revol 	return err;
420771c6b93SFrançois Revol }
421771c6b93SFrançois Revol 
422eb5f3639SJerome Duval 
nbd_teardown(struct nbd_device * dev)423771c6b93SFrançois Revol status_t nbd_teardown(struct nbd_device *dev)
424771c6b93SFrançois Revol {
425eb5f3639SJerome 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;
430eb5f3639SJerome Duval 	wait_for_thread(dev->postoffice, &ret);
431771c6b93SFrançois Revol 	return B_OK;
432771c6b93SFrançois Revol }
433771c6b93SFrançois Revol 
434eb5f3639SJerome Duval 
nbd_post_request(struct nbd_device * dev,struct nbd_request_entry * req)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;
4384e159473SJérôme Duval 	PRINT((DP ">%s(handle:%" B_PRIu64 ")\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 
nbd_open(const char * name,uint32 flags,cookie_t ** cookie)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
465eb5f3639SJerome Duval 	int32 refcnt;
4667f66887bSFrançois Revol 	int kfd;
4677f66887bSFrançois Revol #endif
468e96eef09SFrançois Revol 	struct nbd_device *dev = NULL;
4694e159473SJérôme Duval 	PRINT((DP ">%s(%s, %" B_PRIx32 ", )\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
489eb5f3639SJerome 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:
5124e159473SJérôme Duval 	dprintf(DP " %s: error 0x%08" B_PRIx32 "\n", __FUNCTION__, err);
513771c6b93SFrançois Revol 	return err;
5144d1cc41eSFrançois Revol }
5154d1cc41eSFrançois Revol 
516eb5f3639SJerome Duval 
nbd_close(cookie_t * cookie)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 
545eb5f3639SJerome Duval 
nbd_free(cookie_t * cookie)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 
565eb5f3639SJerome Duval 
nbd_control(cookie_t * cookie,uint32 op,void * data,size_t len)5664d1cc41eSFrançois Revol status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) {
5674e159473SJérôme Duval 	PRINT((DP ">%s(%d, %" B_PRIu32 ", , %ld)\n", __FUNCTION__,
5684e159473SJérôme Duval 		WHICH(cookie->dev), op, len));
5694d1cc41eSFrançois Revol 	switch (op) {
5704d1cc41eSFrançois Revol 	case B_GET_DEVICE_SIZE: /* this one is broken anyway... */
5714d1cc41eSFrançois Revol 		if (data) {
5724d1cc41eSFrançois Revol 			*(size_t *)data = (size_t)cookie->dev->size;
5734d1cc41eSFrançois Revol 			return B_OK;
5744d1cc41eSFrançois Revol 		}
5754d1cc41eSFrançois Revol 		return EINVAL;
5764d1cc41eSFrançois Revol 	case B_SET_DEVICE_SIZE: /* broken */
5774d1cc41eSFrançois Revol 		return EINVAL;
5784d1cc41eSFrançois Revol 	case B_SET_NONBLOCKING_IO:
5794d1cc41eSFrançois Revol 		return EINVAL;
5804d1cc41eSFrançois Revol 	case B_SET_BLOCKING_IO:
5814d1cc41eSFrançois Revol 		return B_OK;
5824d1cc41eSFrançois Revol 	case B_GET_READ_STATUS:
5834d1cc41eSFrançois Revol 	case B_GET_WRITE_STATUS:
5844d1cc41eSFrançois Revol 		if (data) {
5854d1cc41eSFrançois Revol 			*(bool *)data = false;
5864d1cc41eSFrançois Revol 			return B_OK;
5874d1cc41eSFrançois Revol 		}
5884d1cc41eSFrançois Revol 		return EINVAL;
5894d1cc41eSFrançois Revol 	case B_GET_GEOMETRY:
5904d1cc41eSFrançois Revol 	case B_GET_BIOS_GEOMETRY:
591*688acf41SJérôme Duval 		if (data != NULL && len <= sizeof(device_geometry)) {
592*688acf41SJérôme Duval 			device_geometry geometry;
593*688acf41SJérôme Duval 			geometry.bytes_per_sector = BLKSIZE;
594*688acf41SJérôme Duval 			geometry.sectors_per_track = 1;
595*688acf41SJérôme Duval 			geometry.cylinder_count = cookie->dev->size / BLKSIZE;
596*688acf41SJérôme Duval 			geometry.head_count = 1;
597*688acf41SJérôme Duval 			geometry.device_type = B_DISK;
598*688acf41SJérôme Duval 			geometry.removable = false;
599*688acf41SJérôme Duval 			geometry.read_only = cookie->dev->readonly;
600*688acf41SJérôme Duval 			geometry.write_once = false;
601*688acf41SJérôme Duval 			geometry.bytes_per_physical_sector = BLKSIZE;
602*688acf41SJérôme Duval 			return user_memcpy(data, &geometry, len);
6034d1cc41eSFrançois Revol 		}
6044d1cc41eSFrançois Revol 		return EINVAL;
6054d1cc41eSFrançois Revol 	case B_GET_MEDIA_STATUS:
6064d1cc41eSFrançois Revol 		if (data) {
6074d1cc41eSFrançois Revol 			*(status_t *)data = B_OK;
6084d1cc41eSFrançois Revol 			return B_OK;
6094d1cc41eSFrançois Revol 		}
6104d1cc41eSFrançois Revol 		return EINVAL;
6114d1cc41eSFrançois Revol 
6124d1cc41eSFrançois Revol 	case B_EJECT_DEVICE:
6134d1cc41eSFrançois Revol 	case B_LOAD_MEDIA:
614a0062874SFrançois Revol 		return B_BAD_VALUE;
6154d1cc41eSFrançois Revol 	case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */
616a0062874SFrançois Revol 		return B_OK;
6174d1cc41eSFrançois Revol 	default:
618a0062874SFrançois Revol 		return B_BAD_VALUE;
6194d1cc41eSFrançois Revol 	}
6204d1cc41eSFrançois Revol 	return B_NOT_ALLOWED;
6214d1cc41eSFrançois Revol }
6224d1cc41eSFrançois Revol 
623eb5f3639SJerome Duval 
nbd_read(cookie_t * cookie,off_t position,void * data,size_t * numbytes)6244d1cc41eSFrançois Revol status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) {
6253ca76df5SFrançois Revol 	struct nbd_device *dev = cookie->dev;
6263ca76df5SFrançois Revol 	struct nbd_request_entry *req;
6273ca76df5SFrançois Revol 	status_t err, semerr;
6284e159473SJérôme Duval 	PRINT((DP ">%s(%d, %" B_PRIdOFF ", , )\n", __FUNCTION__,
6294e159473SJérôme Duval 		WHICH(cookie->dev), position));
6303ca76df5SFrançois Revol 
6313ca76df5SFrançois Revol 	if (position < 0)
6323ca76df5SFrançois Revol 		return EINVAL;
6333ca76df5SFrançois Revol 	if (!data)
6343ca76df5SFrançois Revol 		return EINVAL;
6353ca76df5SFrançois Revol 
6363ca76df5SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_READ, position, *numbytes, NULL);
6373ca76df5SFrançois Revol 	if (err)
6383ca76df5SFrançois Revol 		goto err0;
6393ca76df5SFrançois Revol 
6403ca76df5SFrançois Revol 	//LOCK
6412b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6423ca76df5SFrançois Revol 	if (err)
6433ca76df5SFrançois Revol 		goto err1;
6443ca76df5SFrançois Revol 
6453ca76df5SFrançois Revol 	err = nbd_post_request(dev, req);
6463ca76df5SFrançois Revol 
6473ca76df5SFrançois Revol 	//UNLOCK
6482b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6493ca76df5SFrançois Revol 
6503ca76df5SFrançois Revol 	if (err)
6513ca76df5SFrançois Revol 		goto err2;
6523ca76df5SFrançois Revol 
6533ca76df5SFrançois Revol 
6543ca76df5SFrançois Revol 	semerr = acquire_sem(req->sem);
6553ca76df5SFrançois Revol 
6563ca76df5SFrançois Revol 	//LOCK
6572b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
6583ca76df5SFrançois Revol 	if(err)
6593ca76df5SFrançois Revol 		goto err3;
6603ca76df5SFrançois Revol 
6613ca76df5SFrançois Revol 	/* bad scenarii */
6623ca76df5SFrançois Revol 	if (!req->replied)
6633ca76df5SFrançois Revol 		req->discard = true;
6643ca76df5SFrançois Revol 	else if (semerr)
6653ca76df5SFrançois Revol 		nbd_free_request(dev, req);
6663ca76df5SFrançois Revol 
6673ca76df5SFrançois Revol 	//UNLOCK
6682b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
6693ca76df5SFrançois Revol 
6703ca76df5SFrançois Revol 	if (semerr == B_OK) {
6713ca76df5SFrançois Revol 		*numbytes = req->len;
6723ca76df5SFrançois Revol 		memcpy(data, req->buffer, req->len);
673ff517f43SFrançois Revol 		err = B_OK;
6743ca76df5SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
675ff517f43SFrançois Revol 			err = EIO;
676ff517f43SFrançois Revol 		nbd_free_request(dev, req);
677ff517f43SFrançois Revol 		return err;
6783ca76df5SFrançois Revol 	}
6793ca76df5SFrançois Revol 
6804d1cc41eSFrançois Revol 	*numbytes = 0;
6813ca76df5SFrançois Revol 	return semerr;
6823ca76df5SFrançois Revol 
6833ca76df5SFrançois Revol 
6843ca76df5SFrançois Revol err3:
6853ca76df5SFrançois Revol err2:
6863ca76df5SFrançois Revol err1:
6873ca76df5SFrançois Revol 	nbd_free_request(dev, req);
6883ca76df5SFrançois Revol err0:
6893ca76df5SFrançois Revol 	*numbytes = 0;
6903ca76df5SFrançois Revol 	return err;
6914d1cc41eSFrançois Revol }
6924d1cc41eSFrançois Revol 
693eb5f3639SJerome Duval 
nbd_write(cookie_t * cookie,off_t position,const void * data,size_t * numbytes)6944d1cc41eSFrançois Revol status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) {
695ff517f43SFrançois Revol 	struct nbd_device *dev = cookie->dev;
696ff517f43SFrançois Revol 	struct nbd_request_entry *req;
697ff517f43SFrançois Revol 	status_t err, semerr;
6984e159473SJérôme Duval 	PRINT((DP ">%s(%d, %" B_PRIdOFF ", %ld, )\n", __FUNCTION__,
6994e159473SJérôme Duval 		WHICH(cookie->dev), position, *numbytes));
700ff517f43SFrançois Revol 
701ff517f43SFrançois Revol 	if (position < 0)
702ff517f43SFrançois Revol 		return EINVAL;
703ff517f43SFrançois Revol 	if (!data)
704ff517f43SFrançois Revol 		return EINVAL;
705ff517f43SFrançois Revol 	err = B_NOT_ALLOWED;
706ff517f43SFrançois Revol 	if (dev->readonly)
707ff517f43SFrançois Revol 		goto err0;
708ff517f43SFrançois Revol 
709ff517f43SFrançois Revol 	err = nbd_alloc_request(dev, &req, NBD_CMD_WRITE, position, *numbytes, data);
710ff517f43SFrançois Revol 	if (err)
711ff517f43SFrançois Revol 		goto err0;
712ff517f43SFrançois Revol 
713ff517f43SFrançois Revol 	//LOCK
7142b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
715ff517f43SFrançois Revol 	if (err)
716ff517f43SFrançois Revol 		goto err1;
717ff517f43SFrançois Revol 
718ff517f43SFrançois Revol 	/* sending request+data must be atomic */
719ff517f43SFrançois Revol 	err = nbd_post_request(dev, req);
720ff517f43SFrançois Revol 
721ff517f43SFrançois Revol 	//UNLOCK
7222b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
723ff517f43SFrançois Revol 
724ff517f43SFrançois Revol 	if (err)
725ff517f43SFrançois Revol 		goto err2;
726ff517f43SFrançois Revol 
727ff517f43SFrançois Revol 
728ff517f43SFrançois Revol 	semerr = acquire_sem(req->sem);
729ff517f43SFrançois Revol 
730ff517f43SFrançois Revol 	//LOCK
7312b07b8e0SIngo Weinhold 	err = mutex_lock(&dev->ben);
732ff517f43SFrançois Revol 	if(err)
733ff517f43SFrançois Revol 		goto err3;
734ff517f43SFrançois Revol 
735ff517f43SFrançois Revol 	/* bad scenarii */
736ff517f43SFrançois Revol 	if (!req->replied)
737ff517f43SFrançois Revol 		req->discard = true;
738ff517f43SFrançois Revol 	else if (semerr)
739ff517f43SFrançois Revol 		nbd_free_request(dev, req);
740ff517f43SFrançois Revol 
741ff517f43SFrançois Revol 	//UNLOCK
7422b07b8e0SIngo Weinhold 	mutex_unlock(&dev->ben);
743ff517f43SFrançois Revol 
744ff517f43SFrançois Revol 	if (semerr == B_OK) {
745ff517f43SFrançois Revol 		*numbytes = req->len;
746ff517f43SFrançois Revol 		err = B_OK;
747ff517f43SFrançois Revol 		if (*numbytes == 0 && req->reply.error)
748ff517f43SFrançois Revol 			err = EIO;
749ff517f43SFrançois Revol 		nbd_free_request(dev, req);
750ff517f43SFrançois Revol 		return err;
751ff517f43SFrançois Revol 	}
752ff517f43SFrançois Revol 
7534d1cc41eSFrançois Revol 	*numbytes = 0;
754ff517f43SFrançois Revol 	return semerr;
755ff517f43SFrançois Revol 
756ff517f43SFrançois Revol 
757ff517f43SFrançois Revol err3:
758ff517f43SFrançois Revol err2:
759ff517f43SFrançois Revol err1:
760ff517f43SFrançois Revol 	nbd_free_request(dev, req);
761ff517f43SFrançois Revol err0:
762ff517f43SFrançois Revol 	*numbytes = 0;
763ff517f43SFrançois Revol 	return err;
7644d1cc41eSFrançois Revol }
7654d1cc41eSFrançois Revol 
766eb5f3639SJerome Duval 
7674d1cc41eSFrançois Revol device_hooks nbd_hooks={
7684d1cc41eSFrançois Revol 	(device_open_hook)nbd_open,
769ff517f43SFrançois Revol 	(device_close_hook)nbd_close,
7704d1cc41eSFrançois Revol 	(device_free_hook)nbd_free,
7714d1cc41eSFrançois Revol 	(device_control_hook)nbd_control,
7724d1cc41eSFrançois Revol 	(device_read_hook)nbd_read,
7734d1cc41eSFrançois Revol 	(device_write_hook)nbd_write,
7744d1cc41eSFrançois Revol 	NULL,
7754d1cc41eSFrançois Revol 	NULL,
7764d1cc41eSFrançois Revol 	NULL,
7774d1cc41eSFrançois Revol 	NULL
7784d1cc41eSFrançois Revol };
7794d1cc41eSFrançois Revol 
7800f609eb2SFrançois Revol #if 0
7814d1cc41eSFrançois Revol #pragma mark ==== driver hooks ====
7820f609eb2SFrançois Revol #endif
7834d1cc41eSFrançois Revol 
784ec8bd525SFrançois Revol int32 api_version = B_CUR_DRIVER_API_VERSION;
785ec8bd525SFrançois Revol 
786ff517f43SFrançois Revol static char *nbd_name[MAX_NBDS+1] = {
7874d1cc41eSFrançois Revol 	NULL
7884d1cc41eSFrançois Revol };
7894d1cc41eSFrançois Revol 
790eb5f3639SJerome Duval 
7914d1cc41eSFrançois Revol status_t
init_hardware(void)7924d1cc41eSFrançois Revol init_hardware (void)
7934d1cc41eSFrançois Revol {
794637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
7954d1cc41eSFrançois Revol 	return B_OK;
7964d1cc41eSFrançois Revol }
7974d1cc41eSFrançois Revol 
798eb5f3639SJerome Duval 
7994d1cc41eSFrançois Revol status_t
init_driver(void)8004d1cc41eSFrançois Revol init_driver (void)
8014d1cc41eSFrançois Revol {
802771c6b93SFrançois Revol 	status_t err;
803771c6b93SFrançois Revol 	int i, j;
804771c6b93SFrançois Revol 	// XXX: load settings
805771c6b93SFrançois Revol 	void *handle;
806ff517f43SFrançois Revol 	char **names = nbd_name;
807637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
808771c6b93SFrançois Revol 
8097f66887bSFrançois Revol 	handle = load_driver_settings(DRV);
8107f66887bSFrançois Revol 	if (handle == NULL)
8117f66887bSFrançois Revol 		return ENOENT;
8127f66887bSFrançois Revol 	// XXX: test for boot args ?
8137f66887bSFrançois Revol 
8147f66887bSFrançois Revol 
815771c6b93SFrançois Revol 	err = ksocket_init();
816771c6b93SFrançois Revol 	if (err < B_OK)
817771c6b93SFrançois Revol 		return err;
818771c6b93SFrançois Revol 
8194d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8207f66887bSFrançois Revol 		nbd_devices[i].valid = false;
8217f66887bSFrançois Revol 		nbd_devices[i].readonly = false;
8222b07b8e0SIngo Weinhold 		mutex_init(&nbd_devices[i].ben, "nbd lock");
823771c6b93SFrançois Revol 		nbd_devices[i].refcnt = 0;
824771c6b93SFrançois Revol 		nbd_devices[i].req = 0LL; /* next ID for requests */
825771c6b93SFrançois Revol 		nbd_devices[i].sock = -1;
826771c6b93SFrançois Revol 		nbd_devices[i].postoffice = -1;
827771c6b93SFrançois Revol 		nbd_devices[i].size = 0LL;
828771c6b93SFrançois Revol 		nbd_devices[i].reqs = NULL;
8297f66887bSFrançois Revol #ifdef MOUNT_KLUDGE
8307f66887bSFrançois Revol 		nbd_devices[i].kludge = -1;
8317f66887bSFrançois Revol #endif
8324d1cc41eSFrançois Revol 		nbd_name[i] = NULL;
833ff517f43SFrançois Revol 	}
834771c6b93SFrançois Revol 
835771c6b93SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
836ff517f43SFrançois Revol 		const driver_settings *settings = get_driver_settings(handle);
837ff517f43SFrançois Revol 		driver_parameter *p = NULL;
838771c6b93SFrançois Revol 		char keyname[10];
8397f66887bSFrançois Revol 		sprintf(keyname, "%d", i);
8407f66887bSFrançois Revol 		for (j = 0; j < settings->parameter_count; j++)
8417f66887bSFrançois Revol 			if (!strcmp(settings->parameters[j].name, keyname))
8427f66887bSFrançois Revol 				p = &settings->parameters[j];
8437f66887bSFrançois Revol 		if (!p)
8447f66887bSFrançois Revol 			continue;
8457f66887bSFrançois Revol 		for (j = 0; j < p->parameter_count; j++) {
8467f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "readonly"))
8477f66887bSFrançois Revol 				nbd_devices[i].readonly = true;
8487f66887bSFrançois Revol 			if (!strcmp(p->parameters[j].name, "server")) {
8497f66887bSFrançois Revol 				if (p->parameters[j].value_count < 2)
8507f66887bSFrançois Revol 					continue;
851771c6b93SFrançois Revol 				nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in);
852771c6b93SFrançois Revol 				nbd_devices[i].server.sin_family = AF_INET;
8537f66887bSFrançois Revol 				kinet_aton(p->parameters[j].values[0], &nbd_devices[i].server.sin_addr);
8547f66887bSFrançois Revol 				nbd_devices[i].server.sin_port = htons(atoi(p->parameters[j].values[1]));
855ff517f43SFrançois Revol 				dprintf(DP " configured [%d]\n", i);
856ff517f43SFrançois Revol 				*(names) = malloc(DEVICE_NAME_MAX);
857ff517f43SFrançois Revol 				if (*(names) == NULL)
858ff517f43SFrançois Revol 					return ENOMEM;
859ff517f43SFrançois Revol 				sprintf(*(names++), DEVICE_FMT, i);
8607f66887bSFrançois Revol 				nbd_devices[i].valid = true;
861771c6b93SFrançois Revol 			}
8627f66887bSFrançois Revol 		}
8637f66887bSFrançois Revol 	}
864ff517f43SFrançois Revol 	*names = NULL;
865771c6b93SFrançois Revol 
866771c6b93SFrançois Revol 	unload_driver_settings(handle);
8674d1cc41eSFrançois Revol 	return B_OK;
8684d1cc41eSFrançois Revol }
8694d1cc41eSFrançois Revol 
870eb5f3639SJerome Duval 
8714d1cc41eSFrançois Revol void
uninit_driver(void)8724d1cc41eSFrançois Revol uninit_driver (void)
8734d1cc41eSFrançois Revol {
8744d1cc41eSFrançois Revol 	int i;
875637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
8764d1cc41eSFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
8774d1cc41eSFrançois Revol 		free(nbd_name[i]);
8782b07b8e0SIngo Weinhold 		mutex_destroy(&nbd_devices[i].ben);
8794d1cc41eSFrançois Revol 	}
880eb5f3639SJerome Duval 	ksocket_cleanup();
881637cbfeeSFrançois Revol 	/* HACK */
882637cbfeeSFrançois Revol 	if (gDelayUnload)
883637cbfeeSFrançois Revol 		snooze(BONE_TEARDOWN_DELAY);
8844d1cc41eSFrançois Revol }
8854d1cc41eSFrançois Revol 
886eb5f3639SJerome Duval 
8874d1cc41eSFrançois Revol const char**
publish_devices()8884d1cc41eSFrançois Revol publish_devices()
8894d1cc41eSFrançois Revol {
890637cbfeeSFrançois Revol 	PRINT((DP ">%s()\n", __FUNCTION__));
891ff517f43SFrançois Revol 	return (const char **)nbd_name;
8924d1cc41eSFrançois Revol }
8934d1cc41eSFrançois Revol 
894eb5f3639SJerome Duval 
8954d1cc41eSFrançois Revol device_hooks*
find_device(const char * name)8964d1cc41eSFrançois Revol find_device(const char* name)
8974d1cc41eSFrançois Revol {
898637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
8994d1cc41eSFrançois Revol 	return &nbd_hooks;
9004d1cc41eSFrançois Revol }
901e96eef09SFrançois Revol 
902eb5f3639SJerome Duval 
903e96eef09SFrançois Revol struct nbd_device*
nbd_find_device(const char * name)904e96eef09SFrançois Revol nbd_find_device(const char* name)
905e96eef09SFrançois Revol {
906e96eef09SFrançois Revol 	int i;
907637cbfeeSFrançois Revol 	PRINT((DP ">%s(%s)\n", __FUNCTION__, name));
908e96eef09SFrançois Revol 	for (i = 0; i < MAX_NBDS; i++) {
909ff517f43SFrançois Revol 		char buf[DEVICE_NAME_MAX];
910ff517f43SFrançois Revol 		sprintf(buf, DEVICE_FMT, i);
911ff517f43SFrançois Revol 		if (!strcmp(buf, name))
912e96eef09SFrançois Revol 			return &nbd_devices[i];
913e96eef09SFrançois Revol 	}
914e96eef09SFrançois Revol 	return NULL;
915e96eef09SFrançois Revol }
916eb5f3639SJerome Duval 
917