1 /* 2 * Copyright 2006-2007, François Revol. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /* 7 * nbd driver for Haiku 8 * 9 * Maps a Network Block Device as virtual partitions. 10 */ 11 12 #include <KernelExport.h> 13 #include <Drivers.h> 14 #include <Errors.h> 15 #include <driver_settings.h> 16 #include <ksocket.h> 17 #include <netinet/in.h> 18 19 #define DEBUG 1 20 21 /* locking support */ 22 #ifdef __HAIKU__ 23 #include <kernel/lock.h> 24 #else 25 /* wrappers for R5 */ 26 #ifndef _IMPEXP_KERNEL 27 #define _IMPEXP_KERNEL 28 #endif 29 #include "lock.h" 30 #define benaphore lock 31 #define benaphore_init new_lock 32 #define benaphore_destroy free_lock 33 #define benaphore_lock LOCK 34 #define benaphore_unlock UNLOCK 35 #endif 36 37 #include "nbd.h" 38 39 #define DRV "nbd" 40 #define DP "nbd:" 41 #define MAX_NBDS 4 42 #define DEVICE_PREFIX "disk/virtual/nbd/" 43 #define DEVICE_FMT DEVICE_PREFIX "%d/raw" 44 #define DEVICE_NAME_MAX 32 45 #define MAX_REQ_SIZE (32*1024*1024) 46 47 /* debugging */ 48 #if DEBUG 49 #define PRINT(a) dprintf a 50 #define WHICH(dev) ((int)(dev - nbd_devices)) 51 #else 52 #define PRINT(a) 53 #endif 54 55 struct nbd_request_entry { 56 struct nbd_request_entry *next; 57 struct nbd_request req; 58 bool r; /* is read */ 59 size_t len; 60 void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */ 61 }; 62 63 struct nbd_device { 64 char target[64]; // "ip:port" 65 struct sockaddr_in server; 66 benaphore ben; 67 vint32 refcnt; 68 uint64 req; /* next ID for requests */ 69 int sock; 70 thread_id postoffice; 71 uint64 size; 72 struct nbd_request_entry *reqs; 73 }; 74 75 typedef struct cookie { 76 struct nbd_device *dev; 77 78 } cookie_t; 79 80 /* data=NULL on read */ 81 status_t nbd_alloc_request(struct nbd_device, struct nbd_request_entry **req, size_t len, const char *data); 82 status_t nbd_post_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); 83 status_t nbd_dequeue_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); 84 status_t nbd_free_request(struct nbd_device, struct nbd_request_entry *req); 85 86 struct nbd_device *nbd_find_device(const char* name); 87 88 KSOCKET_MODULE_DECL; 89 90 /* HACK: 91 * In BONE at least, if connect() fails (EINTR or ETIMEDOUT) 92 * keeps locked pages around (likely a bone_data, 93 * until TCP gets the last ACK). If that happens, we snooze() 94 * in unload_driver() to let TCP timeout before the kernel 95 * tries to delete the image. */ 96 bool gDelayUnload = false; 97 #define BONE_TEARDOWN_DELAY 60000000 98 99 #pragma mark ==== request manager ==== 100 101 102 #pragma mark ==== nbd handler ==== 103 104 int32 nbd_postoffice(void *arg) 105 { 106 struct nbd_device *dev = (struct nbd_device *)arg; 107 int sock = dev->sock; 108 PRINT((DP ">%s()\n", __FUNCTION__)); 109 110 111 112 PRINT((DP "<%s\n", __FUNCTION__)); 113 return 0; 114 } 115 116 status_t nbd_connect(struct nbd_device *dev) 117 { 118 struct nbd_init_packet initpkt; 119 status_t err; 120 PRINT((DP ">%s()\n", __FUNCTION__)); 121 122 PRINT((DP " %s: socket()\n", __FUNCTION__)); 123 err = dev->sock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 124 if (err == -1 && errno < 0) 125 err = errno; 126 if (err < 0) 127 goto err0; 128 129 PRINT((DP " %s: connect()\n", __FUNCTION__)); 130 err = kconnect(dev->sock, (struct sockaddr *)&dev->server, sizeof(dev->server)); 131 //err = ENOSYS; 132 if (err == -1 && errno < 0) 133 err = errno; 134 /* HACK: avoid the kernel unlading us with locked pages from TCP */ 135 if (err) 136 gDelayUnload = true; 137 if (err) 138 goto err1; 139 140 PRINT((DP " %s: recv(initpkt)\n", __FUNCTION__)); 141 err = krecv(dev->sock, &initpkt, sizeof(initpkt), 0); 142 if (err == -1 && errno < 0) 143 err = errno; 144 if (err < sizeof(initpkt)) 145 goto err2; 146 err = EINVAL;//EPROTO; 147 if (memcmp(initpkt.passwd, NBD_INIT_PASSWD, sizeof(initpkt.passwd))) 148 goto err3; 149 if (B_BENDIAN_TO_HOST_INT64(initpkt.magic) != NBD_INIT_MAGIC) 150 goto err3; 151 152 dev->size = B_BENDIAN_TO_HOST_INT64(initpkt.device_size); 153 154 dprintf(DP " %s: connected, device size %Ld bytes.\n", __FUNCTION__, dev->size); 155 156 err = dev->postoffice = spawn_kernel_thread(nbd_postoffice, "nbd postoffice", B_REAL_TIME_PRIORITY, dev); 157 if (err < B_OK) 158 goto err4; 159 resume_thread(dev->postoffice); 160 161 PRINT((DP "<%s\n", __FUNCTION__)); 162 return B_OK; 163 164 err4: 165 dev->postoffice = -1; 166 err3: 167 err2: 168 err1: 169 kclosesocket(dev->sock); 170 dev->sock = -1; 171 err0: 172 dprintf(DP "<%s: error 0x%08lx\n", __FUNCTION__, err); 173 return err; 174 } 175 176 status_t nbd_teardown(struct nbd_device *dev) 177 { 178 status_t err, ret; 179 PRINT((DP ">%s()\n", __FUNCTION__)); 180 kshutdown(dev->sock, SHUTDOWN_BOTH); 181 kclosesocket(dev->sock); 182 dev->sock = -1; 183 err = wait_for_thread(dev->postoffice, &ret); 184 return B_OK; 185 } 186 187 #pragma mark ==== device hooks ==== 188 189 static struct nbd_device nbd_devices[MAX_NBDS]; 190 191 status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie) { 192 status_t err; 193 struct nbd_device *dev = NULL; 194 PRINT((DP ">%s(%s, %x, )\n", __FUNCTION__, name, flags)); 195 (void)name; (void)flags; 196 dev = nbd_find_device(name); 197 if (!dev) 198 return ENOENT; 199 err = ENOMEM; 200 *cookie = (void*)malloc(sizeof(cookie_t)); 201 if (*cookie == NULL) 202 goto err0; 203 memset(*cookie, 0, sizeof(cookie_t)); 204 (*cookie)->dev = dev; 205 err = benaphore_lock(&dev->ben); 206 if (err) 207 goto err1; 208 /* */ 209 if (dev->sock < 0) 210 err = nbd_connect(dev); 211 if (err) 212 goto err2; 213 dev->refcnt++; 214 benaphore_unlock(&dev->ben); 215 return B_OK; 216 217 err2: 218 benaphore_unlock(&dev->ben); 219 err1: 220 free(*cookie); 221 err0: 222 dprintf(DP " %s: error 0x%08lx\n", __FUNCTION__, err); 223 return err; 224 } 225 226 status_t nbd_close(cookie_t *cookie) { 227 struct nbd_device *dev = cookie->dev; 228 status_t err; 229 PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev))); 230 231 err = benaphore_lock(&dev->ben); 232 if (err) 233 return err; 234 235 // XXX: do something ? 236 237 benaphore_unlock(&dev->ben); 238 return B_OK; 239 } 240 241 status_t nbd_free(cookie_t *cookie) { 242 struct nbd_device *dev = cookie->dev; 243 status_t err; 244 PRINT((DP ">%s(%d)\n", __FUNCTION__, WHICH(cookie->dev))); 245 246 err = benaphore_lock(&dev->ben); 247 if (err) 248 return err; 249 250 if (--dev->refcnt == 0) { 251 err = nbd_teardown(dev); 252 } 253 254 benaphore_unlock(&dev->ben); 255 256 free(cookie); 257 return err; 258 } 259 260 status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) { 261 PRINT((DP ">%s(%d, %ul, , %d)\n", __FUNCTION__, WHICH(cookie->dev), op, len)); 262 switch (op) { 263 case B_GET_DEVICE_SIZE: /* this one is broken anyway... */ 264 if (data) { 265 *(size_t *)data = (size_t)cookie->dev->size; 266 return B_OK; 267 } 268 return EINVAL; 269 case B_SET_DEVICE_SIZE: /* broken */ 270 return EINVAL; 271 case B_SET_NONBLOCKING_IO: 272 return EINVAL; 273 case B_SET_BLOCKING_IO: 274 return B_OK; 275 case B_GET_READ_STATUS: 276 case B_GET_WRITE_STATUS: 277 if (data) { 278 *(bool *)data = false; 279 return B_OK; 280 } 281 return EINVAL; 282 case B_GET_GEOMETRY: 283 case B_GET_BIOS_GEOMETRY: 284 if (data) { 285 device_geometry *geom = (device_geometry *)data; 286 geom->bytes_per_sector = 256; 287 geom->sectors_per_track = 1; 288 geom->cylinder_count = cookie->dev->size / 256; 289 geom->head_count = 1; 290 geom->device_type = B_DISK; 291 geom->removable = false; 292 geom->read_only = false; // XXX 293 geom->write_once = false; 294 return B_OK; 295 } 296 return EINVAL; 297 case B_GET_MEDIA_STATUS: 298 if (data) { 299 *(status_t *)data = B_OK; 300 return B_OK; 301 } 302 return EINVAL; 303 304 case B_EJECT_DEVICE: 305 case B_LOAD_MEDIA: 306 return ENOSYS; 307 case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */ 308 default: 309 return ENOSYS; 310 } 311 return B_NOT_ALLOWED; 312 } 313 314 status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) { 315 PRINT((DP ">%s(%d, %Ld, , )\n", __FUNCTION__, WHICH(cookie->dev), position)); 316 *numbytes = 0; 317 return B_NOT_ALLOWED; 318 } 319 320 status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) { 321 PRINT((DP ">%s(%d, %Ld, , )\n", __FUNCTION__, WHICH(cookie->dev), position)); 322 (void)cookie; (void)position; (void)data; (void)numbytes; 323 *numbytes = 0; 324 return EIO; 325 } 326 327 device_hooks nbd_hooks={ 328 (device_open_hook)nbd_open, 329 nbd_close, 330 (device_free_hook)nbd_free, 331 (device_control_hook)nbd_control, 332 (device_read_hook)nbd_read, 333 (device_write_hook)nbd_write, 334 NULL, 335 NULL, 336 NULL, 337 NULL 338 }; 339 340 341 #pragma mark ==== driver hooks ==== 342 343 static const char *nbd_name[MAX_NBDS+1] = { 344 NULL 345 }; 346 347 status_t 348 init_hardware (void) 349 { 350 PRINT((DP ">%s()\n", __FUNCTION__)); 351 return B_OK; 352 } 353 354 status_t 355 init_driver (void) 356 { 357 status_t err; 358 int i, j; 359 // XXX: load settings 360 void *handle; 361 PRINT((DP ">%s()\n", __FUNCTION__)); 362 363 err = ksocket_init(); 364 if (err < B_OK) 365 return err; 366 367 for (i = 0; i < MAX_NBDS; i++) { 368 memset(nbd_devices[i].target, 0, 64); 369 err = benaphore_init(&nbd_devices[i].ben, "nbd lock"); 370 if (err < B_OK) 371 return err; // XXX 372 nbd_devices[i].refcnt = 0; 373 nbd_devices[i].req = 0LL; /* next ID for requests */ 374 nbd_devices[i].sock = -1; 375 nbd_devices[i].postoffice = -1; 376 nbd_devices[i].size = 0LL; 377 nbd_devices[i].reqs = NULL; 378 nbd_name[i] = malloc(DEVICE_NAME_MAX); 379 if (nbd_name[i] == NULL) 380 break; 381 sprintf(nbd_name[i], DEVICE_FMT, i); 382 /* XXX: default init */ 383 nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in); 384 nbd_devices[i].server.sin_family = AF_INET; 385 nbd_devices[i].server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 386 nbd_devices[i].server.sin_port = htons(1337 + i); 387 } 388 nbd_name[i] = NULL; 389 390 handle = load_driver_settings(DRV); 391 if (handle) { 392 for (i = 0; i < MAX_NBDS; i++) { 393 char keyname[10]; 394 char *v; 395 sprintf(keyname, "nbd%d", i); 396 v = get_driver_parameter(handle, keyname, NULL, NULL); 397 /* should be "ip:port" */ 398 // XXX: test 399 if (v || 1) { 400 //strncpy(nbd_devices[i].target, v, 64); 401 //XXX:TEST 402 //strncpy(nbd_devices[i].target, "127.0.0.1:1337", 64); 403 //XXX:parse it 404 nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in); 405 nbd_devices[i].server.sin_family = AF_INET; 406 nbd_devices[i].server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 407 nbd_devices[i].server.sin_port = htons(1337 + i); 408 } 409 } 410 /*should parse as a tree: 411 settings = get_driver_settings(handle); 412 for (i = 0; i < settings->parameter_count; i++) { 413 414 } 415 */ 416 417 unload_driver_settings(handle); 418 } 419 420 return B_OK; 421 } 422 423 void 424 uninit_driver (void) 425 { 426 status_t err; 427 int i; 428 PRINT((DP ">%s()\n", __FUNCTION__)); 429 for (i = 0; i < MAX_NBDS; i++) { 430 free(nbd_name[i]); 431 err = benaphore_destroy(&nbd_devices[i].ben); 432 } 433 err = ksocket_cleanup(); 434 /* HACK */ 435 if (gDelayUnload) 436 snooze(BONE_TEARDOWN_DELAY); 437 } 438 439 const char** 440 publish_devices() 441 { 442 PRINT((DP ">%s()\n", __FUNCTION__)); 443 return nbd_name; 444 } 445 446 device_hooks* 447 find_device(const char* name) 448 { 449 PRINT((DP ">%s(%s)\n", __FUNCTION__, name)); 450 return &nbd_hooks; 451 } 452 453 struct nbd_device* 454 nbd_find_device(const char* name) 455 { 456 int i; 457 PRINT((DP ">%s(%s)\n", __FUNCTION__, name)); 458 for (i = 0; i < MAX_NBDS; i++) { 459 if (!strcmp(nbd_name[i], name)) 460 return &nbd_devices[i]; 461 } 462 return NULL; 463 } 464