*** empty log message ***
[arla.git] / arlad / nnpfs.c
blob7295a4484c4e52574216b05f4f3ca6b38696ef1e
1 /*
2 * Copyright (c) 1999 - 2002, 2004-2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "arla_local.h"
36 RCSID("$Id$");
39 * Begining of breakout of nnpfs releated junk
42 static u_int *seqnums;
44 static List *sleepers;
46 /* number of times each type of message has been sent/recv */
48 static struct {
49 unsigned long sent;
50 unsigned long recv;
51 } nnpfs_stats[NNPFS_MSG_COUNT];
53 static const char *rcvfuncs_name[] =
55 "version",
56 "wakeup",
57 "getroot",
58 "installroot",
59 "getnode",
60 "installnode",
61 "getattr",
62 "installattr",
63 "getdata",
64 "installdata",
65 "inactivenode",
66 "invalidnode",
67 "open",
68 "put_data",
69 "put_attr",
70 "create",
71 "mkdir",
72 "link",
73 "symlink",
74 "remove",
75 "rmdir",
76 "rename",
77 "pioctl",
78 "updatefid",
79 "advlock",
80 "gc",
81 "delete node",
82 "appenddata",
83 "deletedata",
84 "accesses",
85 "installquota"
89 * An interface for the userland to talk to the kernel and recv back
90 * an integer. For larger messages implement a similar function that
91 * uses the `wakeup' message with data.
94 int
95 nnpfs_message_rpc (int fd, struct nnpfs_message_header *h, u_int size)
97 int ret;
99 ret = nnpfs_message_send (fd, h, size);
100 if (ret)
101 return ret;
102 return nnpfs_message_sleep (h->sequence_num);
106 * Try to probe the version on `fd', returning the version.
109 static int
110 nnpfs_send_message_version (int fd)
112 struct nnpfs_message_version msg;
113 int ret;
115 msg.header.opcode = NNPFS_MSG_VERSION;
116 msg.version = NNPFS_VERSION;
117 msg.blocksize = fcache_getblocksize();
118 msg.appendquota = fcache_set_appendquota();
119 arla_warnx (ADEBMSG, "sending version");
120 ret = nnpfs_message_rpc (fd, (struct nnpfs_message_header *)&msg,
121 sizeof(msg));
122 return ret;
126 * Probe for version on `fd'. Fail if != version
129 void
130 nnpfs_probe_version (int fd, int version)
132 int ret = nnpfs_send_message_version (fd);
134 if (ret != version)
135 arla_errx (1, ADEBERROR,
136 "Version mismatch. Nnpfs is version %d and arlad is version %d. Please {up,down}grade.",
137 ret, version);
141 * Send `num' `blocks' to nnpfs on `fd' as proposed gc-able blocks
142 * If `num' is 0 nnpfs should gc everything gc:able.
145 void
146 nnpfs_send_message_gc (int fd, struct nnpfs_message_gc *msg, int num)
148 arla_warnx (ADEBMSG,
149 "nnpfs_send_message_gc sending gc: num = %d", num);
151 if (num > NNPFS_GC_MAX_HANDLE)
152 num = NNPFS_GC_MAX_HANDLE;
154 msg->header.opcode = NNPFS_MSG_GC;
155 msg->len = num;
157 nnpfs_message_send(fd, (struct nnpfs_message_header *)msg,
158 sizeof(*msg));
162 * Init the nnpfs message passing things.
165 void
166 nnpfs_message_init (void)
168 unsigned i;
170 seqnums = (u_int *)malloc (sizeof (*seqnums) * getdtablesize ());
171 if (seqnums == NULL)
172 arla_err (1, ADEBERROR, errno, "nnpfs_message_init: malloc");
173 for (i = 0; i < getdtablesize (); ++i)
174 seqnums[i] = 0;
175 sleepers = listnew ();
176 if (sleepers == NULL)
177 arla_err (1, ADEBERROR, errno, "nnpfs_message_init: listnew");
179 assert (sizeof(rcvfuncs_name) / sizeof(*rcvfuncs_name) == NNPFS_MSG_COUNT);
183 * Go to entry in jump-table depending on entry.
187 nnpfs_message_receive (int fd, struct nnpfs_message_header *h, u_int size)
189 unsigned opcode = h->opcode;
191 if (opcode >= NNPFS_MSG_COUNT || rcvfuncs[opcode] == NULL ) {
192 arla_warnx (ADEBMSG, "Bad message opcode = %u", opcode);
193 return -1;
196 ++nnpfs_stats[opcode].recv;
198 arla_warnx (ADEBMSG, "Rec message: opcode = %u (%s), size = %u",
199 opcode, rcvfuncs_name[opcode], h->size);
201 return (*rcvfuncs[opcode])(fd, h, size);
205 * Send a message to the kernel module.
209 nnpfs_message_send (int fd, struct nnpfs_message_header *h, u_int size)
211 unsigned opcode = h->opcode;
212 int ret;
214 h->size = size;
215 h->sequence_num = seqnums[fd]++;
217 if (opcode >= NNPFS_MSG_COUNT) {
218 arla_warnx (ADEBMSG, "Bad message opcode = %u", opcode);
219 return -1;
222 ++nnpfs_stats[opcode].sent;
224 arla_warnx (ADEBMSG, "Send message: opcode = %u (%s), size = %u",
225 opcode, rcvfuncs_name[opcode], h->size);
227 ret = kern_write (fd, h, size);
228 if (ret != size) {
229 arla_warn (ADEBMSG, errno, "nnpfs_message_send: write");
230 return errno;
231 } else
232 return 0;
236 * This code can only wake up message of type `nnpfs_message_wakeup'
237 * without data
241 nnpfs_message_wakeup (int fd, struct nnpfs_message_wakeup *h, u_int size)
243 Listitem *i, *next;
244 struct nnpfs_message_wakeup *w;
246 assert (sizeof(*w) >= size);
248 for (i = listhead (sleepers); i; i = next) {
249 next = listnext (sleepers, i);
250 w = (struct nnpfs_message_wakeup *)listdata(i);
251 if (w->header.sequence_num == h->sleepers_sequence_num) {
252 listdel (sleepers, i);
253 memcpy (w, h, size);
254 LWP_SignalProcess ((char *)w);
255 break;
258 if (i == NULL)
259 arla_warnx (ADEBWARN, "nnpfs_message_wakeup: no message to wakeup!");
260 return 0;
264 * The middle and last part of the nnpfs_message_rpc.
268 nnpfs_message_sleep (u_int seqnum)
270 struct nnpfs_message_wakeup h;
272 h.header.sequence_num = seqnum;
274 listaddtail (sleepers, &h);
275 LWP_WaitProcess ((char *)&h);
276 return h.error;
280 * Wake up a sleeping kernel-thread that sleeps on `seqnum'
281 * and pass on `error' as an error to the thread.
285 nnpfs_send_message_wakeup (int fd, u_int seqnum, int error)
287 struct nnpfs_message_wakeup msg;
289 msg.header.opcode = NNPFS_MSG_WAKEUP;
290 msg.sleepers_sequence_num = seqnum;
291 msg.error = error;
292 msg.len = 0;
293 arla_warnx (ADEBMSG, "sending wakeup: seq = %u, error = %d",
294 seqnum, error);
295 return nnpfs_message_send (fd, (struct nnpfs_message_header *)&msg,
296 sizeof(msg));
301 * Wake-up a kernel-thread with `seqnum', and pass on `error'
302 * and return value. Add also a data blob for generic use.
306 nnpfs_send_message_wakeup_data (int fd, u_int seqnum, int error,
307 void *data, int size)
309 struct nnpfs_message_wakeup *msg;
310 int allocsize;
312 arla_warnx (ADEBMSG,
313 "sending wakeup: seq = %u, error = %d", seqnum, error);
315 if (size > NNPFS_MSG_MAX_DATASIZE) {
316 arla_warnx(ADEBWARN, "sending wakeup: seq = %u, bad size %d",
317 seqnum, size);
318 return EINVAL;
321 allocsize = sizeof(*msg) + size;
322 msg = malloc(allocsize);
323 if (!msg) {
324 arla_warnx(ADEBERROR, "sending wakeup: malloc failed");
325 return ENOMEM;
328 msg->header.opcode = NNPFS_MSG_WAKEUP;
329 msg->sleepers_sequence_num = seqnum;
330 msg->error = error;
331 msg->len = size;
333 if (size != 0)
334 memcpy(msg->msg, data, size);
336 return nnpfs_message_send (fd, (struct nnpfs_message_header *)msg,
337 allocsize);
344 struct write_buf {
345 unsigned char buf[NNPFS_MAX_MSG_SIZE];
346 size_t len;
350 * Return 1 it buf is full, 0 if it's not.
353 static int
354 add_new_msg (int fd,
355 struct nnpfs_message_header *h, size_t size,
356 struct write_buf *buf)
358 /* align on 8 byte boundery */
360 if (size > sizeof (buf->buf) - buf->len)
361 return 1;
363 h->sequence_num = seqnums[fd]++;
364 h->size = (size + 8) & ~ 7;
366 assert (h->opcode >= 0 && h->opcode < NNPFS_MSG_COUNT);
367 ++nnpfs_stats[h->opcode].sent;
369 arla_warnx (ADEBMSG, "Multi-send: opcode = %u (%s), size = %u",
370 h->opcode, rcvfuncs_name[h->opcode], h->size);
372 memcpy (buf->buf + buf->len, h, size);
373 memset (buf->buf + buf->len + size, 0, h->size - size);
374 buf->len += h->size;
375 return 0;
379 * Blast of a `buf' to `fd'.
382 static int
383 send_msg (int fd, struct write_buf *buf)
385 int ret;
387 if (buf->len == 0)
388 return 0;
390 ret = kern_write (fd, buf->buf, buf->len);
391 if (ret != buf->len) {
392 arla_warn (ADEBMSG, errno,
393 "send_msg: write");
394 buf->len = 0;
395 return errno;
397 buf->len = 0;
398 return 0;
406 nnpfs_send_message_vmultiple (int fd,
407 va_list args)
409 struct nnpfs_message_header *h;
410 struct write_buf *buf;
411 size_t size;
412 int ret;
414 buf = malloc (sizeof (*buf));
415 if (buf == NULL)
416 return ENOMEM;
418 h = va_arg (args, struct nnpfs_message_header *);
419 size = va_arg (args, size_t);
420 buf->len = 0;
421 while (h != NULL) {
422 if (add_new_msg (fd, h, size, buf)) {
423 ret = send_msg (fd, buf);
424 if (ret) {
425 free (buf);
426 return ret;
428 if (add_new_msg (fd, h, size, buf))
429 arla_warnx (ADEBERROR,
430 "nnpfs_send_message_vmultiple: "
431 "add_new_msg failed");
434 h = va_arg (args, struct nnpfs_message_header *);
435 size = va_arg (args, size_t);
437 ret = send_msg (fd, buf);
438 free (buf);
439 return ret;
443 * Same as above but different.
447 nnpfs_send_message_multiple (int fd, ...)
449 va_list args;
450 int ret;
452 va_start (args, fd);
453 ret = nnpfs_send_message_vmultiple (fd, args);
454 va_end (args);
455 return ret;
459 * Almost same as above but different.
463 nnpfs_send_message_multiple_list (int fd,
464 struct nnpfs_message_header *h,
465 size_t size,
466 u_int num)
468 struct write_buf *buf;
469 int ret = 0;
471 buf = malloc (sizeof (*buf));
472 if (buf == NULL)
473 return ENOMEM;
474 buf->len = 0;
475 while (num && ret == 0) {
476 if (add_new_msg (fd, h, size, buf)) {
477 ret = send_msg (fd, buf);
478 if (add_new_msg (fd, h, size, buf))
479 arla_warnx (ADEBERROR,
480 "nnpfs_send_message_multiple_list: "
481 "add_new_msg failed");
483 h = (struct nnpfs_message_header *) (((unsigned char *)h) + size);
484 num--;
486 if (ret) {
487 free (buf);
488 return ret;
490 ret = send_msg (fd, buf);
491 free (buf);
492 return ret;
496 * Send multiple message to the kernel (for performace/simplicity resons)
500 nnpfs_send_message_wakeup_vmultiple (int fd,
501 u_int seqnum,
502 int error,
503 va_list args)
505 struct nnpfs_message_wakeup msg;
506 int ret;
508 ret = nnpfs_send_message_vmultiple (fd, args);
509 if (ret)
510 arla_warnx (ADEBERROR, "nnpfs_send_message_wakeup_vmultiple: "
511 "failed sending messages with error %d", ret);
513 msg.header.opcode = NNPFS_MSG_WAKEUP;
514 msg.header.size = sizeof(msg);
515 msg.header.sequence_num = seqnums[fd]++;
516 msg.sleepers_sequence_num = seqnum;
517 msg.error = error;
518 msg.len = 0;
520 ++nnpfs_stats[NNPFS_MSG_WAKEUP].sent;
522 arla_warnx (ADEBMSG, "multi-sending wakeup: seq = %u, error = %d",
523 seqnum, error);
525 ret = kern_write (fd, &msg, sizeof(msg));
526 if (ret != sizeof(msg)) {
527 arla_warn (ADEBMSG, errno,
528 "nnpfs_send_message_wakeup_vmultiple: writev");
529 return -1;
531 return 0;
535 * Same as above but different.
539 nnpfs_send_message_wakeup_multiple (int fd,
540 u_int seqnum,
541 int error,
542 ...)
544 va_list args;
545 int ret;
547 va_start (args, error);
548 ret = nnpfs_send_message_wakeup_vmultiple (fd, seqnum, error, args);
549 va_end (args);
550 return ret;