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