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