xref: /haiku/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c (revision 771c6b9355a78129a5f0532a318c62889d978153)
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