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 #ifdef __HAIKU__ 20 #include <kernel/lock.h> 21 #else 22 /* wrappers */ 23 #ifndef _IMPEXP_KERNEL 24 #define _IMPEXP_KERNEL 25 #endif 26 #include "lock.h" 27 #define benaphore lock 28 #define benaphore_init new_lock 29 #define benaphore_destroy free_lock 30 #define benaphore_lock LOCK 31 #define benaphore_unlock UNLOCK 32 #endif 33 34 #include "nbd.h" 35 36 #define DRV "nbd" 37 #define D "nbd:" 38 #define MAX_NBDS 4 39 #define DEVICE_PREFIX "disk/virtual/nbd/" 40 #define DEVICE_FMT DEVICE_PREFIX "%2d/raw" 41 #define DEVICE_NAME_MAX 32 42 #define MAX_REQ_SIZE (32*1024*1024) 43 44 struct nbd_request_entry { 45 struct nbd_request_entry *next; 46 struct nbd_request req; 47 bool r; /* is read */ 48 size_t len; 49 void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */ 50 }; 51 52 struct nbd_device { 53 char target[64]; // "ip:port" 54 struct sockaddr_in server; 55 benaphore ben; 56 vint32 refcnt; 57 uint64 req; /* next ID for requests */ 58 int sock; 59 thread_id postoffice; 60 uint64 size; 61 struct nbd_request_entry *reqs; 62 }; 63 64 typedef struct cookie { 65 struct nbd_device *dev; 66 67 } cookie_t; 68 69 /* data=NULL on read */ 70 status_t nbd_alloc_request(struct nbd_device, struct nbd_request_entry **req, size_t len, const char *data); 71 status_t nbd_post_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); 72 status_t nbd_dequeue_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); 73 status_t nbd_free_request(struct nbd_device, struct nbd_request_entry *req); 74 75 struct nbd_device *nbd_find_device(const char* name); 76 77 KSOCKET_MODULE_DECL; 78 79 #pragma mark ==== request manager ==== 80 81 82 #pragma mark ==== nbd handler ==== 83 84 int32 postoffice(void *arg) 85 { 86 struct nbd_device *dev = (struct nbd_device *)arg; 87 int sock = dev->sock; 88 89 90 91 return 0; 92 } 93 94 status_t nbd_connect(struct nbd_device *dev) 95 { 96 97 return B_OK; 98 } 99 100 status_t nbd_teardown(struct nbd_device *dev) 101 { 102 close(dev->sock); 103 return B_OK; 104 } 105 106 #pragma mark ==== device hooks ==== 107 108 static struct nbd_device nbd_devices[MAX_NBDS]; 109 110 status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie) { 111 status_t err; 112 struct nbd_device *dev = NULL; 113 (void)name; (void)flags; 114 dev = nbd_find_device(name); 115 if (!dev) 116 return ENOENT; 117 err = ENOMEM; 118 *cookie = (void*)malloc(sizeof(cookie_t)); 119 if (*cookie == NULL) 120 goto err0; 121 memset(*cookie, 0, sizeof(cookie_t)); 122 (*cookie)->dev = dev; 123 err = benaphore_lock(&dev->ben); 124 if (err) 125 goto err1; 126 /* */ 127 if (dev->sock < 0) 128 err = nbd_connect(dev); 129 if (err) 130 goto err2; 131 dev->refcnt++; 132 benaphore_unlock(&dev->ben); 133 return B_OK; 134 135 err2: 136 benaphore_unlock(&dev->ben); 137 err1: 138 free(*cookie); 139 err0: 140 dprintf("nbd_open : error 0x%08lx\n", err); 141 return err; 142 } 143 144 status_t nbd_close(cookie_t *cookie) { 145 struct nbd_device *dev = cookie->dev; 146 status_t err; 147 148 err = benaphore_lock(&dev->ben); 149 if (err) 150 return err; 151 152 // XXX: do something ? 153 154 benaphore_unlock(&dev->ben); 155 return B_OK; 156 } 157 158 status_t nbd_free(cookie_t *cookie) { 159 struct nbd_device *dev = cookie->dev; 160 status_t err; 161 162 err = benaphore_lock(&dev->ben); 163 if (err) 164 return err; 165 166 if (--dev->refcnt == 0) { 167 err = nbd_teardown(dev); 168 } 169 170 benaphore_unlock(&dev->ben); 171 172 free(cookie); 173 return err; 174 } 175 176 status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) { 177 switch (op) { 178 case B_GET_DEVICE_SIZE: /* this one is broken anyway... */ 179 if (data) { 180 *(size_t *)data = (size_t)cookie->dev->size; 181 return B_OK; 182 } 183 return EINVAL; 184 case B_SET_DEVICE_SIZE: /* broken */ 185 return EINVAL; 186 case B_SET_NONBLOCKING_IO: 187 return EINVAL; 188 case B_SET_BLOCKING_IO: 189 return B_OK; 190 case B_GET_READ_STATUS: 191 case B_GET_WRITE_STATUS: 192 if (data) { 193 *(bool *)data = false; 194 return B_OK; 195 } 196 return EINVAL; 197 case B_GET_GEOMETRY: 198 case B_GET_BIOS_GEOMETRY: 199 if (data) { 200 device_geometry *geom = (device_geometry *)data; 201 geom->bytes_per_sector = 256; 202 geom->sectors_per_track = 1; 203 geom->cylinder_count = cookie->dev->size / 256; 204 geom->head_count = 1; 205 geom->device_type = B_DISK; 206 geom->removable = false; 207 geom->read_only = false; // XXX 208 geom->write_once = false; 209 return B_OK; 210 } 211 return EINVAL; 212 case B_GET_MEDIA_STATUS: 213 if (data) { 214 *(status_t *)data = B_OK; 215 return B_OK; 216 } 217 return EINVAL; 218 219 case B_EJECT_DEVICE: 220 case B_LOAD_MEDIA: 221 return ENOSYS; 222 case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */ 223 default: 224 return ENOSYS; 225 } 226 return B_NOT_ALLOWED; 227 } 228 229 status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) { 230 *numbytes = 0; 231 return B_NOT_ALLOWED; 232 } 233 234 status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) { 235 (void)cookie; (void)position; (void)data; (void)numbytes; 236 *numbytes = 0; 237 return EIO; 238 } 239 240 device_hooks nbd_hooks={ 241 (device_open_hook)nbd_open, 242 nbd_close, 243 (device_free_hook)nbd_free, 244 (device_control_hook)nbd_control, 245 (device_read_hook)nbd_read, 246 (device_write_hook)nbd_write, 247 NULL, 248 NULL, 249 NULL, 250 NULL 251 }; 252 253 254 #pragma mark ==== driver hooks ==== 255 256 static const char *nbd_name[MAX_NBDS+1] = { 257 NULL 258 }; 259 260 status_t 261 init_hardware (void) 262 { 263 return B_OK; 264 } 265 266 status_t 267 init_driver (void) 268 { 269 status_t err; 270 int i, j; 271 // XXX: load settings 272 void *handle; 273 274 err = ksocket_init(); 275 if (err < B_OK) 276 return err; 277 278 for (i = 0; i < MAX_NBDS; i++) { 279 memset(nbd_devices[i].target, 0, 64); 280 err = benaphore_init(&nbd_devices[i].ben, "nbd lock"); 281 if (err < B_OK) 282 return err; // XXX 283 nbd_devices[i].refcnt = 0; 284 nbd_devices[i].req = 0LL; /* next ID for requests */ 285 nbd_devices[i].sock = -1; 286 nbd_devices[i].postoffice = -1; 287 nbd_devices[i].size = 0LL; 288 nbd_devices[i].reqs = NULL; 289 nbd_name[i] = malloc(DEVICE_NAME_MAX); 290 if (nbd_name[i] == NULL) 291 break; 292 sprintf(nbd_name[i], DEVICE_FMT, i); 293 // XXX: init nbd_devices[i] 294 } 295 nbd_name[i] = NULL; 296 297 handle = load_driver_settings(DRV); 298 if (handle) { 299 for (i = 0; i < MAX_NBDS; i++) { 300 char keyname[10]; 301 char *v; 302 sprintf(keyname, "nbd%d", i); 303 v = get_driver_parameter(handle, keyname, NULL, NULL); 304 /* should be "ip:port" */ 305 // XXX: test 306 if (v || 0) { 307 //strncpy(nbd_devices[i].target, v, 64); 308 //XXX:TEST 309 //strncpy(nbd_devices[i].target, "127.0.0.1:1337", 64); 310 //XXX:parse it 311 nbd_devices[i].server.sin_len = sizeof(struct sockaddr_in); 312 nbd_devices[i].server.sin_family = AF_INET; 313 nbd_devices[i].server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 314 nbd_devices[i].server.sin_port = htons(1337 + i); 315 } 316 } 317 /*should parse as a tree: 318 settings = get_driver_settings(handle); 319 for (i = 0; i < settings->parameter_count; i++) { 320 321 } 322 */ 323 324 unload_driver_settings(handle); 325 } 326 327 return B_OK; 328 } 329 330 void 331 uninit_driver (void) 332 { 333 status_t err; 334 int i; 335 for (i = 0; i < MAX_NBDS; i++) { 336 free(nbd_name[i]); 337 err = benaphore_destroy(&nbd_devices[i].ben); 338 } 339 err = ksocket_cleanup(); 340 } 341 342 const char** 343 publish_devices() 344 { 345 return nbd_name; 346 } 347 348 device_hooks* 349 find_device(const char* name) 350 { 351 return &nbd_hooks; 352 } 353 354 struct nbd_device* 355 nbd_find_device(const char* name) 356 { 357 int i; 358 for (i = 0; i < MAX_NBDS; i++) { 359 if (!strcmp(nbd_name[i], name)) 360 return &nbd_devices[i]; 361 } 362 return NULL; 363 } 364