use a cell that actually exists
[arla.git] / arlad / messages.c
blobb9751c9df6d4b17bab43ad4b7f5b01b8e063e9a4
1 /*
2 * Copyright (c) 1995-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"
35 RCSID("$Id$");
37 #include <nnpfs/nnpfs_message.h>
39 #include "messages.h"
41 static int
42 nnpfs_message_getroot (int, struct nnpfs_message_getroot*, u_int);
44 static int
45 nnpfs_message_getnode (int, struct nnpfs_message_getnode*, u_int);
47 static int
48 nnpfs_message_getattr (int, struct nnpfs_message_getattr*, u_int);
50 static int
51 nnpfs_message_open (int, struct nnpfs_message_open*, u_int);
53 static int
54 nnpfs_message_getdata (int, struct nnpfs_message_getdata*, u_int);
56 static int
57 nnpfs_message_inactivenode (int,struct nnpfs_message_inactivenode*,u_int);
59 static int
60 nnpfs_message_putdata (int fd, struct nnpfs_message_putdata *h, u_int size);
62 static int
63 nnpfs_message_putattr (int fd, struct nnpfs_message_putattr *h, u_int size);
65 static int
66 nnpfs_message_create (int fd, struct nnpfs_message_create *h, u_int size);
68 static int
69 nnpfs_message_mkdir (int fd, struct nnpfs_message_mkdir *h, u_int size);
71 static int
72 nnpfs_message_link (int fd, struct nnpfs_message_link *h, u_int size);
74 static int
75 nnpfs_message_symlink (int fd, struct nnpfs_message_symlink *h, u_int size);
77 static int
78 nnpfs_message_remove (int fd, struct nnpfs_message_remove *h, u_int size);
80 static int
81 nnpfs_message_rmdir (int fd, struct nnpfs_message_rmdir *h, u_int size);
83 static int
84 nnpfs_message_rename (int fd, struct nnpfs_message_rename *h, u_int size);
86 static int
87 nnpfs_message_pioctl (int fd, struct nnpfs_message_pioctl *h, u_int size) ;
89 static int
90 nnpfs_message_appenddata (int,struct nnpfs_message_appenddata *h, u_int size);
92 static int
93 nnpfs_message_deletedata (int,struct nnpfs_message_deletedata *h, u_int size);
95 static int
96 nnpfs_message_accesses (int,struct nnpfs_message_accesses *h, u_int size);
98 static nnpfs_rights
99 afsrights2nnpfsrights(u_long, uint32_t, uint32_t);
101 static int
102 possibly_have_network(void);
108 nnpfs_message_function rcvfuncs[] = {
109 NULL, /* version */
110 (nnpfs_message_function)nnpfs_message_wakeup, /* wakeup */
111 (nnpfs_message_function)nnpfs_message_getroot, /* getroot */
112 NULL, /* installroot */
113 (nnpfs_message_function)nnpfs_message_getnode, /* getnode */
114 NULL, /* installnode */
115 (nnpfs_message_function)nnpfs_message_getattr, /* getattr */
116 NULL, /* installattr */
117 (nnpfs_message_function)nnpfs_message_getdata, /* getdata */
118 NULL, /* installdata */
119 (nnpfs_message_function)nnpfs_message_inactivenode, /* inactivenode */
120 NULL, /* invalidnode */
121 (nnpfs_message_function)nnpfs_message_open, /* open */
122 (nnpfs_message_function)nnpfs_message_putdata, /* put_data */
123 (nnpfs_message_function)nnpfs_message_putattr, /* put attr */
124 (nnpfs_message_function)nnpfs_message_create, /* create */
125 (nnpfs_message_function)nnpfs_message_mkdir, /* mkdir */
126 (nnpfs_message_function)nnpfs_message_link, /* link */
127 (nnpfs_message_function)nnpfs_message_symlink, /* symlink */
128 (nnpfs_message_function)nnpfs_message_remove, /* remove */
129 (nnpfs_message_function)nnpfs_message_rmdir, /* rmdir */
130 (nnpfs_message_function)nnpfs_message_rename, /* rename */
131 (nnpfs_message_function)nnpfs_message_pioctl, /* pioctl */
132 NULL, /* updatefid */
133 NULL, /* advlock */
134 NULL, /* gc nodes */
135 NULL, /* delete node */
136 (nnpfs_message_function)nnpfs_message_appenddata, /* appenddata */
137 (nnpfs_message_function)nnpfs_message_deletedata, /* deletedata */
138 (nnpfs_message_function)nnpfs_message_accesses /* accesses */
142 #if 0
143 /* number of prefetches currently in progress */
144 static int num_prefetches = 0;
145 #endif
147 /* maximum number of concurrent prefetches */
148 static int max_prefetches;
151 * init.
154 void
155 message_init(void)
157 max_prefetches = kernel_highworkers() - 2; /* XXX should be configurable */
164 long
165 afsfid2inode (const VenusFid *fid)
167 return ((fid->fid.Volume & 0x7FFF) << 16 | (fid->fid.Vnode & 0xFFFFFFFF));
171 * AFSFetchStatus -> nnpfs_attr
172 * Setting everything except for length and mode.
175 static void
176 afsstatus2nnpfs_attr (AFSFetchStatus *status,
177 const VenusFid *fid,
178 struct nnpfs_attr *attr,
179 int flags)
181 int mode;
183 attr->valid = XA_V_NONE;
184 switch (status->FileType) {
185 case TYPE_FILE :
186 mode = S_IFREG;
187 XA_SET_TYPE(attr, NNPFS_FILE_REG);
188 break;
189 case TYPE_DIR :
190 mode = S_IFDIR;
191 XA_SET_TYPE(attr, NNPFS_FILE_DIR);
192 break;
193 case TYPE_LINK :
194 mode = S_IFLNK;
195 XA_SET_TYPE(attr, NNPFS_FILE_LNK);
196 break;
197 default :
198 arla_warnx (ADEBMSG, "afsstatus2nnpfs_attr: default");
199 abort ();
201 XA_SET_NLINK(attr, status->LinkCount);
202 if (flags & FCACHE2NNPFSNODE_LENGTH)
203 XA_SET_SIZE(attr, fcache_get_status_length(status));
204 XA_SET_UID(attr,status->Owner);
205 XA_SET_GID(attr, status->Group);
206 XA_SET_ATIME(attr, status->ClientModTime);
207 XA_SET_MTIME(attr, status->ClientModTime);
208 XA_SET_CTIME(attr, status->ClientModTime);
209 XA_SET_FILEID(attr, afsfid2inode(fid));
211 /* XXX this is wrong, need to keep track of `our` ae for this req */
212 if (fake_stat) {
213 nnpfs_rights rights;
215 rights = afsrights2nnpfsrights(status->CallerAccess,
216 status->FileType,
217 status->UnixModeBits);
219 if (rights & NNPFS_RIGHT_R)
220 mode |= 0444;
221 if (rights & NNPFS_RIGHT_W)
222 mode |= 0222;
223 if (rights & NNPFS_RIGHT_X)
224 mode |= 0111;
225 } else
226 mode |= status->UnixModeBits;
228 XA_SET_MODE(attr, mode);
232 * Transform `access', `FileType' and `UnixModeBits' into rights.
234 * There are different transformations for directories and files to be
235 * compatible with the Transarc client.
238 static nnpfs_rights
239 afsrights2nnpfsrights(u_long ar, uint32_t FileType, uint32_t UnixModeBits)
241 nnpfs_rights ret = 0;
243 if (FileType == TYPE_DIR) {
244 if (ar & ALIST)
245 ret |= NNPFS_RIGHT_R | NNPFS_RIGHT_X;
246 if (ar & (AINSERT | ADELETE))
247 ret |= NNPFS_RIGHT_W;
248 } else {
250 * If its a file, and the AADMIN bit is set, we are the owner
251 * of the file. Now we really want to know if we had AINSERT
252 * the bits on the directory, but since we don't know that
253 * here, lets just punt and let the fileserver tell us later
254 * if we guess right. Give read and write to ourself for now.
256 if (FileType == TYPE_FILE && (ar & AADMIN))
257 ret |= NNPFS_RIGHT_R|NNPFS_RIGHT_W;
259 * Clients can read symlink in directories where they only
260 * have ALIST (l) rights.
262 if (FileType == TYPE_LINK && (ar & ALIST))
263 ret |= NNPFS_RIGHT_R;
265 * Match RWX to AREAD+R, AWRITE+W, AREAD+X
267 if ((ar & AREAD) && (UnixModeBits & S_IRUSR))
268 ret |= NNPFS_RIGHT_R;
269 if ((ar & AWRITE) && (UnixModeBits & S_IWUSR))
270 ret |= NNPFS_RIGHT_W;
271 if ((ar & AREAD) && (UnixModeBits & S_IXUSR))
272 ret |= NNPFS_RIGHT_X;
275 if (ar & AREAD)
276 ret |= NNPFS_RIGHT_AR;
277 if (ar & AWRITE)
278 ret |= NNPFS_RIGHT_AW;
279 if (ar & ALIST)
280 ret |= NNPFS_RIGHT_AL;
281 if (ar & AINSERT)
282 ret |= NNPFS_RIGHT_AI;
283 if (ar & ADELETE)
284 ret |= NNPFS_RIGHT_AD;
285 if (ar & ALOCK)
286 ret |= NNPFS_RIGHT_AK;
287 if (ar & AADMIN)
288 ret |= NNPFS_RIGHT_AA;
290 return ret;
293 void
294 fcacheentry2nnpfsnode (const VenusFid *fid,
295 const VenusFid *statfid,
296 AFSFetchStatus *status,
297 struct nnpfs_msg_node *node,
298 AccessEntry *ae,
299 int flags)
301 int i;
303 memcpy (&node->handle, fid, sizeof(*fid));
305 afsstatus2nnpfs_attr (status, statfid, &node->attr, flags);
307 node->anonrights = afsrights2nnpfsrights(status->AnonymousAccess,
308 status->FileType,
309 status->UnixModeBits);
310 for (i = 0; i < NACCESS; i++) {
311 node->id[i] = ae[i].cred;
312 node->rights[i] = afsrights2nnpfsrights(ae[i].access,
313 status->FileType,
314 status->UnixModeBits);
319 * convert `xa' into `storestatus'
323 nnpfs_attr2afsstorestatus(struct nnpfs_attr *xa,
324 AFSStoreStatus *storestatus)
326 int mask = 0;
328 if (XA_VALID_MODE(xa)) {
329 storestatus->UnixModeBits = xa->xa_mode;
330 mask |= SS_MODEBITS;
332 if (XA_VALID_UID(xa)) {
333 storestatus->Owner = xa->xa_uid;
334 mask |= SS_OWNER;
336 if (XA_VALID_GID(xa)) {
337 storestatus->Group = xa->xa_gid;
338 mask |= SS_GROUP;
340 if (XA_VALID_MTIME(xa)) {
341 storestatus->ClientModTime = xa->xa_mtime;
342 mask |= SS_MODTIME;
344 storestatus->Mask = mask;
346 /* SS_SegSize */
347 storestatus->SegSize = 0;
348 return 0;
352 * Convert an AFSFetchStatus to AFSStoreStatus
355 void
356 afsstatus2afsstorestatus(AFSFetchStatus *fetchstatus,
357 AFSStoreStatus *storestatus)
359 storestatus->UnixModeBits = fetchstatus->UnixModeBits;
360 storestatus->Owner = fetchstatus->Owner;
361 storestatus->Group = fetchstatus->Group;
362 storestatus->ClientModTime = fetchstatus->ClientModTime;
364 storestatus->Mask = SS_MODEBITS | SS_OWNER | SS_GROUP | SS_MODTIME;
366 storestatus->SegSize = 0;
370 * get new CredCacheEntry, for bad connections.
373 static void
374 retry_cred(CredCacheEntry **ce, nnpfs_cred *cred)
376 int32_t cell = (*ce)->cell;
378 conn_clearcred(CONN_CS_CRED|CONN_CS_SECIDX, 0, cred->pag, 2);
379 cred_expire(*ce);
380 cred_free(*ce);
381 *ce = cred_get(cell, cred->pag, CRED_ANY);
382 assert(*ce);
386 * Return true iff we should retry the operation.
387 * Also replace `ce' with anonymous creds in case it has expired.
389 * There must not be passed in any NULL pointers.
392 static int
393 try_again (int *ret, CredCacheEntry **ce, nnpfs_cred *cred, const VenusFid *fid)
395 switch (*ret) {
396 #ifdef KERBEROS
397 case RXKADEXPIRED :
398 case RXKADBADTICKET:
399 case RXKADBADKEY:
400 case RXKADUNKNOWNKEY:
401 retry_cred(ce, cred);
402 return TRUE;
403 case RXKADSEALEDINCON :
404 arla_warnx_with_fid (ADEBWARN, fid,
405 "seal error");
406 *ret = EINVAL;
407 return FALSE;
408 #endif
409 case ARLA_VSALVAGE :
410 *ret = EIO;
411 return FALSE;
412 case ARLA_VNOVNODE :
413 *ret = ENOENT;
414 return FALSE;
415 case ARLA_VMOVED :
416 case ARLA_VNOVOL :
417 if (fid && !volcache_reliablep (fid->fid.Volume, fid->Cell)) {
418 return TRUE;
419 } else {
420 *ret = ENOENT;
421 return FALSE;
423 case ARLA_VOFFLINE :
424 *ret = ENETDOWN;
425 return FALSE;
426 case ARLA_VDISKFULL :
427 *ret = ENOSPC;
428 return FALSE;
429 case ARLA_VOVERQUOTA:
430 #ifdef EDQUOT
431 *ret = EDQUOT;
432 #else
433 *ret = ENOSPC;
434 #endif
435 return FALSE;
436 case ARLA_VBUSY :
437 arla_warnx_with_fid (ADEBWARN, fid,
438 "Waiting for busy volume...");
439 IOMGR_Sleep (afs_BusyWaitPeriod);
440 return TRUE;
441 case ARLA_VRESTARTING:
442 arla_warnx_with_fid (ADEBWARN, fid,
443 "Waiting for fileserver to restart...");
444 IOMGR_Sleep (afs_BusyWaitPeriod);
445 return TRUE;
446 case ARLA_VIO :
447 *ret = EIO;
448 return FALSE;
449 default :
450 return FALSE;
455 * try_again() for cross cell operations
458 static int
459 try_again_crosscell(int *ret, CredCacheEntry **ce, CredCacheEntry **ce2,
460 nnpfs_cred *cred, const VenusFid *fid)
462 switch (*ret) {
463 #ifdef KERBEROS
464 case RXKADEXPIRED :
465 case RXKADBADTICKET:
466 case RXKADBADKEY:
467 case RXKADUNKNOWNKEY:
468 retry_cred(ce, cred);
469 retry_cred(ce2, cred);
470 return TRUE;
471 #endif
472 default:
473 return try_again(ret, ce, cred, fid);
478 * Do some basic setup and paranoia for installattr messages.
479 * Note that we grant the node NNPFS_ATTR_R tokens here...
481 * XXX more paranoia?
484 static struct nnpfs_message_header *
485 make_installattr(struct nnpfs_message_installattr *msg,
486 FCacheEntry *entry,
487 int flags)
489 if (!entry->flags.datausedp)
490 assert((entry->tokens & NNPFS_DATA_MASK) == 0);
492 entry->tokens |= NNPFS_ATTR_R;
494 fcacheentry2nnpfsnode(&entry->fid, fcache_realfid(entry),
495 &entry->status, &msg->node,
496 entry->acccache, flags);
498 msg->header.opcode = NNPFS_MSG_INSTALLATTR;
499 msg->node.tokens = (entry->tokens & NNPFS_ATTR_MASK);
500 msg->flag = 0;
502 return (struct nnpfs_message_header *)msg;
505 #if 0
507 * Do some basic setup and paranoia for installnode messages.
508 * Note that we grant the node NNPFS_ATTR_R tokens here...
510 * XXX more paranoia?
513 static struct nnpfs_message_header *
514 make_installnode(struct nnpfs_message_installnode *msg,
515 FCacheEntry *entry,
516 const VenusFid *parent,
517 const char *name)
519 fcacheentry2nnpfsnode(&entry->fid, fcache_realfid(entry),
520 &entry->status, &msg->node,
521 entry->acccache, FCACHE2NNPFSNODE_ALL);
523 msg->header.opcode = NNPFS_MSG_INSTALLNODE;
524 /* msg->node.tokens = entry->tokens; */
525 msg->parent_handle = *parent;
526 strlcpy(msg->name, name, sizeof(msg->name));
528 return (struct nnpfs_message_header *)msg;
530 #endif
533 * Do some basic setup and paranoia for installdata messages.
535 * This could be extended to do more of the message setup.
537 * XXX I'd like some node/block flags handling (kernelp, ...) in here,
538 * but maybe they should be taken care of after the actuall install
539 * operation has completed successfully.
542 static struct nnpfs_message_header *
543 make_installdata(struct nnpfs_message_installdata *msg,
544 FCacheEntry *entry,
545 uint64_t offset,
546 uint32_t flag)
548 entry->tokens |= NNPFS_ATTR_R|NNPFS_DATA_R;
549 msg->node.tokens = (entry->tokens & (NNPFS_DATA_MASK | NNPFS_OPEN_MASK));
550 entry->flags.attrusedp = TRUE;
551 entry->flags.datausedp = TRUE;
553 fcacheentry2nnpfsnode(&entry->fid, fcache_realfid(entry),
554 &entry->status, &msg->node,
555 entry->acccache, FCACHE2NNPFSNODE_ALL);
557 msg->offset = offset;
558 msg->cache_id = entry->index;
559 msg->flag = flag;
560 msg->header.opcode = NNPFS_MSG_INSTALLDATA;
562 /* XXX we shouldn't do this until operation was successful */
563 if (offset != NNPFS_NO_OFFSET)
564 fcache_data_setkernelp(entry, offset, TRUE, FALSE);
566 return (struct nnpfs_message_header *)msg;
570 * Fetch data and retry if failing
573 static int
574 message_get_data (FCacheEntry **entry,
575 struct nnpfs_cred *cred,
576 CredCacheEntry **ce,
577 uint64_t wanted_length)
579 int ret;
580 do {
581 ret = fcache_get_data (entry, ce, 0, wanted_length);
582 } while (try_again (&ret, ce, cred, &(*entry)->fid));
583 return ret;
590 static int
591 nnpfs_message_getroot (int fd, struct nnpfs_message_getroot *h, u_int size)
593 struct nnpfs_message_installroot msg;
594 int ret = 0;
595 VenusFid root_fid;
596 CredCacheEntry *ce;
597 FCacheEntry *entry = NULL;
598 struct nnpfs_message_header *h0 = NULL;
599 size_t h0_len = 0;
600 int32_t cell_id = cell_name2num(cell_getthiscell());
602 ce = cred_get (cell_id, h->cred.pag, CRED_ANY);
603 assert (ce != NULL);
604 do {
605 ret = getroot (&root_fid, ce);
606 } while (try_again (&ret, &ce, &h->cred, &root_fid));
608 if (ret)
609 goto out;
611 ret = fcache_get(&entry, root_fid, ce);
612 if (ret)
613 goto out;
615 do {
616 ret = cm_getattr(entry, ce);
617 } while (try_again (&ret, &ce, &h->cred, &root_fid));
619 if (ret == 0) {
620 fcacheentry2nnpfsnode (&root_fid, fcache_realfid(entry),
621 &entry->status, &msg.node, entry->acccache,
622 FCACHE2NNPFSNODE_ALL);
624 entry->tokens |= NNPFS_ATTR_R;
625 msg.node.tokens = entry->tokens & ~NNPFS_DATA_MASK;
626 msg.header.opcode = NNPFS_MSG_INSTALLROOT;
627 h0 = (struct nnpfs_message_header *)&msg;
628 h0_len = sizeof(msg);
631 out:
632 nnpfs_send_message_wakeup_multiple (fd,
633 h->header.sequence_num,
634 ret,
635 h0, h0_len,
636 NULL, 0);
637 if (entry)
638 fcache_release(entry);
639 cred_free (ce);
641 return 0;
644 static int
645 nnpfs_message_getnode (int fd, struct nnpfs_message_getnode *h, u_int size)
647 struct nnpfs_message_installnode msg;
648 VenusFid *dirfid = (VenusFid *)&h->parent_handle;
649 VenusFid fid;
650 VenusFid real_fid;
651 AFSFetchStatus status;
652 CredCacheEntry *ce;
653 FCacheEntry *entry = NULL;
654 FCacheEntry *dentry = NULL;
655 struct nnpfs_message_header *h0 = NULL;
656 size_t h0_len = 0;
657 int ret;
659 arla_warnx (ADEBMSG, "getnode (%ld.%lu.%lu.%lu) \"%s\"",
660 (long)dirfid->Cell, (unsigned long)dirfid->fid.Volume,
661 (unsigned long)dirfid->fid.Vnode,
662 (unsigned long)dirfid->fid.Unique, h->name);
664 ce = cred_get (dirfid->Cell, h->cred.pag, CRED_ANY);
665 assert (ce != NULL);
667 ret = fcache_get(&dentry, *dirfid, ce);
668 if (ret)
669 goto out;
671 assert_flag(dentry,kernelp);
673 do {
674 ret = cm_lookup (&dentry, h->name, &fid, &ce, TRUE);
675 *dirfid = dentry->fid;
676 } while (try_again (&ret, &ce, &h->cred, dirfid));
678 if (ret)
679 goto out;
681 fcache_release(dentry);
682 dentry = NULL;
684 ret = fcache_get(&entry, fid, ce);
685 if (ret)
686 goto out;
688 do {
689 ret = cm_getattr(entry, ce);
690 status = entry->status;
691 real_fid = *fcache_realfid(entry);
692 } while (try_again (&ret, &ce, &h->cred, &fid));
694 if (ret == 0) {
695 fcacheentry2nnpfsnode (&fid, &real_fid, &status, &msg.node,
696 entry->acccache, FCACHE2NNPFSNODE_ALL);
698 entry->tokens |= NNPFS_ATTR_R;
699 msg.node.tokens = entry->tokens;
700 msg.parent_handle = h->parent_handle;
701 strlcpy (msg.name, h->name, sizeof(msg.name));
703 msg.header.opcode = NNPFS_MSG_INSTALLNODE;
704 h0 = (struct nnpfs_message_header *)&msg;
705 h0_len = sizeof(msg);
707 out:
708 nnpfs_send_message_wakeup_multiple (fd,
709 h->header.sequence_num,
710 ret,
711 h0, h0_len,
712 NULL, 0);
713 if (entry)
714 fcache_release(entry);
715 if (dentry)
716 fcache_release(dentry);
717 cred_free (ce);
719 return 0;
722 static int
723 nnpfs_message_getattr (int fd, struct nnpfs_message_getattr *h, u_int size)
725 struct nnpfs_message_installattr msg;
726 VenusFid fid;
727 CredCacheEntry *ce;
728 FCacheEntry *entry = NULL;
729 struct nnpfs_message_header *h0 = NULL;
730 size_t h0_len = 0;
731 int ret;
733 fid = *(VenusFid *)&h->handle;
734 arla_warnx (ADEBMSG, "getattr (%ld.%lu.%lu.%lu)",
735 (long)fid.Cell, (unsigned long)fid.fid.Volume,
736 (unsigned long)fid.fid.Vnode,
737 (unsigned long)fid.fid.Unique);
738 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
739 assert (ce != NULL);
741 ret = fcache_get(&entry, fid, ce);
742 if (ret)
743 goto out;
745 assert_flag(entry,kernelp);
747 do {
748 ret = cm_getattr(entry, ce);
749 } while (try_again (&ret, &ce, &h->cred, &fid));
751 if (ret)
752 goto out;
754 h0 = make_installattr(&msg, entry, FCACHE2NNPFSNODE_ALL);
755 h0_len = sizeof(msg);
757 out:
758 nnpfs_send_message_wakeup_multiple (fd,
759 h->header.sequence_num,
760 ret,
761 h0, h0_len,
762 NULL, 0);
763 if (entry)
764 fcache_release(entry);
765 cred_free (ce);
767 return 0;
770 static int
771 nnpfs_message_putattr (int fd, struct nnpfs_message_putattr *h, u_int size)
773 struct nnpfs_message_installattr msg;
774 VenusFid fid;
775 AFSStoreStatus status;
776 CredCacheEntry *ce;
777 struct nnpfs_message_header *h0 = NULL;
778 size_t h0_len = 0;
779 int ret;
781 FCacheEntry *entry = NULL;
783 fid = *(VenusFid *)&h->handle;
784 arla_warnx (ADEBMSG, "putattr (%ld.%lu.%lu.%lu)",
785 (long)fid.Cell, (unsigned long)fid.fid.Volume,
786 (unsigned long)fid.fid.Vnode,
787 (unsigned long)fid.fid.Unique);
788 nnpfs_attr2afsstorestatus(&h->attr, &status);
789 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
790 assert (ce != NULL);
792 if (connected_mode != CONNECTED) {
793 entry = fcache_find(fid);
794 if (!entry) {
795 ret = ENETDOWN;
796 goto out;
798 } else {
799 ret = fcache_get(&entry, fid, ce);
800 if (ret)
801 goto out;
804 assert_flag(entry,kernelp);
806 if (XA_VALID_SIZE(&h->attr)) {
807 /* Bits update may fail on old servers, fixed in openafs-1.2.7 */
808 do {
809 ret = cm_ftruncate (entry, h->attr.xa_size, &status, ce);
810 } while (try_again (&ret, &ce, &h->cred, &fid));
811 if (ret)
812 goto out;
814 entry->flags.appended = FALSE;
817 /* XXX this is redundant on XA_VALID_SIZE(&h->attr), right? */
818 if (status.Mask) {
819 do {
820 ret = cm_setattr(entry, &status, ce);
821 } while (try_again (&ret, &ce, &h->cred, &fid));
824 if (ret)
825 goto out;
827 do {
828 ret = cm_getattr(entry, ce);
829 } while (try_again (&ret, &ce, &h->cred, &fid));
832 if (ret)
833 goto out;
835 h0 = make_installattr(&msg, entry, FCACHE2NNPFSNODE_ALL);
836 h0_len = sizeof(msg);
837 msg.flag = NNPFS_PUTATTR_REPLY;
839 if (connected_mode != CONNECTED)
840 entry->disco_id = disco_store_status(&fid, &status, entry->disco_id);
842 out:
843 nnpfs_send_message_wakeup_multiple (fd,
844 h->header.sequence_num,
845 ret,
846 h0, h0_len,
847 NULL, 0);
848 if (entry)
849 fcache_release(entry);
850 cred_free (ce);
852 return 0;
855 static int
856 nnpfs_message_create (int fd, struct nnpfs_message_create *h, u_int size)
858 VenusFid parent_fid, child_fid;
859 AFSStoreStatus store_status;
860 CredCacheEntry *ce;
861 int ret;
862 struct nnpfs_message_installdata msg1;
863 struct nnpfs_message_installnode msg2;
864 struct nnpfs_message_installdata msg3;
865 struct nnpfs_message_header *h0 = NULL;
866 size_t h0_len = 0;
867 struct nnpfs_message_header *h1 = NULL;
868 size_t h1_len = 0;
869 struct nnpfs_message_header *h2 = NULL;
870 size_t h2_len = 0;
871 FCacheEntry *dir_entry = NULL;
872 FCacheEntry *child_entry = NULL;
874 parent_fid = *(VenusFid *)&h->parent_handle;
875 arla_warnx (ADEBMSG, "create (%ld.%lu.%lu.%lu) \"%s\"",
876 (long)parent_fid.Cell,
877 (unsigned long)parent_fid.fid.Volume,
878 (unsigned long)parent_fid.fid.Vnode,
879 (unsigned long)parent_fid.fid.Unique, h->name);
881 nnpfs_attr2afsstorestatus(&h->attr, &store_status);
882 if (connected_mode != CONNECTED) {
883 if (!(store_status.Mask & SS_OWNER)) {
884 store_status.Owner = h->cred.uid;
885 store_status.Mask |= SS_OWNER;
887 if (!(store_status.Mask & SS_GROUP)) {
888 store_status.Group = 0;
889 store_status.Mask |= SS_GROUP;
891 if (!(store_status.Mask & SS_MODTIME)) {
892 struct timeval now;
894 gettimeofday (&now, NULL);
896 store_status.ClientModTime = now.tv_sec;
897 store_status.Mask |= SS_MODTIME;
900 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
901 assert (ce != NULL);
903 ret = fcache_get(&dir_entry, parent_fid, ce);
904 if (ret)
905 goto out;
907 assert_flag(dir_entry,kernelp);
909 do {
910 ret = cm_create(&dir_entry, h->name, &store_status,
911 &child_entry, &ce);
912 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
914 if (ret)
915 goto out;
917 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
918 if (ret)
919 goto out;
921 ret = conv_dir(dir_entry, ce, 0);
922 if (ret)
923 goto out;
925 /* XXX remove this, we don't want to fetch data from the fileserver
926 ret = message_get_data (&child_entry, &h->cred, &ce, 0); */
927 ret = fcache_verify_attr (child_entry, dir_entry, h->name, ce); /* better? */
928 if (ret)
929 goto out;
931 child_fid = child_entry->fid;
933 assert_flag(dir_entry,kernelp);
934 assert_flag(dir_entry,attrusedp);
936 h0 = make_installdata(&msg1, dir_entry, 0, 0);
937 h0_len = sizeof(msg1);
939 fcacheentry2nnpfsnode (&child_fid, &child_fid,
940 &child_entry->status, &msg2.node, dir_entry->acccache,
941 FCACHE2NNPFSNODE_ALL);
943 fcache_node_setkernelp(child_entry, TRUE);
945 child_entry->tokens |= NNPFS_ATTR_R | NNPFS_DATA_R | NNPFS_DATA_W;
946 msg2.node.tokens = child_entry->tokens & ~(NNPFS_DATA_MASK);
947 child_entry->flags.attrusedp = TRUE;
948 child_entry->flags.datausedp = TRUE;
950 msg2.parent_handle = h->parent_handle;
951 strlcpy (msg2.name, h->name, sizeof(msg2.name));
953 msg2.header.opcode = NNPFS_MSG_INSTALLNODE;
954 h1 = (struct nnpfs_message_header *)&msg2;
955 h1_len = sizeof(msg2);
957 /* msg3.node = msg2.node; */
959 h2 = make_installdata(&msg3, child_entry, 0, 0);
960 h2_len = sizeof(msg3);
962 if (connected_mode != CONNECTED)
963 child_entry->disco_id = disco_create_file(&parent_fid, &child_fid,
964 h->name, &store_status);
966 out:
967 nnpfs_send_message_wakeup_multiple (fd,
968 h->header.sequence_num,
969 ret,
970 h0, h0_len,
971 h1, h1_len,
972 h2, h2_len,
973 NULL, 0);
974 if (dir_entry)
975 fcache_release(dir_entry);
976 if (child_entry)
977 fcache_release(child_entry);
978 cred_free (ce);
980 return ret;
983 static int
984 nnpfs_message_mkdir (int fd, struct nnpfs_message_mkdir *h, u_int size)
986 VenusFid parent_fid, child_fid;
987 AFSStoreStatus store_status;
988 AFSFetchStatus fetch_status;
989 CredCacheEntry *ce;
990 int ret;
991 struct nnpfs_message_installdata msg1;
992 struct nnpfs_message_installnode msg2;
993 struct nnpfs_message_installdata msg3;
994 FCacheEntry *dir_entry = NULL;
995 FCacheEntry *child_entry = NULL;
997 struct nnpfs_message_header *h0 = NULL;
998 size_t h0_len = 0;
999 struct nnpfs_message_header *h1 = NULL;
1000 size_t h1_len = 0;
1001 struct nnpfs_message_header *h2 = NULL;
1002 size_t h2_len = 0;
1004 #if 0
1005 parent_fid = *fid_translate((VenusFid *)&h->parent_handle);
1006 #else
1007 parent_fid = *(VenusFid *)&h->parent_handle;
1008 #endif
1009 arla_warnx (ADEBMSG, "mkdir (%ld.%lu.%lu.%lu) \"%s\"",
1010 (long)parent_fid.Cell, (unsigned long)parent_fid.fid.Volume,
1011 (unsigned long)parent_fid.fid.Vnode,
1012 (unsigned long)parent_fid.fid.Unique, h->name);
1014 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
1015 assert (ce != NULL);
1017 nnpfs_attr2afsstorestatus(&h->attr, &store_status);
1018 if (connected_mode != CONNECTED) {
1019 if (!(store_status.Mask & SS_OWNER)) {
1020 store_status.Owner = h->cred.uid;
1021 store_status.Mask |= SS_OWNER;
1023 if (!(store_status.Mask & SS_MODTIME)) {
1024 struct timeval now;
1026 gettimeofday (&now, NULL);
1028 store_status.ClientModTime = now.tv_sec;
1029 store_status.Mask |= SS_MODTIME;
1033 ret = fcache_get(&dir_entry, parent_fid, ce);
1034 if (ret)
1035 goto out;
1037 assert_flag(dir_entry,kernelp);
1039 do {
1040 ret = cm_mkdir(&dir_entry, h->name, &store_status,
1041 &child_fid, &fetch_status, &ce);
1042 } while(try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1044 if (ret)
1045 goto out;
1047 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
1048 if (ret)
1049 goto out;
1051 ret = conv_dir(dir_entry, ce, 0);
1052 if (ret)
1053 goto out;
1055 assert_flag(dir_entry,kernelp);
1056 assert_flag(dir_entry,attrusedp);
1058 h0 = make_installdata(&msg1, dir_entry, 0, 0);
1059 h0_len = sizeof(msg1);
1061 ret = fcache_get(&child_entry, child_fid, ce);
1062 if (ret)
1063 goto out;
1064 ret = message_get_data (&child_entry, &h->cred, &ce, 0);
1065 if (ret)
1066 goto out;
1068 child_fid = child_entry->fid;
1070 ret = conv_dir(child_entry, ce, 0);
1071 if (ret)
1072 goto out;
1074 fcache_node_setkernelp(child_entry, TRUE);
1075 child_entry->flags.attrusedp = TRUE;
1076 child_entry->flags.datausedp = TRUE;
1077 child_entry->tokens |= NNPFS_ATTR_R;
1078 msg2.node.tokens = child_entry->tokens & ~(NNPFS_DATA_MASK);
1080 fcacheentry2nnpfsnode (&child_fid, &child_fid,
1081 &child_entry->status, &msg2.node,
1082 dir_entry->acccache,
1083 FCACHE2NNPFSNODE_ALL);
1085 msg2.parent_handle = h->parent_handle;
1086 strlcpy (msg2.name, h->name, sizeof(msg2.name));
1088 msg2.header.opcode = NNPFS_MSG_INSTALLNODE;
1089 h1 = (struct nnpfs_message_header *)&msg2;
1090 h1_len = sizeof(msg2);
1092 /* msg3.node = msg2.node; */
1094 h2 = make_installdata(&msg3, child_entry, 0, 0);
1095 h2_len = sizeof(msg3);
1097 if (connected_mode != CONNECTED)
1098 child_entry->disco_id = disco_create_dir(&parent_fid, &child_fid,
1099 h->name, &store_status);
1101 out:
1102 nnpfs_send_message_wakeup_multiple (fd,
1103 h->header.sequence_num,
1104 ret,
1105 h0, h0_len,
1106 h1, h1_len,
1107 h2, h2_len,
1108 NULL, 0);
1109 if (child_entry)
1110 fcache_release(child_entry);
1111 if (dir_entry)
1112 fcache_release(dir_entry);
1113 cred_free (ce);
1115 return ret;
1118 static int
1119 nnpfs_message_link (int fd, struct nnpfs_message_link *h, u_int size)
1121 VenusFid parent_fid, existing_fid;
1122 CredCacheEntry *ce;
1123 int ret;
1124 struct nnpfs_message_installdata msg1;
1125 struct nnpfs_message_installnode msg2;
1126 struct nnpfs_message_header *h0 = NULL;
1127 size_t h0_len = 0;
1128 struct nnpfs_message_header *h1 = NULL;
1129 size_t h1_len = 0;
1130 FCacheEntry *dir_entry = NULL;
1131 FCacheEntry *child_entry = NULL;
1133 parent_fid = *(VenusFid *)&h->parent_handle;
1134 existing_fid = *(VenusFid *)&h->from_handle;
1135 arla_warnx (ADEBMSG, "link (%ld.%lu.%lu.%lu) (%ld.%lu.%lu.%lu) \"%s\"",
1136 (long)parent_fid.Cell, (unsigned long)parent_fid.fid.Volume,
1137 (unsigned long)parent_fid.fid.Vnode,
1138 (unsigned long)parent_fid.fid.Unique,
1139 (long)existing_fid.Cell,
1140 (unsigned long)existing_fid.fid.Volume,
1141 (unsigned long)existing_fid.fid.Vnode,
1142 (unsigned long)existing_fid.fid.Unique,
1143 h->name);
1145 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
1146 assert (ce != NULL);
1148 ret = fcache_get(&dir_entry, parent_fid, ce);
1149 if (ret)
1150 goto out;
1152 ret = fcache_get(&child_entry, existing_fid, ce);
1153 if (ret)
1154 goto out;
1156 assert_flag(dir_entry,kernelp);
1157 assert_flag(child_entry,kernelp);
1159 do {
1160 ret = cm_link(&dir_entry, h->name, child_entry, &ce);
1161 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1163 if (ret)
1164 goto out;
1166 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
1167 if (ret)
1168 goto out;
1170 ret = conv_dir(dir_entry, ce, 0);
1171 if (ret == -1)
1172 goto out;
1174 assert_flag(dir_entry,kernelp);
1175 assert_flag(dir_entry,attrusedp);
1177 h0 = make_installdata(&msg1, dir_entry, 0, 0);
1178 h0_len = sizeof(msg1);
1180 fcacheentry2nnpfsnode(&existing_fid, &existing_fid, /* &child_entry->fid ? */
1181 &child_entry->status, &msg2.node,
1182 child_entry->acccache,
1183 FCACHE2NNPFSNODE_ALL);
1185 child_entry->flags.attrp = TRUE;
1186 child_entry->tokens |= NNPFS_ATTR_R;
1188 msg2.node.tokens = child_entry->tokens;
1189 msg2.parent_handle = h->parent_handle;
1190 strlcpy (msg2.name, h->name, sizeof(msg2.name));
1192 msg2.header.opcode = NNPFS_MSG_INSTALLNODE;
1193 h1 = (struct nnpfs_message_header *)&msg2;
1194 h1_len = sizeof(msg2);
1196 out:
1197 nnpfs_send_message_wakeup_multiple (fd,
1198 h->header.sequence_num,
1199 ret,
1200 h0, h0_len,
1201 h1, h1_len,
1202 NULL, 0);
1203 if (dir_entry)
1204 fcache_release(dir_entry);
1205 if (child_entry)
1206 fcache_release(child_entry);
1207 cred_free (ce);
1209 return ret;
1212 static int
1213 nnpfs_message_symlink (int fd, struct nnpfs_message_symlink *h, u_int size)
1215 VenusFid parent_fid, child_fid, real_fid;
1216 AFSStoreStatus store_status;
1217 AFSFetchStatus fetch_status;
1218 CredCacheEntry *ce;
1219 int saved_ret;
1220 int ret;
1221 struct nnpfs_message_installdata msg1;
1222 struct nnpfs_message_installnode msg2;
1223 struct nnpfs_message_header *h0 = NULL;
1224 size_t h0_len = 0;
1225 struct nnpfs_message_header *h1 = NULL;
1226 size_t h1_len = 0;
1227 FCacheEntry *dir_entry = NULL;
1229 parent_fid = *(VenusFid *)&h->parent_handle;
1230 arla_warnx (ADEBMSG, "symlink (%ld.%lu.%lu.%lu) \"%s\"",
1231 (long)parent_fid.Cell, (unsigned long)parent_fid.fid.Volume,
1232 (unsigned long)parent_fid.fid.Vnode,
1233 (unsigned long)parent_fid.fid.Unique, h->name);
1235 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
1236 assert (ce != NULL);
1238 nnpfs_attr2afsstorestatus(&h->attr, &store_status);
1240 ret = fcache_get(&dir_entry, parent_fid, ce);
1241 if (ret)
1242 goto out;
1244 assert_flag(dir_entry,kernelp);
1246 do {
1247 ret = cm_symlink(&dir_entry, h->name, &store_status,
1248 &child_fid, &real_fid,
1249 &fetch_status,
1250 h->contents, &ce);
1251 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1253 cred_free (ce);
1254 ce = cred_get (dir_entry->fid.Cell, h->cred.pag, CRED_ANY);
1255 assert (ce != NULL);
1258 * Mountpoints can be created even when the target volume doesn't
1259 * exist, and other things may happen. Always update the directory
1260 * just to be on the safe side.
1262 saved_ret = ret;
1264 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
1265 if (ret)
1266 goto out;
1268 ret = conv_dir(dir_entry, ce, 0);
1269 if (ret)
1270 goto out;
1272 assert_flag(dir_entry,kernelp);
1273 assert_flag(dir_entry,attrusedp);
1275 h0 = make_installdata(&msg1, dir_entry, 0, 0);
1276 h0_len = sizeof(msg1);
1278 if (saved_ret) {
1279 ret = saved_ret;
1280 goto out;
1283 fcacheentry2nnpfsnode (&child_fid, &real_fid,
1284 &fetch_status, &msg2.node,
1285 dir_entry->acccache,
1286 FCACHE2NNPFSNODE_ALL);
1288 msg2.node.tokens = NNPFS_ATTR_R; /* XXX */
1289 msg2.parent_handle = h->parent_handle;
1290 strlcpy (msg2.name, h->name, sizeof(msg2.name));
1292 msg2.header.opcode = NNPFS_MSG_INSTALLNODE;
1293 h1 = (struct nnpfs_message_header *)&msg2;
1294 h1_len = sizeof(msg2);
1296 out:
1297 nnpfs_send_message_wakeup_multiple (fd,
1298 h->header.sequence_num,
1299 ret,
1300 h0, h0_len,
1301 h1, h1_len,
1302 NULL, 0);
1303 if (dir_entry)
1304 fcache_release(dir_entry);
1305 cred_free (ce);
1307 return ret;
1311 * Handle the NNPFS remove message in `h', that is, remove name
1312 * `h->name' in directory `h->parent' with the creds from `h->cred'.
1315 static int
1316 nnpfs_message_remove (int fd, struct nnpfs_message_remove *h, u_int size)
1318 VenusFid parent_fid;
1319 VenusFid fid;
1320 CredCacheEntry *ce;
1321 int ret;
1322 struct nnpfs_message_installdata msg1;
1323 struct nnpfs_message_installattr msg2;
1324 struct nnpfs_message_header *h0 = NULL;
1325 size_t h0_len = 0;
1326 struct nnpfs_message_header *h1 = NULL;
1327 size_t h1_len = 0;
1328 FCacheEntry *limbo_entry = NULL;
1329 FCacheEntry *dir_entry = NULL;
1331 parent_fid = *(VenusFid *)&h->parent_handle;
1332 arla_warnx (ADEBMSG, "remove (%ld.%lu.%lu.%lu) \"%s\"",
1333 (long)parent_fid.Cell, (unsigned long)parent_fid.fid.Volume,
1334 (unsigned long)parent_fid.fid.Vnode,
1335 (unsigned long)parent_fid.fid.Unique, h->name);
1337 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
1338 assert (ce != NULL);
1340 ret = fcache_get(&dir_entry, parent_fid, ce);
1341 if (ret)
1342 goto out;
1344 assert_flag(dir_entry,kernelp);
1346 do {
1347 ret = cm_lookup (&dir_entry, h->name, &fid, &ce, FALSE);
1348 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1350 if (ret)
1351 goto out;
1354 * Fetch the linkcount of the to be removed node
1357 ret = fcache_get (&limbo_entry, fid, ce);
1358 if (ret)
1359 goto out;
1361 ret = fcache_verify_attr (limbo_entry, dir_entry, h->name, ce);
1362 if (ret)
1363 goto out;
1366 * Do the actual work
1369 do {
1370 ret = cm_remove(&dir_entry, h->name, &limbo_entry, &ce);
1371 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1373 if (ret)
1374 goto out;
1376 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
1377 if (ret)
1378 goto out;
1380 if (!dir_entry->flags.extradirp
1381 || dir_remove_name (dir_entry, h->name)) {
1382 ret = conv_dir(dir_entry, ce, 0);
1383 if (ret)
1384 goto out;
1387 assert(dir_entry->flags.attrusedp);
1389 h0 = make_installdata(&msg1, dir_entry, 0, NNPFS_ID_INVALID_DNLC);
1390 h0_len = sizeof(msg1);
1393 * Make sure that if the removed node is in the kernel it has the
1394 * right linkcount since some might hold a reference to it.
1397 if (limbo_entry->flags.kernelp) {
1399 * Now insert the limbo entry to get right linkcount
1401 h1 = make_installattr(&msg2, limbo_entry, FCACHE2NNPFSNODE_ALL);
1402 h1_len = sizeof(msg2);
1405 out:
1406 nnpfs_send_message_wakeup_multiple (fd,
1407 h->header.sequence_num,
1408 ret,
1409 h0, h0_len,
1410 h1, h1_len,
1411 NULL, 0);
1412 if (dir_entry)
1413 fcache_release(dir_entry);
1414 if (limbo_entry)
1415 fcache_release (limbo_entry);
1416 cred_free (ce);
1418 return ret;
1421 static int
1422 nnpfs_message_rmdir (int fd, struct nnpfs_message_rmdir *h, u_int size)
1424 VenusFid parent_fid, fid;
1425 CredCacheEntry *ce;
1426 int ret;
1427 struct nnpfs_message_installdata msg0;
1428 struct nnpfs_message_header *h0 = NULL;
1429 size_t h0_len = 0;
1430 struct nnpfs_message_installattr msg1;
1431 struct nnpfs_message_header *h1 = NULL;
1432 size_t h1_len = 0;
1433 FCacheEntry *limbo_entry = NULL;
1434 FCacheEntry *dir_entry = NULL;
1436 parent_fid = *(VenusFid *)&h->parent_handle;
1437 arla_warnx (ADEBMSG, "rmdir (%ld.%lu.%lu.%lu) \"%s\"",
1438 (long)parent_fid.Cell, (unsigned long)parent_fid.fid.Volume,
1439 (unsigned long)parent_fid.fid.Vnode,
1440 (unsigned long)parent_fid.fid.Unique, h->name);
1442 ce = cred_get (parent_fid.Cell, h->cred.pag, CRED_ANY);
1443 assert (ce != NULL);
1446 * Fetch the child-entry fid.
1449 ret = fcache_get(&dir_entry, parent_fid, ce);
1450 if (ret)
1451 goto out;
1453 assert_flag(dir_entry,kernelp);
1455 do {
1456 ret = cm_lookup (&dir_entry, h->name, &fid, &ce, FALSE);
1457 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1459 if (ret)
1460 goto out;
1462 if (VenusFid_cmp(&dir_entry->fid, &fid) == 0) {
1463 ret = EINVAL;
1464 goto out;
1468 * Need to get linkcount for silly rename.
1471 ret = fcache_get (&limbo_entry, fid, ce);
1472 if (ret)
1473 goto out;
1475 ret = fcache_verify_attr (limbo_entry, dir_entry, h->name, ce);
1476 if (ret)
1477 goto out;
1480 * Do the actual work
1483 do {
1484 ret = cm_rmdir(&dir_entry, h->name, &limbo_entry, &ce);
1485 } while (try_again (&ret, &ce, &h->cred, &dir_entry->fid));
1487 if (ret)
1488 goto out;
1490 ret = message_get_data (&dir_entry, &h->cred, &ce, 0);
1491 if (ret)
1492 goto out;
1494 if (!dir_entry->flags.extradirp
1495 || dir_remove_name (dir_entry, h->name)) {
1496 ret = conv_dir(dir_entry, ce, 0);
1497 if (ret)
1498 goto out;
1501 h0 = make_installdata(&msg0, dir_entry, 0, NNPFS_ID_INVALID_DNLC);
1502 h0_len = sizeof(msg0);
1504 if (limbo_entry->flags.kernelp) {
1505 h1 = make_installattr(&msg1, limbo_entry, FCACHE2NNPFSNODE_ALL);
1506 h1_len = sizeof(msg1);
1508 assert_flag(dir_entry,kernelp);
1509 assert_flag(dir_entry,attrusedp);
1511 out:
1512 nnpfs_send_message_wakeup_multiple (fd,
1513 h->header.sequence_num,
1514 ret,
1515 h0, h0_len,
1516 h1, h1_len,
1517 NULL, 0);
1518 if (dir_entry)
1519 fcache_release(dir_entry);
1520 if (limbo_entry)
1521 fcache_release (limbo_entry);
1523 cred_free (ce);
1525 return ret;
1528 static int
1529 nnpfs_message_rename (int fd, struct nnpfs_message_rename *h, u_int size)
1531 VenusFid old_parent_fid;
1532 VenusFid new_parent_fid;
1533 VenusFid child_fid;
1534 CredCacheEntry *ce;
1535 CredCacheEntry *ce2;
1536 int ret;
1537 struct nnpfs_message_installdata msg1;
1538 struct nnpfs_message_installdata msg2;
1539 struct nnpfs_message_installdata msg3;
1540 struct nnpfs_message_header *h0 = NULL;
1541 size_t h0_len = 0;
1542 struct nnpfs_message_header *h1 = NULL;
1543 size_t h1_len = 0;
1544 struct nnpfs_message_header *h2 = NULL;
1545 size_t h2_len = 0;
1546 FCacheEntry *old_entry = NULL;
1547 FCacheEntry *new_entry = NULL;
1548 FCacheEntry *child_entry = NULL;
1549 int update_child = 0;
1550 int diff_dir = 0;
1552 old_parent_fid = *(VenusFid *)&h->old_parent_handle;
1553 new_parent_fid = *(VenusFid *)&h->new_parent_handle;
1554 arla_warnx (ADEBMSG,
1555 "rename (%ld.%lu.%lu.%lu) (%ld.%lu.%lu.%lu) \"%s\" \"%s\"",
1556 (long)old_parent_fid.Cell,
1557 (unsigned long)old_parent_fid.fid.Volume,
1558 (unsigned long)old_parent_fid.fid.Vnode,
1559 (unsigned long)old_parent_fid.fid.Unique,
1560 (long)new_parent_fid.Cell,
1561 (unsigned long)new_parent_fid.fid.Volume,
1562 (unsigned long)new_parent_fid.fid.Vnode,
1563 (unsigned long)new_parent_fid.fid.Unique,
1564 h->old_name,
1565 h->new_name);
1567 ce = cred_get (old_parent_fid.Cell, h->cred.pag, CRED_ANY);
1568 assert (ce != NULL);
1570 if (new_parent_fid.Cell == old_parent_fid.Cell) {
1571 ce2 = ce;
1572 cred_ref(ce2);
1573 } else {
1574 ce2 = cred_get(new_parent_fid.Cell, h->cred.pag, CRED_ANY);
1575 assert(ce2);
1578 diff_dir = VenusFid_cmp (&old_parent_fid, &new_parent_fid);
1580 ret = fcache_get(&old_entry, old_parent_fid, ce);
1581 if (ret)
1582 goto out;
1584 assert_flag(old_entry,kernelp);
1586 if (diff_dir) {
1587 ret = fcache_get(&new_entry, new_parent_fid, ce2);
1588 if (ret)
1589 goto out;
1590 } else {
1591 new_entry = old_entry;
1595 assert_flag(new_entry,kernelp);
1597 do {
1598 ret = cm_rename(&old_entry, h->old_name,
1599 &new_entry, h->new_name,
1600 &child_fid, &update_child, &ce, &ce2);
1601 } while (try_again_crosscell(&ret, &ce, &ce2, &h->cred, &old_entry->fid));
1603 if (ret)
1604 goto out;
1606 ret = message_get_data (&old_entry, &h->cred, &ce, 0);
1607 if (ret)
1608 goto out;
1610 if (!old_entry->flags.extradirp
1611 || dir_remove_name (old_entry, h->old_name)) {
1612 ret = conv_dir(old_entry, ce, 0);
1613 if (ret)
1614 goto out;
1617 assert_flag(old_entry,kernelp);
1618 assert_flag(old_entry,attrusedp);
1620 h0 = make_installdata(&msg1, old_entry, 0, NNPFS_ID_INVALID_DNLC);
1621 h0_len = sizeof(msg1);
1623 ret = fcache_get_data (&new_entry, &ce2, 0, 0); /* XXX - fake_mp? */
1624 if (ret)
1625 goto out;
1627 ret = conv_dir(new_entry, ce2, 0);
1628 if (ret)
1629 goto out;
1631 assert_flag(new_entry,kernelp);
1632 assert_flag(new_entry,attrusedp);
1634 h1 = make_installdata(&msg2, new_entry, 0, NNPFS_ID_INVALID_DNLC);
1635 h1_len = sizeof(msg2);
1637 if (update_child) {
1638 ret = fcache_get(&child_entry, child_fid, ce2);
1639 if (ret)
1640 goto out;
1641 ret = message_get_data (&child_entry, &h->cred, &ce2, 0);
1642 if (ret) {
1643 fcache_release(child_entry);
1644 goto out;
1646 child_fid = child_entry->fid;
1648 ret = conv_dir(child_entry, ce2, 0);
1649 if (ret)
1650 goto out;
1652 h2 = make_installdata(&msg3, child_entry, 0, NNPFS_ID_INVALID_DNLC);
1653 h2_len = sizeof(msg3);
1656 out:
1657 nnpfs_send_message_wakeup_multiple (fd,
1658 h->header.sequence_num,
1659 ret,
1660 h0, h0_len,
1661 h1, h1_len,
1662 NULL, 0);
1663 if (old_entry) fcache_release(old_entry);
1664 if (new_entry && diff_dir) fcache_release(new_entry);
1665 if (child_entry) fcache_release(child_entry);
1667 cred_free (ce);
1668 cred_free(ce2);
1670 return ret;
1673 static int
1674 nnpfs_message_putdata (int fd, struct nnpfs_message_putdata *h, u_int size)
1676 VenusFid fid;
1677 CredCacheEntry *ce;
1678 int ret;
1679 AFSStoreStatus status;
1680 FCacheEntry *entry = NULL;
1681 uint64_t len, end;
1683 worker_setdebuginfo("message putdata");
1685 if (h->flag & NNPFS_GC)
1686 fcache_cleaner_ref();
1688 fid = *(VenusFid *)&h->handle;
1689 arla_warnx (ADEBMSG, "putdata (%ld.%lu.%lu.%lu)",
1690 (long)fid.Cell, (unsigned long)fid.fid.Volume,
1691 (unsigned long)fid.fid.Vnode,
1692 (unsigned long)fid.fid.Unique);
1694 nnpfs_attr2afsstorestatus(&h->attr, &status);
1696 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
1697 assert (ce != NULL);
1699 if (connected_mode != CONNECTED) {
1700 entry = fcache_find(fid); /* XXX gcp? */
1701 if (!entry) {
1702 ret = ENETDOWN;
1703 goto out;
1705 } else {
1706 if (h->flag & NNPFS_GC)
1707 ret = fcache_get_gc(&entry, fid, ce);
1708 else
1709 ret = fcache_get(&entry, fid, ce);
1710 if (ret)
1711 goto out;
1714 assert_flag(entry,kernelp);
1715 assert(XA_VALID_SIZE(&h->attr));
1716 assert(h->attr.xa_size >= h->offset);
1718 len = h->attr.xa_size;
1720 if (fcache_get_status_length(&entry->status) < len)
1721 fcache_set_status_length(&entry->status, len);
1723 end = h->offset + h->len;
1724 assert(end <= len);
1726 #if 0
1727 worker_setdebuginfo("putdata have");
1729 /* XXX this is not a good place to be picky about cache usage */
1730 ret = fcache_set_have(entry, h->offset, end);
1731 if (ret) {
1732 arla_warn(ADEBMSG, ret, "nnpfs_message_putdata: set_have");
1733 goto out;
1735 #endif
1737 worker_setdebuginfo("putdata write");
1739 do {
1740 ret = cm_write(entry, h->flag, h->offset, h->len, &status, ce);
1741 } while (try_again (&ret, &ce, &h->cred, &fid));
1743 if (ret) {
1744 arla_warn (ADEBMSG, ret, "nnpfs_message_putdata: cm_write");
1745 goto out;
1748 entry->flags.appended = FALSE;
1750 if (connected_mode != CONNECTED)
1751 entry->disco_id = disco_store_data(&fid, &status, entry->disco_id);
1753 if (h->flag & NNPFS_GC) {
1754 uint64_t blocksize = fcache_getblocksize();
1755 uint64_t off;
1756 for (off = h->offset; off < end; off += blocksize)
1757 fcache_data_setkernelp(entry, off, FALSE, FALSE);
1758 } else {
1759 /* XXX do this on GC too? */
1761 entry->flags.dirtied = FALSE;
1762 entry->flags.stale = FALSE;
1764 /* XXX argh. if this was a partial write we may still have
1765 * stale blocks
1769 out:
1770 worker_setdebuginfo("putdata done");
1772 if (h->flag & NNPFS_GC)
1773 fcache_cleaner_deref();
1775 if (ret)
1776 entry->flags.dirtied = TRUE; /* break_callback(entry); */
1778 if (entry)
1779 fcache_release(entry);
1780 cred_free (ce);
1781 nnpfs_send_message_wakeup (fd, h->header.sequence_num, ret);
1782 return 0;
1785 static void
1786 prefetch_data(FCacheEntry **e, CredCacheEntry **ce)
1788 #if 0 /* XXX no prefetch for now */
1789 FCacheEntry *entry = *e;
1790 uint64_t length;
1791 int ret = 0;
1793 if (entry->status.FileType != TYPE_FILE)
1794 return;
1796 /* always leave a few threads for synchronous work */
1797 if (num_prefetches >= max_prefetches)
1798 return;
1800 num_prefetches++;
1802 length = fcache_get_status_length(&entry->status);
1804 if (length > entry->fetched_length) {
1805 uint64_t offset;
1807 offset = entry->fetched_length + stats_prefetch(NULL, -1);
1808 if (offset > length)
1809 offset = length;
1810 arla_warnx (ADEBMSG, " prefetching to %lu", (unsigned long)offset);
1811 ret = fcache_get_data (e, ce, 0, offset);
1812 arla_warnx (ADEBMSG, " prefetched returned %d", ret);
1815 num_prefetches--;
1817 #endif
1818 return;
1821 static int
1822 nnpfs_message_open (int fd, struct nnpfs_message_open *h, u_int size)
1824 struct nnpfs_message_installdata msg;
1825 struct nnpfs_message_header *h0;
1826 FCacheEntry *entry = NULL;
1827 CredCacheEntry *ce;
1828 VenusFid fid;
1829 int ret;
1831 fid = *(VenusFid *)&h->handle;
1832 arla_warnx (ADEBMSG, "open (%ld.%lu.%lu.%lu)",
1833 (long)fid.Cell, (unsigned long)fid.fid.Volume,
1834 (unsigned long)fid.fid.Vnode,
1835 (unsigned long)fid.fid.Unique);
1837 worker_setdebuginfo("message open");
1839 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
1840 assert (ce != NULL);
1842 worker_setdebuginfo("message open fcache_get");
1844 ret = fcache_get(&entry, fid, ce);
1845 if (ret)
1846 goto out;
1848 assert_flag(entry,kernelp);
1850 tryagain:
1852 worker_setdebuginfo("message open cm_getattr");
1854 ret = cm_getattr(entry, ce);
1856 if (try_again (&ret, &ce, &h->cred, &fid))
1857 goto tryagain;
1858 if (ret)
1859 goto out;
1861 if (entry->status.FileType == TYPE_DIR) {
1862 if (h->tokens & NNPFS_DATA_W) {
1863 ret = EACCES;
1864 goto out;
1867 worker_setdebuginfo("message open fcache_get_data");
1869 ret = fcache_get_data (&entry, &ce, 0,
1870 fcache_get_status_length(&entry->status));
1871 if (try_again (&ret, &ce, &h->cred, &fid))
1872 goto tryagain;
1873 if (ret)
1874 goto out;
1875 fid = entry->fid;
1877 ret = conv_dir(entry, ce, h->tokens);
1878 if (ret)
1879 goto out;
1881 entry->tokens |= h->tokens;
1882 assert_flag(entry,kernelp);
1884 h0 = make_installdata(&msg, entry, 0, 0);
1885 } else {
1886 worker_setdebuginfo("message open cm_open");
1887 ret = cm_open (entry, ce, h->tokens);
1888 if (try_again (&ret, &ce, &h->cred, &fid))
1889 goto tryagain;
1890 if (ret)
1891 goto out;
1893 h0 = make_installdata(&msg, entry, NNPFS_NO_OFFSET, 0);
1896 worker_setdebuginfo("message open wakeup");
1898 nnpfs_send_message_wakeup_multiple (fd,
1899 h->header.sequence_num,
1900 ret,
1901 &msg, sizeof(msg),
1902 NULL, 0);
1904 worker_setdebuginfo("message open prefetching");
1906 prefetch_data(&entry, &ce);
1908 fcache_release(entry);
1909 cred_free (ce);
1910 return ret;
1912 out:
1914 if (entry)
1915 fcache_release(entry);
1916 cred_free (ce);
1917 nnpfs_send_message_wakeup_multiple (fd,
1918 h->header.sequence_num,
1919 ret,
1920 NULL, 0);
1921 return ret;
1924 #define NUM_INSTALLDATA 10
1926 static int
1927 send_installdata_range(int fd, FCacheEntry *node,
1928 uint64_t offset, uint64_t end,
1929 struct nnpfs_message_installdata *proto)
1931 struct nnpfs_message_installdata n_msg[NUM_INSTALLDATA];
1932 struct nnpfs_message_installdata *msg = &n_msg[0];
1933 uint64_t blocksize = fcache_getblocksize();
1934 uint64_t i, n, off;
1935 Bool kernelp = TRUE;
1936 int ret = 0;
1938 if (end <= offset)
1939 n = 1;
1940 else
1941 n = (end - offset - 1) / blocksize + 1;
1943 if (n > NUM_INSTALLDATA) {
1944 void *tmp = malloc(n * sizeof(msg[0]));
1945 if (tmp) {
1946 msg = tmp;
1947 } else {
1948 /* oh well, maybe we can add a few at least */
1949 n = NUM_INSTALLDATA;
1953 for (i = 0, off = offset; i < n; i++, off += blocksize) {
1954 msg[i] = *proto;
1955 msg[i].offset = off;
1957 fcache_data_setbusy(node, offset, off, TRUE);
1959 if (node->flags.appended) {
1960 uint64_t length = fcache_get_status_length(&node->status);
1961 uint64_t lastoff = off - blocksize;
1962 if (block_end_offset(length) == lastoff) {
1963 ret = abuf_truncate_block(node, lastoff, blocksize);
1964 if (ret)
1965 arla_warn(ADEBWARN, ret,
1966 "block truncate failed for (%ld.%lu.%lu.%lu) @%llu",
1967 (long)node->fid.Cell,
1968 (unsigned long)node->fid.fid.Volume,
1969 (unsigned long)node->fid.fid.Vnode,
1970 (unsigned long)node->fid.fid.Unique,
1971 (unsigned long long)lastoff);
1975 arla_warnx(ADEBMSG, " sending %llu installdata from %llu to %llu",
1976 (unsigned long long)n,
1977 (unsigned long long)offset, (unsigned long long)end);
1979 if (!ret)
1980 ret = nnpfs_send_message_multiple_list(fd,
1981 (struct nnpfs_message_header *)msg,
1982 sizeof (msg[0]),
1984 if (msg != &n_msg[0])
1985 free(msg);
1987 if (ret)
1988 kernelp = FALSE;
1990 for (i = 0, off = offset; i < n; i++, off += blocksize)
1991 fcache_data_setkernelp(node, off, kernelp, TRUE);
1993 return ret;
1996 static int
1997 nnpfs_message_getdata (int fd, struct nnpfs_message_getdata *h, u_int size)
1999 struct nnpfs_message_installdata msg;
2000 VenusFid fid;
2001 CredCacheEntry *ce;
2002 int ret;
2003 uint64_t offset, end, length;
2004 FCacheEntry *entry = NULL;
2006 worker_setdebuginfo("message getdata");
2008 fid = *(VenusFid *)&h->handle;
2009 arla_warnx (ADEBMSG, "getdata (%ld.%lu.%lu.%lu)",
2010 (long)fid.Cell, (unsigned long)fid.fid.Volume,
2011 (unsigned long)fid.fid.Vnode,
2012 (unsigned long)fid.fid.Unique);
2014 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2015 assert (ce != NULL);
2017 ret = fcache_get(&entry, fid, ce);
2018 if (ret)
2019 goto out;
2021 assert_flag(entry,kernelp);
2023 tryagain:
2025 worker_setdebuginfo("getdata getattr");
2027 ret = cm_getattr(entry, ce);
2029 if (try_again (&ret, &ce, &h->cred, &fid))
2030 goto tryagain;
2031 if (ret)
2032 goto out;
2034 length = fcache_get_status_length(&entry->status);
2036 offset = h->offset;
2038 assert(offset % fcache_getblocksize() == 0);
2039 assert(offset < length || (offset == length && length == 0));
2041 if (entry->status.FileType == TYPE_DIR) {
2042 end = length;
2043 } else {
2044 end = block_next_offset(h->offset + h->len);
2045 if (end > length)
2046 end = length;
2049 /* The first block is always there. */
2050 if (end == 0) {
2051 ret = fcache_set_have(entry, end, end);
2052 if (ret) {
2053 arla_warn(ADEBMSG, ret, "nnpfs_message_getdata: set_have");
2054 goto out;
2058 arla_warnx (ADEBMSG, " requested block at %lu fetching to byte %lu",
2059 (unsigned long)h->offset, (unsigned long)end);
2061 worker_setdebuginfo("getdata getdata");
2063 ret = fcache_get_data(&entry, &ce, offset, end);
2064 if (try_again (&ret, &ce, &h->cred, &fid))
2065 goto tryagain;
2066 if (ret)
2067 goto out;
2069 worker_setdebuginfo("getdata done");
2071 if (entry->status.FileType == TYPE_DIR) {
2072 ret = conv_dir(entry, ce, h->tokens);
2073 if (ret)
2074 goto out;
2075 #if 0
2076 msg.flag = NNPFS_ID_INVALID_DNLC; /* paranoia */
2077 #endif
2080 if (h->tokens & NNPFS_DATA_W)
2081 entry->tokens |= NNPFS_DATA_W;
2082 arla_warnx (ADEBMSG, " got %lu", (unsigned long)end);
2084 make_installdata(&msg, entry, NNPFS_NO_OFFSET, 0);
2086 send_installdata_range(fd, entry, offset, end, &msg);
2087 nnpfs_send_message_wakeup(fd, h->header.sequence_num, ret);
2089 prefetch_data(&entry, &ce);
2091 fcache_release(entry);
2092 cred_free (ce);
2093 return ret;
2095 out:
2096 if (entry)
2097 fcache_release(entry);
2098 cred_free (ce);
2099 nnpfs_send_message_wakeup(fd, h->header.sequence_num, ret);
2101 return ret;
2105 * Send a invalid node to the kernel to invalidate `entry'
2106 * and record that it's not being used in the kernel.
2109 void
2110 break_callback (FCacheEntry *entry)
2112 struct nnpfs_message_invalidnode msg;
2113 enum { CALLBACK_BREAK_WARN = 100 };
2114 static int failed_callbacks_break = 0;
2115 int ret;
2117 assert_flag(entry,kernelp);
2120 * Throw away tokens for all directories and unused entries.
2121 * needs to be same as NNPFS_MSG_INVALIDNODE processing in
2122 * nnpfs
2124 if (entry->status.FileType == TYPE_DIR || !entry->flags.datausedp)
2125 entry->tokens = 0;
2127 msg.header.opcode = NNPFS_MSG_INVALIDNODE;
2128 memcpy (&msg.handle, &entry->fid, sizeof(entry->fid));
2129 ret = nnpfs_message_send (kernel_fd, (struct nnpfs_message_header *)&msg,
2130 sizeof(msg));
2131 if (ret == EISDIR) {
2133 * Ignore EISDIR for invalidnode since that means that a
2134 * message is on route to arlad to tell it the node is on the
2135 * way out from the cache.
2137 } else if (ret) {
2138 arla_warnx (ADEBMSG, "break_callback: (%ld.%lu.%lu.%lu) failed",
2139 (long)entry->fid.Cell,
2140 (unsigned long)entry->fid.fid.Volume,
2141 (unsigned long)entry->fid.fid.Vnode,
2142 (unsigned long)entry->fid.fid.Unique);
2143 ++failed_callbacks_break;
2144 if (failed_callbacks_break > CALLBACK_BREAK_WARN) {
2145 arla_warnx (ADEBWARN, "break_callback: have failed %d times",
2146 failed_callbacks_break);
2147 failed_callbacks_break = 0;
2153 * Send an unsolicited install-attr for the node in `e'
2156 void
2157 install_attr (FCacheEntry *e, int flags)
2159 struct nnpfs_message_installattr msg;
2160 struct nnpfs_message_header *h;
2162 memset (&msg, 0, sizeof(msg));
2163 h = make_installattr(&msg, e, flags);
2165 nnpfs_message_send(kernel_fd, h, sizeof(msg));
2168 void
2169 update_fid(VenusFid oldfid, FCacheEntry *old_entry,
2170 VenusFid newfid, FCacheEntry *new_entry)
2172 struct nnpfs_message_updatefid msg;
2174 msg.header.opcode = NNPFS_MSG_UPDATEFID;
2175 memcpy (&msg.old_handle, &oldfid, sizeof(oldfid));
2176 memcpy (&msg.new_handle, &newfid, sizeof(newfid));
2177 nnpfs_message_send (kernel_fd, (struct nnpfs_message_header *)&msg,
2178 sizeof(msg));
2179 if (new_entry != NULL) {
2180 fcache_node_setkernelp(new_entry, TRUE);
2181 new_entry->flags.attrusedp = TRUE;
2183 if (old_entry != NULL) {
2184 fcache_node_setkernelp(old_entry, FALSE);
2185 old_entry->flags.attrusedp = FALSE;
2186 old_entry->flags.datausedp = FALSE;
2187 old_entry->tokens &= ~NNPFS_DATA_MASK;
2192 * Currently kernel never sends inactivenode w/o NNPFS_DELETE set, and
2193 * we don't handle that case properly (it's ignored).
2196 static int
2197 nnpfs_message_inactivenode (int fd, struct nnpfs_message_inactivenode *h,
2198 u_int size)
2200 FCacheEntry *entry;
2201 VenusFid *fid;
2203 if (h->flag & NNPFS_DELETE)
2204 fcache_cleaner_ref();
2206 fid = (VenusFid *)&h->handle;
2207 arla_warnx (ADEBMSG, "inactivenode (%ld.%lu.%lu.%lu)",
2208 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2209 (unsigned long)fid->fid.Vnode,
2210 (unsigned long)fid->fid.Unique);
2212 entry = fcache_find(*fid);
2213 if (!entry) {
2214 arla_warnx (ADEBWARN, "nnpfs_message_inactivenode: node not found "
2215 "(%ld.%lu.%lu.%lu)",
2216 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2217 (unsigned long)fid->fid.Vnode,
2218 (unsigned long)fid->fid.Unique);
2219 goto out;
2222 /* non-delete messages may arrive out of order w/ no harm */
2223 if ((h->flag & NNPFS_DELETE) == 0 && entry->flags.kernelp == 0)
2224 goto out;
2226 assert_flag(entry,kernelp);
2228 if (h->flag & NNPFS_DELETE) {
2229 struct nnpfs_message_delete_node msg;
2231 fcache_node_setkernelp(entry, FALSE);
2233 msg.handle = h->handle;
2234 msg.header.opcode = NNPFS_MSG_DELETE_NODE;
2235 nnpfs_message_send (kernel_fd,
2236 (struct nnpfs_message_header *)&msg,
2237 sizeof(msg));
2238 fcache_unused(entry);
2241 out:
2242 if (h->flag & NNPFS_DELETE)
2243 fcache_cleaner_deref();
2245 if (entry)
2246 fcache_release(entry);
2248 return 0;
2252 install_appendquota(int64_t diff)
2254 struct nnpfs_message_installquota msg;
2255 int ret;
2257 msg.header.opcode = NNPFS_MSG_INSTALLQUOTA;
2258 msg.appendbytes = diff;
2260 ret = nnpfs_message_send(kernel_fd, &msg.header, sizeof(msg));
2261 if (ret)
2262 arla_warnx(ADEBWARN, "install_appendquota returned %d", ret);
2263 assert(!ret);
2264 return ret;
2267 static void
2268 set_data_kernelp(VenusFid *fid, uint64_t offset, Bool kernelp)
2270 FCacheEntry *entry;
2271 int ret;
2273 if (kernelp) {
2274 worker_setdebuginfo("setkernelp find");
2275 entry = fcache_find(*fid);
2276 } else {
2277 worker_setdebuginfo("unsetkernelp find");
2278 entry = fcache_find_gcp(*fid, TRUE);
2281 if (!entry) {
2282 arla_warnx(ADEBWARN, "set_data_kernelp: node not found "
2283 "(%ld.%lu.%lu.%lu)",
2284 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2285 (unsigned long)fid->fid.Vnode,
2286 (unsigned long)fid->fid.Unique);
2287 return;
2290 /* messages may arrive out of order? */
2291 if (entry->flags.kernelp) {
2292 if (kernelp) {
2293 Bool exists = fcache_block_exists(entry, offset);
2294 if (exists) {
2295 arla_warnx(ADEBWARN, "set_data_kernelp: append on existing block"
2296 "(%ld.%lu.%lu.%lu)@%llu",
2297 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2298 (unsigned long)fid->fid.Vnode,
2299 (unsigned long)fid->fid.Unique,
2300 (unsigned long long)offset);
2302 worker_setdebuginfo("setkernelp");
2303 fcache_data_setkernelp(entry, offset, kernelp, FALSE);
2304 ret = install_appendquota(fcache_getblocksize());
2305 } else {
2306 ret = fcache_append_block(entry, offset);
2307 if (ret) {
2308 arla_warnx(ADEBWARN, "set_data_kernelp: "
2309 "create (%ld.%lu.%lu.%lu)@%llu returned %d",
2310 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2311 (unsigned long)fid->fid.Vnode,
2312 (unsigned long)fid->fid.Unique,
2313 (unsigned long long)offset,
2314 ret);
2315 } else {
2316 ret = fcache_update_appendquota(entry);
2318 entry->flags.appended = TRUE;
2320 } else {
2321 worker_setdebuginfo("setkernelp");
2322 fcache_data_setkernelp(entry, offset, kernelp, FALSE);
2324 } else {
2325 arla_warnx(ADEBWARN, "set_data_kernelp: node not in kernel "
2326 "(%ld.%lu.%lu.%lu)",
2327 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2328 (unsigned long)fid->fid.Vnode,
2329 (unsigned long)fid->fid.Unique);
2332 worker_setdebuginfo("release");
2333 fcache_release(entry);
2334 return;
2337 static int
2338 nnpfs_message_appenddata(int fd,struct nnpfs_message_appenddata *h, u_int size)
2340 VenusFid *fid = (VenusFid *)&h->handle;
2342 arla_warnx(ADEBMSG, "nnpfs_message_appenddata (%ld.%lu.%lu.%lu), offset %llu",
2343 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2344 (unsigned long)fid->fid.Vnode,
2345 (unsigned long)fid->fid.Unique,
2346 (unsigned long long)h->offset);
2348 set_data_kernelp(fid, h->offset, TRUE);
2350 return 0;
2354 * Block has been dropped from kernel.
2357 static int
2358 nnpfs_message_deletedata (int fd,struct nnpfs_message_deletedata *h, u_int size)
2360 VenusFid *fid = (VenusFid *)&h->handle;
2362 arla_warnx(ADEBMSG, "nnpfs_message_deletedata (%ld.%lu.%lu.%lu), offset %llu",
2363 (long)fid->Cell, (unsigned long)fid->fid.Volume,
2364 (unsigned long)fid->fid.Vnode,
2365 (unsigned long)fid->fid.Unique,
2366 (unsigned long long)h->offset);
2368 fcache_cleaner_ref();
2369 set_data_kernelp(fid, h->offset, FALSE);
2370 fcache_cleaner_deref();
2372 return 0;
2375 static int
2376 nnpfs_message_accesses (int fd,struct nnpfs_message_accesses *h, u_int size)
2378 arla_warnx(ADEBWARN, "accesses not implemented");
2380 return 0;
2385 * Do we have powers for changing stuff?
2388 static Bool
2389 all_powerful_p (const nnpfs_cred *cred)
2391 return cred->uid == 0;
2395 * Flush the contents of a volume
2398 static int
2399 viocflushvolume (int fd, struct nnpfs_message_pioctl *h, u_int size)
2401 VenusFid fid ;
2403 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2404 return EINVAL;
2406 fid.Cell = h->handle.a;
2407 fid.fid.Volume = h->handle.b;
2408 fid.fid.Vnode = 0;
2409 fid.fid.Unique = 0;
2411 arla_warnx(ADEBMSG,
2412 "flushing volume (%d, %u)",
2413 fid.Cell, fid.fid.Volume);
2415 fcache_purge_volume(fid);
2416 volcache_invalidate (fid.fid.Volume, fid.Cell);
2417 return 0 ;
2421 * Get an ACL for a directory
2424 static int
2425 viocgetacl(int fd, struct nnpfs_message_pioctl *h, u_int size)
2427 VenusFid fid;
2428 AFSOpaque opaque;
2429 CredCacheEntry *ce;
2430 int error;
2432 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2433 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2435 fid.Cell = h->handle.a;
2436 fid.fid.Volume = h->handle.b;
2437 fid.fid.Vnode = h->handle.c;
2438 fid.fid.Unique = h->handle.d;
2440 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2441 assert (ce != NULL);
2443 do {
2444 error = getacl (fid, ce, &opaque);
2445 } while (try_again (&error, &ce, &h->cred, &fid));
2447 if (error != 0 && error != EACCES)
2448 error = EINVAL;
2450 cred_free (ce);
2452 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
2453 opaque.val, opaque.len);
2454 if (error == 0)
2455 free (opaque.val);
2456 return 0;
2460 * Set an ACL for a directory
2463 static int
2464 viocsetacl(int fd, struct nnpfs_message_pioctl *h, u_int size)
2466 VenusFid fid;
2467 AFSOpaque opaque;
2468 CredCacheEntry *ce;
2469 FCacheEntry *e;
2470 int error;
2472 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2473 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2475 if (h->insize > AFSOPAQUEMAX || h->insize == 0)
2476 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2478 opaque.val = malloc(h->insize);
2479 if(opaque.val == NULL)
2480 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOMEM);
2482 fid.Cell = h->handle.a;
2483 fid.fid.Volume = h->handle.b;
2484 fid.fid.Vnode = h->handle.c;
2485 fid.fid.Unique = h->handle.d;
2487 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2488 assert (ce != NULL);
2490 opaque.len = h->insize;
2491 memcpy(opaque.val, h->msg, h->insize);
2493 do {
2494 error = setacl (fid, ce, &opaque, &e);
2495 } while (try_again (&error, &ce, &h->cred, &fid));
2497 if (error == 0) {
2498 install_attr (e, FCACHE2NNPFSNODE_ALL);
2499 fcache_release (e);
2500 } else if (error != EACCES)
2501 error = EINVAL;
2503 cred_free (ce);
2504 free (opaque.val);
2506 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error, NULL, 0);
2507 return 0;
2511 * Get volume status
2514 static int
2515 viocgetvolstat(int fd, struct nnpfs_message_pioctl *h, u_int size)
2517 VenusFid fid;
2518 CredCacheEntry *ce;
2519 AFSFetchVolumeStatus volstat;
2520 char volumename[AFSNAMEMAX];
2521 char offlinemsg[AFSOPAQUEMAX];
2522 char motd[AFSOPAQUEMAX];
2523 char out[SYSNAMEMAXLEN];
2524 int32_t outsize = 0;
2525 int error;
2527 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2528 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2530 fid.Cell = h->handle.a;
2531 fid.fid.Volume = h->handle.b;
2532 fid.fid.Vnode = 0;
2533 fid.fid.Unique = 0;
2535 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2536 assert (ce != NULL);
2538 memset (volumename, 0, AFSNAMEMAX);
2539 memset (offlinemsg, 0, AFSOPAQUEMAX);
2540 memset (motd, 0, AFSOPAQUEMAX);
2541 memset (out, 0, SYSNAMEMAXLEN);
2543 do {
2544 error = getvolstat (fid, ce, &volstat,
2545 volumename, sizeof(volumename),
2546 offlinemsg,
2547 motd);
2548 } while (try_again (&error, &ce, &h->cred, &fid));
2550 cred_free (ce);
2552 if (error != 0 && error != EACCES)
2553 error = EINVAL;
2555 memcpy (out, (char *) &volstat, sizeof (AFSFetchVolumeStatus));
2556 outsize = sizeof (AFSFetchVolumeStatus);
2558 if (volumename[0]) {
2559 strncpy (out+outsize, volumename, AFSNAMEMAX);
2560 outsize += strlen (volumename);
2562 else {
2563 out[outsize] = 0;
2564 outsize++;
2567 if (offlinemsg[0]) {
2568 strncpy (out+outsize, offlinemsg, AFSOPAQUEMAX);
2569 outsize += strlen (offlinemsg);
2571 else {
2572 out[outsize] = 0;
2573 outsize++;
2576 if (motd[0]) {
2577 strncpy (out+outsize, motd, AFSOPAQUEMAX);
2578 outsize += strlen (motd);
2580 else {
2581 out[outsize] = 0;
2582 outsize++;
2585 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
2586 out, outsize);
2587 return 0;
2591 * Set volume status
2594 static int
2595 viocsetvolstat(int fd, struct nnpfs_message_pioctl *h, u_int size)
2597 VenusFid fid;
2598 CredCacheEntry *ce;
2599 AFSFetchVolumeStatus *involstat;
2600 AFSStoreVolumeStatus outvolstat;
2601 char volumename[AFSNAMEMAX];
2602 char offlinemsg[AFSOPAQUEMAX];
2603 char motd[AFSOPAQUEMAX];
2604 int error;
2605 char *ptr;
2607 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2608 return EINVAL;
2610 fid.Cell = h->handle.a;
2611 fid.fid.Volume = h->handle.b;
2612 fid.fid.Vnode = 0;
2613 fid.fid.Unique = 0;
2615 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2616 assert (ce != NULL);
2618 involstat = (AFSFetchVolumeStatus *) h->msg;
2619 outvolstat.Mask = 0x3; /* Store both the next fields */
2620 outvolstat.MinQuota = involstat->MinQuota;
2621 outvolstat.MaxQuota = involstat->MaxQuota;
2623 ptr = h->msg + sizeof (AFSFetchVolumeStatus);
2625 #if 0
2626 if (*ptr) {
2627 strncpy (volumename, ptr, AFSNAMEMAX);
2628 ptr += strlen (ptr);
2630 else {
2631 memset (volumename, 0, AFSNAMEMAX);
2632 ptr++; /* skip 0 character */
2635 if (*ptr) {
2636 strncpy (offlinemsg, ptr, AFSOPAQUEMAX);
2637 ptr += strlen (ptr);
2639 else {
2640 memset (offlinemsg, 0, AFSOPAQUEMAX);
2641 ptr++;
2644 strncpy (motd, ptr, AFSOPAQUEMAX);
2645 #else
2646 volumename[0] = '\0';
2647 offlinemsg[0] = '\0';
2648 motd[0] = '\0';
2649 #endif
2651 do {
2652 error = setvolstat (fid, ce, &outvolstat, volumename,
2653 offlinemsg, motd);
2654 } while (try_again (&error, &ce, &h->cred, &fid));
2656 if (error != 0 && error != EACCES)
2657 error = EINVAL;
2659 cred_free (ce);
2661 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
2662 NULL, 0);
2663 return 0;
2667 * Get the mount point at (`fid', `filename') using the cred in `ce'
2668 * and returning the fcache entry in `ret_mp_entry'
2669 * Return 0 or an error.
2672 static int
2673 get_mount_point (VenusFid fid,
2674 const char *filename,
2675 CredCacheEntry **ce,
2676 FCacheEntry **ret_mp_entry)
2678 FCacheEntry *mp_entry;
2679 FCacheEntry *dentry;
2680 VenusFid mp_fid;
2681 int error;
2683 if (fid.fid.Volume == 0 && fid.fid.Vnode == 0 && fid.fid.Unique == 0)
2684 return EINVAL;
2686 error = fcache_get(&dentry, fid, *ce);
2687 if (error)
2688 return error;
2690 error = fcache_get_data(&dentry, ce, 0, 0);
2691 if (error) {
2692 fcache_release(dentry);
2693 return error;
2696 error = adir_lookup(dentry, filename, &mp_fid);
2697 if (error) {
2698 fcache_release(dentry);
2699 return error;
2702 if (VenusFid_cmp(&dentry->fid, &mp_fid) == 0) {
2703 mp_entry = dentry;
2704 } else {
2705 error = fcache_get(&mp_entry, mp_fid, *ce);
2706 if (error) {
2707 fcache_release(dentry);
2708 return error;
2712 error = fcache_verify_attr (mp_entry, dentry, filename, *ce);
2713 if (mp_entry != dentry)
2714 fcache_release(dentry);
2715 if (error) {
2716 fcache_release(mp_entry);
2717 return error;
2720 if ((mp_entry->status.FileType != TYPE_LINK
2721 && !mp_entry->flags.fake_mp)
2722 || fcache_get_status_length(&mp_entry->status) == 0) { /* Is not a mount point */
2723 fcache_release(mp_entry);
2724 return EINVAL;
2726 *ret_mp_entry = mp_entry;
2727 return 0;
2731 * Read the contents of the mount point in `mp_entry' into `buf',
2732 * check they look valid and null-terminate.
2733 * Return 0 or an error
2736 static int
2737 read_mount_point (FCacheEntry **mp_entry, CredCacheEntry **ce,
2738 char *buf, int buflen, int *outlen)
2740 int error;
2741 int len;
2742 fbuf f;
2744 error = fcache_get_data (mp_entry, ce, 0, 0);
2745 if (error)
2746 return error;
2748 error = fcache_get_fbuf(*mp_entry, &f, FBUF_READ);
2749 if (error)
2750 return error;
2752 len = fbuf_len(&f);
2753 if (len >= buflen || len <= 0) {
2754 abuf_end(&f);
2755 arla_warnx(ADEBWARN, "mountpoint with bad length: %d", len);
2756 return EIO;
2759 memcpy(buf, fbuf_buf(&f), buflen);
2760 abuf_end(&f);
2762 if (buf[0] != '#' && buf[0] != '%') /* Is not a mount point */
2763 return EINVAL;
2766 * To confuse us, the volume is passed up w/o the ending
2767 * dot. It's not even mentioned in the ``VIOC_AFS_STAT_MT_PT''
2768 * documentation.
2771 buf[len - 1] = '\0';
2772 *outlen = len;
2774 return 0;
2778 * Get info for a mount point.
2781 static int
2782 vioc_afs_stat_mt_pt(int fd, struct nnpfs_message_pioctl *h, u_int size)
2784 VenusFid fid;
2785 int error;
2786 CredCacheEntry *ce;
2787 FCacheEntry *e;
2788 char buf[MAXPATHLEN]; /* AFSNAMEMAX would suffice */
2789 int len;
2791 fid.Cell = h->handle.a;
2792 fid.fid.Volume = h->handle.b;
2793 fid.fid.Vnode = h->handle.c;
2794 fid.fid.Unique = h->handle.d;
2796 h->msg[min(h->insize, sizeof(h->msg)-1)] = '\0';
2798 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2799 assert (ce != NULL);
2801 error = get_mount_point (fid, h->msg, &ce, &e);
2802 if (error) {
2803 cred_free(ce);
2804 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
2807 error = read_mount_point(&e, &ce, buf, sizeof(buf), &len);
2808 if (error) {
2809 fcache_release (e);
2810 cred_free(ce);
2811 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
2814 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
2815 buf, len);
2816 fcache_release (e);
2817 cred_free (ce);
2819 return 0;
2823 * Handle the VIOC_AFS_DELETE_MT_PT message in `h' by deleting the
2824 * mountpoint.
2827 static int
2828 vioc_afs_delete_mt_pt(int fd, struct nnpfs_message_pioctl *h, u_int size)
2830 VenusFid fid;
2831 int error = 0;
2832 CredCacheEntry *ce;
2833 struct nnpfs_message_remove remove_msg;
2834 FCacheEntry *entry;
2836 h->msg[min(h->insize, sizeof(h->msg)-1)] = '\0';
2838 fid.Cell = h->handle.a;
2839 fid.fid.Volume = h->handle.b;
2840 fid.fid.Vnode = h->handle.c;
2841 fid.fid.Unique = h->handle.d;
2843 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2844 assert (ce != NULL);
2846 error = get_mount_point (fid, h->msg, &ce, &entry);
2847 cred_free (ce);
2848 if (error)
2849 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
2850 fcache_release(entry);
2852 remove_msg.header = h->header;
2853 remove_msg.header.size = sizeof(remove_msg);
2854 remove_msg.parent_handle = h->handle;
2855 strlcpy(remove_msg.name, h->msg, sizeof(remove_msg.name));
2856 remove_msg.cred = h->cred;
2858 return nnpfs_message_remove (fd, &remove_msg, sizeof(remove_msg));
2861 static int
2862 viocwhereis(int fd, struct nnpfs_message_pioctl *h, u_int size)
2864 VenusFid fid;
2865 CredCacheEntry *ce;
2866 FCacheEntry *e;
2867 int error;
2868 int i, j;
2869 int32_t addresses[8];
2870 int bit;
2872 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
2873 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2875 fid.Cell = h->handle.a;
2876 fid.fid.Volume = h->handle.b;
2877 fid.fid.Vnode = h->handle.c;
2878 fid.fid.Unique = h->handle.d;
2880 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
2881 assert (ce != NULL);
2883 error = fcache_get(&e, fid, ce);
2884 if (error) {
2885 cred_free(ce);
2886 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
2888 error = fcache_verify_attr (e, NULL, NULL, ce);
2889 if (error) {
2890 fcache_release(e);
2891 cred_free(ce);
2892 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
2895 bit = volcache_volid2bit (e->volume, fid.fid.Volume);
2897 if (bit == -1) {
2898 fcache_release(e);
2899 cred_free(ce);
2900 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
2903 memset(addresses, 0, sizeof(addresses));
2904 for (i = 0, j = 0; i < min(e->volume->entry.nServers, MAXNSERVERS); i++) {
2905 u_long addr = htonl(e->volume->entry.serverNumber[i]);
2907 if ((e->volume->entry.serverFlags[i] & bit) && addr != 0)
2908 addresses[j++] = addr;
2910 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
2911 addresses, sizeof(long) * j);
2913 fcache_release(e);
2914 cred_free (ce);
2916 return 0;
2920 * Return all db servers for a particular cell.
2923 static int
2924 vioc_get_cell(int fd, struct nnpfs_message_pioctl *h, u_int size)
2926 int i;
2927 int32_t index;
2928 const char *cellname;
2929 int cellname_len;
2930 int outsize;
2931 char out[8 * sizeof(int32_t) + MAXPATHLEN]; /* XXX */
2932 const cell_db_entry *dbservers;
2933 int num_dbservers;
2935 index = *((int32_t *) h->msg);
2936 cellname = cell_num2name(index);
2937 if (cellname == NULL)
2938 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EDOM);
2940 dbservers = cell_dbservers_by_id (index, &num_dbservers);
2942 if (dbservers == NULL)
2943 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EDOM);
2945 memset(out, 0, sizeof(out));
2946 cellname_len = min(strlen(cellname), MAXPATHLEN - 1);
2947 memcpy(out + 8 * sizeof(int32_t), cellname, cellname_len);
2948 out[8 * sizeof(int32_t) + cellname_len] = '\0';
2949 outsize = 8 * sizeof(int32_t) + cellname_len + 1;
2950 for (i = 0; i < min(num_dbservers, 8); ++i) {
2951 uint32_t addr = dbservers[i].addr.s_addr;
2952 memcpy (&out[i * sizeof(int32_t)], &addr, sizeof(int32_t));
2955 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
2956 out, outsize);
2958 return 0;
2962 * Return status information about a cell.
2965 static int
2966 vioc_get_cellstatus(int fd, struct nnpfs_message_pioctl *h, u_int size)
2968 char *cellname;
2969 int32_t cellid;
2970 uint32_t out = 0;
2972 cellname = h->msg;
2973 cellname[h->insize-1] = '\0';
2975 cellid = cell_name2num (cellname);
2976 if (cellid == -1)
2977 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOENT);
2979 if (cellid == 0)
2980 out |= arla_CELLSTATUS_PRIMARY;
2981 if (cell_issuid_by_num (cellid))
2982 out |= arla_CELLSTATUS_SETUID;
2984 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
2985 &out, sizeof(out));
2987 return 0;
2991 * Set status information about a cell.
2994 static int
2995 vioc_set_cellstatus(int fd, struct nnpfs_message_pioctl *h, u_int size)
2997 int32_t cellid;
2998 char *cellname;
2999 uint32_t in = 0;
3000 int ret;
3002 if (!all_powerful_p (&h->cred))
3003 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EACCES);
3005 if (h->insize < sizeof (in) + 2) /* terminating NUL and one char */
3006 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3008 cellname = h->msg + sizeof (in);
3009 cellname[h->insize-1-sizeof(in)] = '\0';
3011 cellid = cell_name2num (cellname);
3012 if (cellid == -1)
3013 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOENT);
3015 if (in & arla_CELLSTATUS_SETUID) {
3016 ret = cell_setsuid_by_num (cellid);
3017 if (ret)
3018 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,EINVAL);
3021 nnpfs_send_message_wakeup (fd, h->header.sequence_num, 0);
3023 return 0;
3027 * Set information about a cell or add a new one.
3030 static int
3031 vioc_new_cell(int fd, struct nnpfs_message_pioctl *h, u_int size)
3033 const char *cellname;
3034 cell_entry *ce;
3035 int count, i;
3036 uint32_t *hp;
3037 cell_db_entry *dbs;
3039 if (!all_powerful_p (&h->cred))
3040 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EPERM);
3042 if (h->insize < 9)
3043 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3045 hp = (uint32_t *)h->msg;
3046 for (count = 0; *hp != 0; ++hp)
3047 ++count;
3049 dbs = malloc (count * sizeof(*dbs));
3050 if (dbs == NULL)
3051 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOMEM);
3053 memset(dbs, 0, count * sizeof(*dbs));
3055 hp = (uint32_t *)h->msg;
3056 for (i = 0; i < count; ++i) {
3057 dbs[i].name = NULL;
3058 dbs[i].addr.s_addr = hp[i];
3059 dbs[i].timeout = 0;
3062 cellname = h->msg + 8 * sizeof(uint32_t);
3063 ce = cell_get_by_name (cellname);
3064 if (ce == NULL) {
3065 ce = cell_new_dynamic (cellname);
3067 if (ce == NULL) {
3068 free (dbs);
3069 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
3070 ENOMEM);
3072 } else {
3073 free (ce->dbservers);
3076 ce->ndbservers = count;
3077 ce->dbservers = dbs;
3079 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, 0);
3082 #ifdef KERBEROS
3085 * Return the token for the cell in `ce'
3088 static int
3089 token_for_cell (int fd, struct nnpfs_message_pioctl *h, u_int size,
3090 CredCacheEntry *ce)
3092 char buf[NNPFS_MSG_MAX_DATASIZE];
3093 size_t len, cell_len;
3094 char *p = buf;
3095 uint32_t tmp;
3096 struct cred_rxkad *cred = (struct cred_rxkad *)ce->cred_data;
3097 const char *cell = cell_num2name (ce->cell);
3099 cell_len = strlen(cell);
3101 len = 4 + cred->ticket_len + 4 + sizeof(cred->ct) + 4 + cell_len;
3102 if (len > sizeof(buf))
3103 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3105 tmp = cred->ticket_len;
3106 memcpy (p, &tmp, sizeof(tmp));
3107 p += sizeof(tmp);
3108 memcpy (p, cred->ticket, tmp);
3109 p += tmp;
3110 tmp = sizeof(cred->ct);
3111 memcpy (p, &tmp, sizeof(tmp));
3112 p += sizeof(tmp);
3113 memcpy (p, &cred->ct, sizeof(cred->ct));
3114 p += sizeof(cred->ct);
3115 tmp = 0;
3116 memcpy (p, &tmp, sizeof(tmp));
3117 p += sizeof(tmp);
3118 strcpy (p, cell);
3119 p += strlen(cell) + 1;
3121 len = p - buf;
3123 cred_free (ce);
3125 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
3126 buf, len);
3127 return 0;
3130 struct get_tok {
3131 int32_t counter;
3132 int32_t cell;
3135 static int
3136 gettok_func(CredCacheEntry *ce, void *ptr)
3138 struct get_tok *gt = ptr;
3140 if (gt->counter == 0) {
3141 gt->cell = ce->cell;
3142 return 1;
3145 gt->counter--;
3146 return 0;
3151 * Handle the GETTOK message in `h'
3154 static int
3155 viocgettok (int fd, struct nnpfs_message_pioctl *h, u_int size)
3157 CredCacheEntry *ce;
3158 int32_t cell_id;
3160 if (h->insize == 0) {
3161 cell_id = cell_name2num(cell_getthiscell());
3162 } else if (h->insize == sizeof(uint32_t)) {
3163 struct get_tok gt;
3164 int32_t n;
3166 memcpy (&n, h->msg, sizeof(n));
3168 if (n < 0) {
3169 nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3170 return 0;
3173 gt.counter = n;
3174 gt.cell = -1;
3176 cred_list_pag(h->cred.pag, CRED_KRB4, gettok_func, &gt);
3178 if (gt.cell == -1) {
3179 nnpfs_send_message_wakeup (fd, h->header.sequence_num, EDOM);
3180 return 0;
3183 cell_id = gt.cell;
3184 } else {
3185 nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3186 return 0;
3189 ce = cred_get (cell_id, h->cred.pag, CRED_KRB4);
3190 if (ce == NULL) {
3191 nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOTCONN);
3192 return 0;
3195 return token_for_cell (fd, h, size, ce);
3199 * Handle the SETTOK message in `h'
3202 static int
3203 viocsettok (int fd, struct nnpfs_message_pioctl *h, u_int size)
3205 struct cred_rxkad cred;
3206 long cell;
3207 char realm[256];
3208 int32_t sizeof_x;
3209 char *t = h->msg;
3211 /* someone probed us */
3212 if (h->insize == 0)
3213 return EINVAL;
3214 if (h->insize < 4)
3215 return EINVAL;
3217 /* Get ticket_st */
3218 memcpy(&sizeof_x, t, sizeof(sizeof_x)) ;
3219 cred.ticket_len = sizeof_x;
3220 arla_warnx (ADEBMSG, "ticket_st has size %d", sizeof_x);
3221 t += sizeof(sizeof_x) ;
3223 /* data used + datalen + cleartoken's length field */
3224 if ((t - (char *)h->msg) + sizeof_x + 4 > h->insize)
3225 return EINVAL;
3226 if (sizeof_x > sizeof(cred.ticket))
3227 return EINVAL;
3229 memcpy(cred.ticket, t, sizeof_x) ;
3230 t += sizeof_x ;
3232 /* Get ClearToken */
3233 memcpy(&sizeof_x, t, sizeof(sizeof_x)) ;
3234 t += sizeof(sizeof_x) ;
3236 /* data used + datalen + cell's length field */
3237 if ((t - (char *)h->msg) + sizeof_x + 4 > h->insize)
3238 return EINVAL;
3240 memcpy(&cred.ct, t, sizeof_x) ;
3241 t += sizeof_x ;
3243 /* Get primary cell ? */
3244 memcpy(&sizeof_x, t, sizeof(sizeof_x)) ;
3245 t += sizeof(sizeof_x) ;
3247 /* Get Cellname */
3248 strlcpy(realm, t, min(h->insize - (t - (char *)h->msg), sizeof(realm)));
3249 strlwr(realm);
3251 cell = cell_name2num(realm);
3253 if (cell == -1)
3254 return ENOENT;
3256 conn_clearcred (CONN_CS_ALL, cell, h->cred.pag, 2);
3257 fcache_purge_cred(h->cred.pag, cell);
3258 cred_add (h->cred.pag, CRED_KRB4, 2, cell, cred.ct.EndTimestamp,
3259 &cred, sizeof(cred), cred.ct.ViceId);
3260 return 0;
3263 static int
3264 viocunlog (int fd, struct nnpfs_message_pioctl *h, u_int size)
3266 nnpfs_pag_t cred = h->cred.pag;
3268 cred_remove(cred);
3269 fcache_purge_cred(cred, -1);
3270 return 0;
3273 #if defined(HAVE_KRB5) && defined(WITH_RXGK)
3276 * handle rxgk kerberos 5 authenticator
3278 * format:
3279 * int32_t ticket_len
3280 * char krb5_ticket[];
3281 * int32_t kvno;
3282 * int32_t krb5_enctype;
3283 * int32_t viceid;
3284 * int32_t sessionkey_len;
3285 * char sessionkey[];
3286 * int64_t start_time;
3287 * int64_t expiration_time;
3288 * char cell[]
3291 size_t k5ticket_limit_size = 40 * 1024;
3293 static int
3294 k5settok (int fd, struct nnpfs_message_pioctl *h, u_int size)
3296 struct cred_rxgk c;
3297 char cellname[256];
3298 uint32_t sizeof_x;
3299 uint64_t endtime;
3300 int32_t viceid;
3301 long cell;
3302 char *t = h->msg;
3303 int insize = h->insize;
3305 if (insize < 4)
3306 return EINVAL;
3308 memcpy(&sizeof_x, t, sizeof(sizeof_x)) ;
3309 arla_warnx (ADEBMSG, "ticket has size %d", sizeof_x);
3310 t += sizeof(sizeof_x) ;
3312 if (sizeof_x < k5ticket_limit_size || sizeof_x > insize)
3313 return EINVAL;
3315 c.type = CRED_GK_K5;
3317 c.t.k5.ticket = malloc(sizeof_x);
3318 if (c.t.k5.ticket == NULL)
3319 return ENOMEM;
3321 memcpy(c.t.k5.ticket, t, sizeof_x);
3322 insize -= sizeof_x;
3323 t += sizeof_x;
3325 if (h->insize < 4 + 4 + 4 + 4) {
3326 free(c.t.k5.ticket);
3327 return EINVAL;
3330 memcpy(&sizeof_x, t, sizeof(sizeof_x));
3331 t += sizeof(sizeof_x); insize -= sizeof(sizeof_x);
3332 c.t.k5.enctype = sizeof_x;
3334 memcpy(&sizeof_x, t, sizeof(sizeof_x));
3335 t += sizeof(sizeof_x); insize -= sizeof(sizeof_x);
3336 c.t.k5.kvno = sizeof_x;
3338 memcpy(&sizeof_x, t, sizeof(sizeof_x));
3339 t += sizeof(sizeof_x); insize -= sizeof(sizeof_x);
3340 viceid = sizeof_x;
3342 memcpy(&sizeof_x, t, sizeof(sizeof_x));
3343 t += sizeof(sizeof_x); insize -= sizeof(sizeof_x);
3344 c.t.k5.sessionkey_len = sizeof_x;
3346 if (sizeof_x < k5ticket_limit_size || sizeof_x > insize) {
3347 free(c.t.k5.ticket);
3348 return EINVAL;
3351 c.t.k5.sessionkey = malloc(c.t.k5.sessionkey_len);
3352 if (c.t.k5.sessionkey == NULL) {
3353 free(c.t.k5.ticket);
3354 return EINVAL;
3357 memcpy(c.t.k5.sessionkey, t, c.t.k5.sessionkey_len);
3358 t += c.t.k5.sessionkey_len;
3359 insize -= c.t.k5.sessionkey_len;
3362 if (insize < 8 + 8 + 1) {
3363 free(c.t.k5.sessionkey);
3364 free(c.t.k5.ticket);
3365 return EINVAL;
3368 t += 8;
3369 insize -= 8;
3371 memcpy(&endtime, t, sizeof(endtime));
3372 t += 8;
3373 insize -= 8;
3375 if (insize > sizeof(cellname) || t[insize - 1] != '\0') {
3376 free(c.t.k5.sessionkey);
3377 free(c.t.k5.ticket);
3378 return EINVAL;
3381 strlcpy(cellname, t, sizeof(cellname));
3383 cell = cell_name2num(strlwr(cellname));
3385 if (cell == -1) {
3386 free(c.t.k5.sessionkey);
3387 free(c.t.k5.ticket);
3388 return ENOENT;
3391 conn_clearcred (CONN_CS_ALL, cell, h->cred.pag, 2);
3392 fcache_purge_cred(h->cred.pag, cell);
3393 cred_add (h->cred.pag, CRED_GK_K5, 2, cell, (time_t)endtime,
3394 &c, sizeof(c), viceid);
3395 return 0;
3398 #endif /* HAVE_KRB5 && WITH_RXGK */
3400 #endif /* KERBEROS */
3403 * Flush the fid in `h->handle' from the cache.
3406 static int
3407 viocflush (int fd, struct nnpfs_message_pioctl *h, u_int size)
3409 VenusFid fid ;
3410 AFSCallBack broken_callback = {0, 0, CBDROPPED};
3412 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
3413 return EINVAL;
3415 fid.Cell = h->handle.a;
3416 fid.fid.Volume = h->handle.b;
3417 fid.fid.Vnode = h->handle.c;
3418 fid.fid.Unique = h->handle.d;
3420 arla_warnx(ADEBMSG,
3421 "flushing (%d, %u, %u, %u)",
3422 fid.Cell, fid.fid.Volume, fid.fid.Vnode, fid.fid.Unique);
3424 fcache_stale_entry(fid, broken_callback);
3425 return 0 ;
3429 get_connmode(int32_t *mode)
3431 switch(connected_mode) {
3432 case CONNECTED:
3433 *mode = arla_CONNMODE_CONN; break;
3434 case FETCH_ONLY:
3435 *mode = arla_CONNMODE_FETCH; break;
3436 case DISCONNECTED:
3437 *mode = arla_CONNMODE_DISCONN; break;
3438 default:
3439 *mode = 0;
3440 return EINVAL;
3442 return 0;
3446 set_connmode(int32_t mode, nnpfs_cred *cred)
3448 switch(mode) {
3449 case arla_CONNMODE_CONN:
3450 case arla_CONNMODE_CONN_WITHCALLBACKS:
3451 if (connected_mode == CONNECTED)
3452 return 0;
3454 disco_closelog();
3456 cmcb_reinit();
3458 if (connected_mode == DISCONNECTED)
3459 fcache_discard_attrs();
3461 if (disco_need_integrate())
3462 disco_reintegrate(cred->pag);
3464 if (mode == arla_CONNMODE_CONN_WITHCALLBACKS)
3465 fcache_reobtain_callbacks (cred);
3467 connected_mode = CONNECTED;
3468 break;
3469 case arla_CONNMODE_FETCH:
3470 if (connected_mode == CONNECTED)
3471 disco_openlog();
3473 if (connected_mode == DISCONNECTED)
3474 fcache_discard_attrs();
3476 connected_mode = FETCH_ONLY;
3477 break;
3478 case arla_CONNMODE_DISCONN:
3479 if (connected_mode == CONNECTED)
3480 disco_openlog();
3482 if (possibly_have_network())
3483 fcache_giveup_all_callbacks();
3485 connected_mode = DISCONNECTED;
3486 break;
3487 default:
3488 return EINVAL;
3489 break;
3491 return 0;
3494 static int
3495 viocconnect(int fd, struct nnpfs_message_pioctl *h, u_int size)
3497 char *p = h->msg;
3498 int32_t tmp;
3499 int32_t ret;
3500 int error = 0;
3502 if (h->insize != sizeof(int32_t) ||
3503 h->outsize != sizeof(int32_t)) {
3505 ret = -EINVAL;
3506 } else {
3508 memcpy(&tmp, h->msg, sizeof(tmp));
3509 p += sizeof(tmp);
3511 ret = tmp;
3513 /* check permission */
3514 switch (tmp) {
3515 case arla_CONNMODE_PROBE:
3516 break;
3517 default:
3518 if (!all_powerful_p(&h->cred))
3519 return EPERM;
3520 break;
3523 switch(tmp) {
3524 case arla_CONNMODE_PROBE:
3525 error = get_connmode(&ret);
3526 break;
3527 default:
3528 error = set_connmode(tmp, &h->cred);
3529 break;
3533 nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, error,
3534 &ret, sizeof(ret));
3535 return 0;
3538 static int
3539 getrxkcrypt(int fd, struct nnpfs_message_pioctl *h, u_int size)
3541 if (h->outsize == sizeof(uint32_t)) {
3542 uint32_t n;
3544 #ifdef KERBEROS
3545 if (conn_rxkad_level == rxkad_crypt)
3546 n = 1;
3547 else
3548 #endif
3549 n = 0;
3551 return nnpfs_send_message_wakeup_data (fd,
3552 h->header.sequence_num,
3555 sizeof(n));
3556 } else
3557 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3560 static int
3561 setrxkcrypt(int fd, struct nnpfs_message_pioctl *h, u_int size)
3563 #ifdef KERBEROS
3564 int error = 0;
3566 if (!all_powerful_p(&h->cred))
3567 return EPERM;
3569 if (h->insize == sizeof(uint32_t)) {
3570 uint32_t n;
3572 memcpy (&n, h->msg, sizeof(n));
3574 if (n == 0)
3575 conn_rxkad_level = rxkad_auth;
3576 else if(n == 1)
3577 conn_rxkad_level = rxkad_crypt;
3578 else
3579 error = EINVAL;
3580 if (error == 0)
3581 conn_clearcred (CONN_CS_SECIDX, 0, -1, 2);
3582 } else
3583 error = EINVAL;
3584 return error;
3585 #else
3586 return EOPNOTSUPP;
3587 #endif
3591 * XXX - this function sometimes does a wakeup_data and then an ordinary wakeup is sent in nnpfs_message_pioctl
3594 static int
3595 vioc_fpriostatus (int fd, struct nnpfs_message_pioctl *h, u_int size)
3597 struct arla_vioc_fprio *fprio;
3598 int error = 0;
3599 VenusFid fid;
3601 if (h->insize != sizeof(struct arla_vioc_fprio))
3602 return EINVAL;
3604 fprio = (struct arla_vioc_fprio *) h->msg;
3606 fid.Cell = fprio->Cell ;
3607 fid.fid.Volume = fprio->Volume ;
3608 fid.fid.Vnode = fprio->Vnode ;
3609 fid.fid.Unique = fprio->Unique ;
3611 if (!all_powerful_p(&h->cred))
3612 return EPERM;
3614 #if 0
3615 switch(fprio->cmd) {
3616 case FPRIO_GET: {
3617 unsigned prio;
3619 if (h->outsize != sizeof(unsigned)) {
3620 error = EINVAL;
3621 break;
3624 prio = fprio_get(fid);
3625 nnpfs_send_message_wakeup_data (fd,
3626 h->header.sequence_num,
3628 &prio,
3629 sizeof(prio));
3631 break;
3633 case FPRIO_SET:
3634 if (fprio->prio == 0) {
3635 fprio_remove(fid);
3636 error = 0;
3637 } else if (fprio->prio < FPRIO_MIN ||
3638 fprio->prio > FPRIO_MAX)
3639 error = EINVAL;
3640 else {
3641 fprio_set(fid, fprio->prio);
3642 error = 0;
3644 break;
3645 case FPRIO_GETMAX:
3646 if (h->outsize != sizeof(unsigned)) {
3647 error = EINVAL;
3648 break;
3651 nnpfs_send_message_wakeup_data (fd,
3652 h->header.sequence_num,
3654 &fprioritylevel,
3655 sizeof(fprioritylevel));
3656 error = 0;
3657 break;
3658 case FPRIO_SETMAX:
3659 if (fprio->prio < FPRIO_MIN ||
3660 fprio->prio > FPRIO_MAX)
3661 error = EINVAL;
3662 else {
3663 fprioritylevel = fprio->prio;
3664 error = 0;
3666 break;
3667 default:
3668 error = EINVAL;
3669 break;
3671 #endif
3672 return error;
3675 static int
3676 viocgetfid (int fd, struct nnpfs_message_pioctl *h, u_int size)
3678 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
3679 &h->handle, sizeof(VenusFid));
3682 static int
3683 viocvenuslog (int fd, struct nnpfs_message_pioctl *h, u_int size)
3685 if (!all_powerful_p(&h->cred))
3686 return EPERM;
3688 conn_status ();
3689 volcache_status ();
3690 cred_status ();
3691 fcache_status ();
3692 cell_status (stderr);
3693 #if 0
3694 fprio_status ();
3695 #endif
3696 rx_PrintStats(stderr);
3697 worker_printstatus();
3698 return 0;
3702 * Set or get the sysname
3705 static int
3706 vioc_afs_sysname (int fd, struct nnpfs_message_pioctl *h, u_int size)
3708 char *t = h->msg;
3709 int32_t parm = *((int32_t *)t);
3711 if (parm) {
3712 char t_sysname[SYSNAMEMAXLEN];
3713 int size;
3715 if (!all_powerful_p (&h->cred))
3716 return nnpfs_send_message_wakeup (fd,
3717 h->header.sequence_num,
3718 EPERM);
3719 t += sizeof(int32_t);
3720 arla_warnx (ADEBMSG, "VIOC_AFS_SYSNAME: setting sysname: %s", t);
3722 size = min(h->insize, SYSNAMEMAXLEN);
3724 memcpy(t_sysname, t, size);
3725 t_sysname[size - 1] = '\0';
3727 fcache_setdefsysname (t_sysname);
3729 return nnpfs_send_message_wakeup(fd, h->header.sequence_num, 0);
3730 } else {
3731 char *buf;
3732 const char *sysname = fcache_getdefsysname ();
3733 size_t sysname_len = strlen (sysname);
3734 int ret;
3736 buf = malloc (sysname_len + 4 + 1);
3737 if (buf == NULL)
3738 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
3739 ENOMEM);
3740 /* Return always 1 as we do not support sysname lists. */
3741 /* Historically the value of this uint32 has been success/failure. */
3742 /* OpenAFS' utilities treat this value as the number of elements */
3743 /* in a list of returned sysnames. It was never meant to be buflen.*/
3744 *((uint32_t *)buf) = 1;
3745 memcpy (buf + 4, sysname, sysname_len);
3746 buf[sysname_len + 4] = '\0';
3748 ret = nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
3749 buf, sysname_len + 5);
3750 free (buf);
3751 return ret;
3755 static int
3756 viocfilecellname (int fd, struct nnpfs_message_pioctl *h, u_int size)
3758 char *cellname;
3760 cellname = (char *) cell_num2name(h->handle.a);
3762 if (cellname)
3763 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
3764 cellname, strlen(cellname)+1);
3765 else
3766 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, EINVAL,
3767 NULL, 0);
3770 static int
3771 viocgetwscell (int fd, struct nnpfs_message_pioctl *h, u_int size)
3773 char *cellname;
3775 cellname = (char*) cell_getthiscell();
3776 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
3777 cellname, strlen(cellname)+1);
3780 static int
3781 viocsetcachesize (int fd, struct nnpfs_message_pioctl *h, u_int size)
3783 uint32_t *s = (uint32_t *)h->msg;
3785 if (!all_powerful_p (&h->cred))
3786 return EPERM;
3788 if (h->insize >= sizeof(int32_t) * 4)
3789 return fcache_reinit(s[0], s[1], s[2], s[3]);
3790 else
3791 return fcache_reinit(*s/2, *s, *s*500, *s*1000);
3795 * VIOCCKSERV
3797 * in: flags - bitmask (1 - dont ping, use cached data, 2 - check fsservers only)
3798 * cell - string (optional)
3799 * out: hosts - uint32_t number of hosts, followed by list of hosts being down.
3802 static int
3803 viocckserv (int fd, struct nnpfs_message_pioctl *h, u_int size)
3805 int32_t cell = cell_name2num (cell_getthiscell());
3806 int flags = 0;
3807 int num_entries;
3808 uint32_t hosts[arla_CKSERV_MAXSERVERS + 1];
3809 int msg_size;
3811 if (h->insize < sizeof(int32_t))
3812 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, EINVAL);
3814 memset (hosts, 0, sizeof(hosts));
3816 flags = *(uint32_t *)h->msg;
3817 flags &= arla_CKSERV_DONTPING|arla_CKSERV_FSONLY;
3819 if (h->insize > sizeof(int32_t)) {
3820 h->msg[min(h->insize, sizeof(h->msg)-1)] = '\0';
3822 cell = cell_name2num (((char *)h->msg) + sizeof(int32_t));
3823 if (cell == -1)
3824 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, ENOENT);
3827 num_entries = arla_CKSERV_MAXSERVERS;
3829 conn_downhosts(cell, hosts + 1, &num_entries, flags);
3831 hosts[0] = num_entries;
3832 msg_size = sizeof(hosts[0]) * (num_entries + 1);
3833 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
3834 hosts, msg_size);
3839 * Return the number of used KBs and reserved KBs
3842 static int
3843 viocgetcacheparms (int fd, struct nnpfs_message_pioctl *h, u_int size)
3845 uint32_t parms[16];
3847 memset(parms, 0, sizeof(parms));
3848 parms[0] = fcache_highbytes() / 1024;
3849 parms[1] = fcache_usedbytes() / 1024;
3850 parms[2] = fcache_highvnodes();
3851 parms[3] = fcache_usedvnodes();
3852 parms[4] = fcache_highbytes();
3853 parms[5] = fcache_usedbytes();
3854 parms[6] = fcache_lowbytes();
3855 parms[7] = fcache_lowvnodes();
3857 h->outsize = sizeof(parms);
3858 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
3859 parms, sizeof(parms));
3863 * debugging interface to give out statistics of the cache
3866 static int
3867 viocaviator (int fd, struct nnpfs_message_pioctl *h, u_int size)
3869 uint32_t parms[16];
3871 memset(parms, 0, sizeof(parms));
3872 parms[0] = kernel_highworkers();
3873 parms[1] = kernel_usedworkers();
3875 h->outsize = sizeof(parms);
3876 return nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
3877 parms, sizeof(parms));
3881 * Get/set arla debug level
3884 static int
3885 vioc_arladebug (int fd, struct nnpfs_message_pioctl *h, u_int size)
3887 if (h->insize != 0) {
3888 if (h->insize < sizeof(int32_t))
3889 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
3890 EINVAL);
3891 if (!all_powerful_p (&h->cred))
3892 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
3893 EPERM);
3894 arla_log_set_level_num (*((int32_t *)h->msg));
3896 if (h->outsize != 0) {
3897 int32_t debug_level;
3899 if (h->outsize < sizeof(int32_t))
3900 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
3901 EINVAL);
3903 debug_level = arla_log_get_level_num ();
3904 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num,
3905 0, &debug_level,
3906 sizeof(debug_level));
3908 return nnpfs_send_message_wakeup (fd, h->header.sequence_num, 0);
3912 * GC pags --- there shouldn't be any need to do anything here.
3915 static int
3916 vioc_gcpags (int fd, struct nnpfs_message_pioctl *h, u_int size)
3918 return 0;
3922 * Break the callback of the specified fid
3925 static int
3926 vioc_calculate_cache (int fd, struct nnpfs_message_pioctl *h, u_int size)
3928 uint32_t parms[16];
3930 memset(parms, 0, sizeof(parms));
3932 if (!all_powerful_p(&h->cred))
3933 return EPERM;
3935 h->outsize = sizeof(parms);
3937 parms[0] = fcache_calculate_usage();
3938 parms[1] = fcache_usedbytes();
3940 arla_warnx (ADEBMISC,
3941 "diskusage = %d, usedbytes = %d",
3942 parms[0], parms[1]);
3944 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
3945 &parms, sizeof(parms));
3952 static int
3953 vioc_breakcallback(int fd, struct nnpfs_message_pioctl *h, u_int size)
3955 int error;
3956 VenusFid fid;
3957 FCacheEntry *e;
3958 CredCacheEntry *ce;
3960 if (!all_powerful_p(&h->cred))
3961 return EPERM;
3963 if (!h->handle.a && !h->handle.b && !h->handle.c && !h->handle.d)
3964 return EINVAL;
3966 fid.Cell = h->handle.a;
3967 fid.fid.Volume = h->handle.b;
3968 fid.fid.Vnode = h->handle.c;
3969 fid.fid.Unique = h->handle.d;
3971 ce = cred_get (fid.Cell, h->cred.pag, CRED_ANY);
3972 assert (ce != NULL);
3974 error = fcache_get(&e, fid, ce);
3975 if (error)
3976 return error;
3978 if (!e->flags.kernelp) {
3979 cred_free (ce);
3980 return -ENOENT;
3983 break_callback (e);
3985 fcache_release (e);
3986 cred_free (ce);
3988 return 0;
3992 * check volume mappings
3995 static int
3996 vioc_ckback(int fd, struct nnpfs_message_pioctl *h, u_int size)
3998 volcache_invalidate_all ();
3999 fcache_invalidate_mp ();
4000 return 0;
4004 * checks if caller has the rights in h->msg
4007 static int
4008 viocaccess(int fd, struct nnpfs_message_pioctl *h, u_int size)
4010 VenusFid fid;
4011 CredCacheEntry *ce;
4012 int ret = 0;
4013 FCacheEntry *entry = NULL;
4014 int32_t *rights = (int32_t *) h->msg;
4016 if (h->insize != sizeof(int32_t)) {
4017 ret = EINVAL;
4018 goto out;
4021 fid.Cell = h->handle.a;
4022 fid.fid.Volume = h->handle.b;
4023 fid.fid.Vnode = h->handle.c;
4024 fid.fid.Unique = h->handle.d;
4026 ce = cred_get(fid.Cell, h->cred.pag, CRED_ANY);
4027 assert(ce != NULL);
4029 ret = fcache_get (&entry, fid, ce);
4030 if (ret)
4031 goto out;
4033 /* Two reasons for calling read_attr explicitly:
4034 1. To get our hands on any error code.
4035 2. To make sure the server is asked, since
4036 you don't get callback for change of ACL.
4038 Still, it is inefficient...
4040 ret = read_attr(entry, ce);
4041 if (ret)
4042 goto out;
4045 errno = 0;
4046 ret = cm_checkright(entry, *rights, ce);
4048 out:
4049 nnpfs_send_message_wakeup(fd, h->header.sequence_num, ret);
4050 if (entry)
4051 fcache_release(entry);
4052 cred_free (ce);
4054 return 0;
4057 static int
4058 vioc_getvcxstatus2(int fd, struct nnpfs_message_pioctl *h, u_int size)
4060 VenusFid fid;
4061 CredCacheEntry *ce;
4062 int ret = 0;
4063 FCacheEntry *entry = NULL;
4064 struct afs_vcxstat2 stat;
4066 fid.Cell = h->handle.a;
4067 fid.fid.Volume = h->handle.b;
4068 fid.fid.Vnode = h->handle.c;
4069 fid.fid.Unique = h->handle.d;
4071 ce = cred_get(fid.Cell, h->cred.pag, CRED_ANY);
4072 assert(ce != NULL);
4074 ret = fcache_get(&entry, fid, ce);
4075 if (ret)
4076 goto out;
4078 /* ret = read_attr(entry, ce);
4080 * You don't get callback for change of ACL. So you would need
4081 * to explicitly ask server to make sure you get correct
4082 * access-fields. But it is to inefficient...
4085 ret = fcache_verify_attr(entry, NULL, NULL, ce);
4086 if (ret)
4087 goto out;
4089 stat.callerAccess = entry->status.CallerAccess;
4090 stat.cbExpires = entry->callback.ExpirationTime;
4091 stat.anyAccess = entry->anonaccess;
4093 if (entry->flags.mountp)
4094 stat.mvstat = 1;
4095 else if (entry->flags.vol_root)
4096 stat.mvstat = 2;
4097 else
4098 stat.mvstat = 0;
4100 out:
4101 if (ret) {
4102 nnpfs_send_message_wakeup(fd, h->header.sequence_num, ret);
4103 } else {
4104 nnpfs_send_message_wakeup_data(fd, h->header.sequence_num, 0,
4105 (char *) &stat, sizeof(stat));
4107 if (entry)
4108 fcache_release(entry);
4109 cred_free (ce);
4111 return 0;
4114 static int
4115 statistics_hostpart(int fd, struct nnpfs_message_pioctl *h, u_int size)
4117 uint32_t host[100];
4118 uint32_t part[100];
4119 uint32_t outparms[512];
4120 int n;
4121 int outsize;
4122 int maxslots;
4123 int i;
4125 if (h->outsize < sizeof(uint32_t))
4126 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4127 EINVAL);
4129 n = 100;
4130 collectstats_hostpart(host, part, &n);
4131 maxslots = (h->outsize / sizeof(uint32_t) - 1) / 2;
4132 if (n > maxslots)
4133 n = maxslots;
4135 outsize = (n * 2 + 1) * sizeof(uint32_t);
4137 outparms[0] = n;
4138 for (i = 0; i < n; i++) {
4139 outparms[i*2 + 1] = host[i];
4140 outparms[i*2 + 2] = part[i];
4143 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
4144 (char *) &outparms, outsize);
4147 static int
4148 statistics_entry(int fd, struct nnpfs_message_pioctl *h, u_int size)
4150 uint32_t *request = (uint32_t *) h->msg;
4151 uint32_t host;
4152 uint32_t part;
4153 uint32_t type;
4154 uint32_t items_slot;
4155 uint32_t count[32];
4156 int64_t items_total[32];
4157 int64_t total_time[32];
4158 uint32_t outparms[160];
4159 int i;
4160 int j;
4162 if (h->insize < sizeof(uint32_t) * 5) {
4163 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4164 EINVAL);
4167 if (h->outsize < sizeof(uint32_t) * 160) {
4168 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4169 EINVAL);
4172 host = request[1];
4173 part = request[2];
4174 type = request[3];
4175 items_slot = request[4];
4177 collectstats_getentry(host, part, type, items_slot,
4178 count, items_total, total_time);
4180 j = 0;
4181 for (i = 0; i < 32; i++) {
4182 outparms[j++] = count[i];
4184 for (i = 0; i < 32; i++) {
4185 memcpy(&outparms[j], &items_total[i], 8);
4186 j+=2;
4188 for (i = 0; i < 32; i++) {
4189 memcpy(&outparms[j], &total_time[i], 8);
4190 j+=2;
4192 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
4193 (char *) &outparms, sizeof(outparms));
4196 static int
4197 aioc_statistics(int fd, struct nnpfs_message_pioctl *h, u_int size)
4199 uint32_t opcode;
4201 if (!all_powerful_p (&h->cred))
4202 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4203 EPERM);
4205 if (h->insize < sizeof(opcode))
4206 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4207 EPERM);
4209 memcpy(&opcode, &h->msg, sizeof(opcode));
4211 switch (opcode) {
4212 case arla_STATISTICS_OPCODE_LIST:
4213 return statistics_hostpart(fd, h, size);
4214 case arla_STATISTICS_OPCODE_GETENTRY:
4215 return statistics_entry(fd, h, size);
4216 default:
4217 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4218 EINVAL);
4223 static int
4224 aioc_getcacheparam(int fd, struct nnpfs_message_pioctl *h, u_int size)
4226 int32_t opcode;
4227 int64_t val;
4228 int error = 0;
4230 if (h->insize < sizeof(opcode) || h->outsize < sizeof(int64_t))
4231 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4232 EINVAL);
4234 memcpy(&opcode, &h->msg, sizeof(opcode));
4236 switch(opcode) {
4237 case arla_GETCACHEPARAMS_OPCODE_HIGHBYTES:
4238 val = fcache_highbytes();
4239 break;
4240 case arla_GETCACHEPARAMS_OPCODE_USEDBYTES:
4241 val = fcache_usedbytes();
4242 break;
4243 case arla_GETCACHEPARAMS_OPCODE_LOWBYTES:
4244 val = fcache_lowbytes();
4245 break;
4246 case arla_GETCACHEPARAMS_OPCODE_HIGHVNODES:
4247 val = fcache_highvnodes();
4248 break;
4249 case arla_GETCACHEPARAMS_OPCODE_USEDVNODES:
4250 val = fcache_usedvnodes();
4251 break;
4252 case arla_GETCACHEPARAMS_OPCODE_LOWVNODES:
4253 val = fcache_lowvnodes();
4254 break;
4255 default:
4256 error = EINVAL;
4257 break;
4260 return nnpfs_send_message_wakeup_data (fd, h->header.sequence_num, 0,
4261 (char *) &val, sizeof(val));
4264 static int
4265 aioc_setcacheparam(int fd, struct nnpfs_message_pioctl *h, u_int size)
4267 char *p = (char*)&h->msg;
4268 int32_t opcode;
4269 int64_t high;
4270 int64_t low;
4271 int error = 0;
4273 if (!all_powerful_p(&h->cred))
4274 return nnpfs_send_message_wakeup(fd, h->header.sequence_num,
4275 EPERM);
4277 if (h->insize < (sizeof(opcode) + sizeof(high) + sizeof(low)))
4278 return nnpfs_send_message_wakeup (fd, h->header.sequence_num,
4279 EINVAL);
4281 memcpy(&opcode, p, sizeof(opcode));
4282 p += sizeof(opcode);
4284 memcpy(&high, p, sizeof(high));
4285 p += sizeof(high);
4287 memcpy(&low, p, sizeof(low));
4289 switch(opcode) {
4290 case arla_SETCACHEPARAMS_OPCODE_BYTES:
4291 error = fcache_reinit(0, 0, low, high);
4292 break;
4293 case arla_SETCACHEPARAMS_OPCODE_VNODES:
4294 error = fcache_reinit(low, high, 0, 0);
4295 break;
4296 default:
4297 error = EINVAL;
4298 break;
4301 return nnpfs_send_message_wakeup(fd, h->header.sequence_num, error);
4306 * Handle a pioctl message in `h'
4309 static int
4310 nnpfs_message_pioctl (int fd, struct nnpfs_message_pioctl *h, u_int size)
4312 int error;
4314 switch(h->opcode) {
4315 #ifdef KERBEROS
4316 case ARLA_VIOCSETTOK:
4317 error = viocsettok (fd, h, size);
4318 break;
4320 #if defined(HAVE_KRB5) && defined(WITH_RXGK)
4321 case AFSCOMMONIOC_GKK5SETTOK:
4322 error = k5settok(fd, h, size);
4323 break;
4324 #endif /* HAVE_KRB5 && WITH_RXGK */
4326 case ARLA_VIOCGETTOK :
4327 return viocgettok (fd, h, size);
4328 case ARLA_VIOCUNPAG:
4329 case ARLA_VIOCUNLOG:
4330 error = viocunlog (fd, h, size);
4331 break;
4332 #endif /* KERBEROS */
4333 case ARLA_AIOC_CONNECTMODE:
4334 return viocconnect(fd, h, size);
4335 case ARLA_VIOCFLUSH:
4336 error = viocflush(fd, h, size);
4337 break;
4338 case ARLA_VIOC_FLUSHVOLUME:
4339 error = viocflushvolume(fd, h, size);
4340 break;
4341 case ARLA_VIOCGETFID:
4342 return viocgetfid (fd, h, size);
4343 case ARLA_VIOCGETAL:
4344 return viocgetacl(fd, h, size);
4345 case ARLA_VIOCSETAL:
4346 return viocsetacl(fd, h, size);
4347 case ARLA_VIOCGETVOLSTAT:
4348 return viocgetvolstat(fd, h, size);
4349 case ARLA_VIOCSETVOLSTAT:
4350 error = viocsetvolstat(fd, h, size);
4351 break;
4352 case ARLA_VIOC_AFS_STAT_MT_PT:
4353 return vioc_afs_stat_mt_pt(fd, h, size);
4354 case ARLA_VIOC_AFS_DELETE_MT_PT:
4355 return vioc_afs_delete_mt_pt(fd, h, size);
4356 case ARLA_VIOCWHEREIS:
4357 return viocwhereis(fd, h, size);
4358 case ARLA_VIOCNOP:
4359 error = EINVAL;
4360 break;
4361 case ARLA_VIOCGETCELL:
4362 return vioc_get_cell(fd, h, size);
4363 case ARLA_VIOC_GETCELLSTATUS:
4364 return vioc_get_cellstatus(fd, h, size);
4365 case ARLA_VIOC_SETCELLSTATUS:
4366 return vioc_set_cellstatus(fd, h, size);
4367 case ARLA_VIOCNEWCELL:
4368 return vioc_new_cell(fd, h, size);
4369 case ARLA_VIOC_VENUSLOG:
4370 error = viocvenuslog (fd, h, size);
4371 break;
4372 case ARLA_VIOC_AFS_SYSNAME:
4373 return vioc_afs_sysname (fd, h, size);
4374 case ARLA_VIOC_FILE_CELL_NAME:
4375 return viocfilecellname (fd, h, size);
4376 case ARLA_VIOC_GET_WS_CELL:
4377 return viocgetwscell (fd, h, size);
4378 case ARLA_VIOCSETCACHESIZE:
4379 error = viocsetcachesize (fd, h, size);
4380 break;
4381 case ARLA_VIOCCKSERV:
4382 return viocckserv (fd, h, size);
4383 case ARLA_VIOCGETCACHEPARAMS:
4384 return viocgetcacheparms (fd, h, size);
4385 case ARLA_VIOC_GETRXKCRYPT:
4386 return getrxkcrypt(fd, h, size);
4387 case ARLA_VIOC_SETRXKCRYPT:
4388 error = setrxkcrypt(fd, h, size);
4389 break;
4390 case ARLA_VIOC_FPRIOSTATUS:
4391 error = vioc_fpriostatus(fd, h, size);
4392 break;
4393 case ARLA_VIOC_AVIATOR:
4394 return viocaviator (fd, h, size);
4395 case ARLA_VIOC_ARLADEBUG:
4396 return vioc_arladebug (fd, h, size);
4397 case ARLA_VIOC_GCPAGS:
4398 error = vioc_gcpags (fd, h, size);
4399 break;
4400 case ARLA_VIOC_CALCULATE_CACHE:
4401 return vioc_calculate_cache (fd, h, size);
4402 case ARLA_VIOC_BREAKCALLBACK:
4403 error = vioc_breakcallback (fd, h, size);
4404 break;
4405 case ARLA_VIOCACCESS:
4406 return viocaccess(fd, h, size);
4407 case ARLA_VIOC_GETVCXSTATUS2:
4408 return vioc_getvcxstatus2(fd, h, size);
4409 case ARLA_VIOCCKBACK :
4410 error = vioc_ckback (fd, h, size);
4411 break;
4412 case ARLA_AIOC_STATISTICS:
4413 return aioc_statistics (fd, h, size);
4414 case ARLA_AIOC_GETCACHEPARAMS:
4415 return aioc_getcacheparam(fd, h, size);
4416 case ARLA_AIOC_SETCACHEPARAMS:
4417 return aioc_setcacheparam(fd, h, size);
4418 default:
4419 arla_warnx (ADEBMSG, "unknown pioctl call %d", h->opcode);
4420 error = EINVAL ;
4423 nnpfs_send_message_wakeup (fd, h->header.sequence_num, error);
4425 return 0;
4430 * Return non-zero if there is a possibility that we have a network
4431 * connectivity. Can't tell the existence of network, just the lack of.
4433 * Ignore lookback interfaces and known loopback addresses.
4436 static int
4437 possibly_have_network(void)
4439 struct ifaddrs *ifa, *ifa0;
4440 int found_addr = 0;
4442 if (getifaddrs(&ifa0) != 0)
4443 return 1; /* well we don't really have a clue, do we ? */
4445 for (ifa = ifa0; ifa != NULL && !found_addr; ifa = ifa->ifa_next) {
4446 if (ifa->ifa_addr == NULL)
4447 continue;
4449 #if IFF_LOOPBACK
4450 if (ifa->ifa_flags & IFF_LOOPBACK)
4451 continue;
4452 #endif
4454 switch (ifa->ifa_addr->sa_family) {
4455 case AF_INET: {
4456 struct sockaddr_in *sin = (struct sockaddr_in *)ifa->ifa_addr;
4457 if (sin->sin_addr.s_addr == htonl(0x7f000001))
4458 continue;
4459 if (sin->sin_addr.s_addr == htonl(0))
4460 continue;
4461 found_addr = 1;
4462 break;
4464 #ifdef RX_SUPPORT_INET6
4465 case AF_INET6:
4467 * XXX avoid link local and local loopback addresses since
4468 * those are not allowed in VLDB
4470 found_addr = 1;
4471 break;
4472 #endif
4473 default:
4474 break;
4477 freeifaddrs(ifa0);
4479 /* if we found an acceptable address, good for us */
4480 if (found_addr)
4481 return 1;
4482 return 0;