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