*** empty log message ***
[arla.git] / nnpfs / bsd / nnpfs_vnodeops-common.c
blobc5bbb55835c8b4d409a65fc42f3cab4d42ea11e8
1 /*
2 * Copyright (c) 1995 - 2002, 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
35 * NNPFS operations.
38 #include <nnpfs/nnpfs_locl.h>
39 #include <nnpfs/nnpfs_message.h>
40 #include <nnpfs/nnpfs_common.h>
41 #include <nnpfs/nnpfs_fs.h>
42 #include <nnpfs/nnpfs_dev.h>
43 #include <nnpfs/nnpfs_deb.h>
44 #include <nnpfs/nnpfs_syscalls.h>
45 #include <nnpfs/nnpfs_vnodeops.h>
46 #include <sys/param.h>
48 RCSID("$Id$");
50 static void
51 nnpfs_handle_stale(struct nnpfs_node *xn)
53 #ifdef __APPLE__
54 struct vnode *vp = XNODE_TO_VNODE(xn);
55 #endif
57 if ((xn->flags & NNPFS_STALE) == 0)
58 return;
60 #if 0
61 if (UBCISVALID(vp) && !ubc_isinuse(vp, 1)) {
62 xn->flags &= ~NNPFS_STALE;
63 ubc_setsize(vp, 0);
64 NNPFS_TOKEN_CLEAR(xn, ~0,
65 NNPFS_OPEN_MASK | NNPFS_ATTR_MASK |
66 NNPFS_DATA_MASK | NNPFS_LOCK_MASK);
68 #endif
71 int
72 nnpfs_open_valid(struct vnode *vp, nnpfs_vfs_context ctx, u_int tok)
74 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
75 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
76 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
77 int error = 0;
79 NNPFSDEB(XDEBVFOPS, ("nnpfs_open_valid\n"));
81 nnpfs_handle_stale(xn);
83 do {
84 if (!NNPFS_TOKEN_GOT(xn, tok)) {
85 struct nnpfs_message_open msg;
87 msg.header.opcode = NNPFS_MSG_OPEN;
88 msg.cred.uid = nnpfs_cred_get_uid(cred);
89 msg.cred.pag = nnpfs_get_pag(cred);
90 msg.handle = xn->handle;
91 msg.tokens = tok;
93 error = nnpfs_message_rpc(nnpfsp, &msg.header,
94 sizeof(msg), nnpfs_vfs_context_proc(ctx));
95 if (error == 0)
96 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
98 } else {
99 goto done;
101 } while (error == 0);
103 done:
104 NNPFSDEB(XDEBVFOPS, ("nnpfs_open_valid: error = %d\n", error));
106 return error;
110 nnpfs_attr_valid(struct vnode *vp, nnpfs_kernel_cred cred, d_thread_t *p,
111 u_int tok)
113 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
114 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
115 int error = 0;
116 nnpfs_pag_t pag = nnpfs_get_pag(cred);
118 do {
119 if (!NNPFS_TOKEN_GOT(xn, tok) || !nnpfs_has_pag(xn, pag)) {
120 struct nnpfs_message_getattr msg;
122 msg.header.opcode = NNPFS_MSG_GETATTR;
123 msg.cred.uid = nnpfs_cred_get_uid(cred);
124 msg.cred.pag = pag;
125 msg.handle = xn->handle;
126 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
127 if (error == 0)
128 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
129 } else {
130 goto done;
132 } while (error == 0);
134 done:
135 return error;
138 static int
139 nnpfs_do_getdata(struct nnpfs_node *xn, nnpfs_cred *cred, u_int tok,
140 off_t offset, off_t end)
142 struct nnpfs_message_getdata msg;
143 int error;
145 msg.header.opcode = NNPFS_MSG_GETDATA;
146 msg.cred = *cred;
147 msg.handle = xn->handle;
148 msg.tokens = tok;
149 msg.offset = offset;
150 msg.len = end - offset;
152 error = nnpfs_message_rpc(NNPFS_FROM_XNODE(xn), &msg.header, sizeof(msg),
153 nnpfs_curproc());
154 if (error == 0)
155 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
157 return error;
160 static void
161 update_end(struct nnpfs_node *xn, off_t *end, int writep)
163 if (NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_R)) {
164 off_t size = nnpfs_vattr_get_size(&xn->attr);
166 if (*end > size && !writep)
167 *end = size;
172 nnpfs_data_valid(struct vnode *vp, nnpfs_cred *cred,
173 u_int tok, off_t want_offset, off_t want_end)
175 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
176 int error = 0;
177 int writep = ((tok & NNPFS_DATA_W) == NNPFS_DATA_W);
178 int did_rpc;
179 off_t offset = nnpfs_offset(want_offset);
180 off_t end, off;
182 if (!NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_R))
183 printf("NNPFS PANIC WARNING! data_valid w/o tokens!\n");
185 if (nnpfs_vnode_isdir(vp)) {
186 /* hack, entire dir goes in 'first block' */
187 offset = 0;
188 want_end = 1;
191 do {
192 did_rpc = 0;
193 end = want_end;
195 update_end(xn, &end, writep);
197 NNPFSDEB(XDEBVNOPS, ("nnpfs_data_valid: want %lld - %lld, "
198 "tokens: want %lx has %lx length: %lld\n",
199 (long long) offset, (long long) end,
200 (long) tok, (long) xn->tokens,
201 (long long) nnpfs_vattr_get_size(&xn->attr)));
203 /* use find_first_block() ? */
204 off = offset;
206 while (off < end) {
207 if (!nnpfs_block_have_p(xn, off)) {
208 off_t size = nnpfs_vattr_get_size(&xn->attr);
211 * For append beyond what daemon knows, just go ahead.
212 * Offset zero is special in that the block always exists;
213 * we need it "installed" to be safe against gc.
216 /* XXX can length be less than end after rpc or schedule? */
217 if (off >= xn->daemon_length && off > 0
218 && NNPFS_TOKEN_GOT_ALL(xn, tok|NNPFS_ATTR_R)
219 && (writep || off < nnpfs_end_offset(size))) {
220 error = nnpfs_block_create(xn, off);
221 if (error)
222 break;
224 update_end(xn, &end, writep);
225 continue;
228 did_rpc = 1;
230 error = nnpfs_do_getdata(xn, cred, tok, off, end);
231 if (error)
232 break;
234 update_end(xn, &end, writep);
236 off += nnpfs_blocksize;
239 if (error)
240 break;
242 if (!NNPFS_TOKEN_GOT_ALL(xn, tok|NNPFS_ATTR_R)) {
243 error = nnpfs_do_getdata(xn, cred, tok, offset, end);
244 did_rpc = 1;
247 } while (error == 0 && did_rpc);
249 return error;
253 nnpfs_open_common(struct vnode *vp,
254 int mode,
255 nnpfs_vfs_context ctx)
257 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
258 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
259 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
260 int ret;
262 nnpfs_dev_lock(nnpfsp);
263 NNPFSDEB(XDEBVNOPS, ("nnpfs_open(%p)\n", vp));
265 if (mode & FWRITE) {
266 ret = nnpfs_open_valid(vp, ctx, NNPFS_OPEN_NW);
268 if (!ret) {
269 #ifdef __APPLE__
270 xn->writers++;
271 #endif
272 nnpfs_setcred(&xn->wr_cred, cred);
274 } else {
275 ret = nnpfs_open_valid(vp, ctx, NNPFS_OPEN_NR);
278 /* always update the read cred */
279 if (!ret)
280 nnpfs_setcred(&xn->rd_cred, cred);
282 nnpfs_dev_unlock(nnpfsp);
284 return ret;
288 * find first block in given range with validity according to 'validp'
290 * returns offset of first such block, or NNPFS_NO_OFFSET if none
293 static uint64_t
294 find_first_block(struct nnpfs_node *node, uint64_t offset,
295 uint64_t end, int validp)
297 off_t eof = nnpfs_vattr_get_size(&node->attr);
298 uint64_t off;
300 if (nnpfs_block_empty(node)
301 || offset >= eof)
302 return NNPFS_NO_OFFSET;
304 /* get some batch search perhaps? */
306 nnpfs_assert(nnpfs_offset(offset) == offset);
308 if (end > eof)
309 end = eof;
311 for (off = offset; off < end; off += nnpfs_blocksize) {
312 int validity = nnpfs_block_have_p(node, off);
313 if (validp) {
314 if (validity)
315 return off;
316 } else {
317 if (!validity)
318 return off;
322 return NNPFS_NO_OFFSET;
326 * store data for entire node
328 static int
329 do_fsync(struct nnpfs *nnpfsp,
330 struct nnpfs_node *xn,
331 nnpfs_kernel_cred cred,
332 nnpfs_cred *ncred,
333 d_thread_t *p,
334 u_int flag)
336 off_t len = nnpfs_vattr_get_size(&xn->attr); /* XXX may change on rpc */
337 struct nnpfs_message_putdata msg;
338 uint64_t off = 0;
339 uint64_t end;
340 int error = 0;
341 int nrpcs = 0;
343 NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: len 0x%llx, mask0=0x%lx\n",
344 (unsigned long long)len,
345 (unsigned long)(xn->data.nmasks > 1
346 ? xn->data.masks.list[0]
347 : xn->data.masks.first)));
349 do {
350 /* get first valid block */
351 off = find_first_block(xn, off, len, TRUE);
352 if (off >= len || off == NNPFS_NO_OFFSET)
353 break; /* no more blocks installed */
355 /* find the end of this range of valid blocks */
356 end = find_first_block(xn, off + nnpfs_blocksize, len, FALSE);
357 if (end > len || off == NNPFS_NO_OFFSET)
358 end = len;
360 vattr2nnpfs_attr(&xn->attr, &msg.attr);
362 if (ncred != NULL)
363 msg.cred = *ncred;
364 else
365 nnpfs_setcred(&msg.cred, cred);
367 msg.header.opcode = NNPFS_MSG_PUTDATA;
368 msg.handle = xn->handle;
369 msg.flag = flag;
370 msg.offset = off;
371 msg.len = end - off;
373 xn->pending_writes++; /* XXX lock */
375 nrpcs++;
376 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
377 if (error == 0)
378 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
380 /* XXX locking, rpc may fail */
381 xn->daemon_length = nnpfs_vattr_get_size(&xn->attr);
383 xn->pending_writes--; /* XXX lock */
384 nnpfs_assert(xn->pending_writes >= 0);
386 off = end;
387 } while (!error && end < len);
389 if (error == 0)
390 xn->flags &= ~NNPFS_DATA_DIRTY;
392 NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: nrpcs %d -> %d\n", nrpcs, error));
394 return error;
398 nnpfs_fsync_common(struct vnode *vp, nnpfs_kernel_cred cred, nnpfs_cred *ncred,
399 int waitfor, d_thread_t *proc)
401 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
402 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
403 int error = 0;
405 NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: %lx\n", (unsigned long)vp));
408 * It seems that fsync is sometimes called after reclaiming a node.
409 * In that case we just look happy.
412 if (xn == NULL) {
413 printf("NNPFS PANIC WARNING! nnpfs_fsync called after reclaiming!\n");
414 return 0;
417 nnpfs_pushdirty(vp);
419 nnpfs_dev_lock(nnpfsp);
420 if (xn->flags & NNPFS_DATA_DIRTY) {
421 NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: dirty\n"));
422 #ifdef FSYNC_RECLAIM
423 /* writing back the data from this vnode failed */
424 if (waitfor & FSYNC_RECLAIM) {
425 printf("nnpfs_fsync: data lost, failed to write back\n");
426 xn->flags &= ~NNPFS_DATA_DIRTY;
427 return 0;
429 #endif
430 error = do_fsync(nnpfsp, xn, cred, ncred, proc, NNPFS_WRITE | NNPFS_FSYNC);
432 nnpfs_dev_unlock(nnpfsp);
434 NNPFSDEB(XDEBVNOPS, ("nnpfs_fsync: return %d\n", error));
436 return error;
440 nnpfs_close_common(struct vnode *vp, int fflag,
441 d_thread_t *proc, nnpfs_kernel_cred cred)
443 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
444 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
445 int error = 0;
447 NNPFSDEB(XDEBVNOPS,
448 ("nnpfs_close(%p) cred = %lx, fflag = %x, xn->flags = %x\n",
449 vp, (unsigned long)cred, fflag, xn->flags));
451 if (nnpfs_vnode_isreg(vp))
452 nnpfs_pushdirty(vp);
454 nnpfs_dev_lock(nnpfsp);
456 if (fflag & FWRITE) {
457 if (xn->async_error == 0 && xn->flags & NNPFS_DATA_DIRTY) {
458 NNPFSDEB(XDEBVNOPS, ("nnpfs_close: fsync\n"));
460 error = do_fsync(nnpfsp, xn, cred, NULL, proc, NNPFS_WRITE);
462 /* XXX DATA_DIRTY on async_error? */
464 #ifdef __APPLE__
465 if (--xn->writers < 0)
466 panic("xn -ve writers");
467 #endif
470 if (xn->async_error) {
471 xn->async_error = 0;
472 error = EIO;
475 nnpfs_dev_unlock(nnpfsp);
477 NNPFSDEB(XDEBVNOPS, ("nnpfs_close -> %d\n", error));
479 return error;
483 * return offset + resid
486 off_t
487 nnpfs_uio_end_length (struct uio *uio)
489 #if defined(DIAGNOSTIC) && !defined(__APPLE__)
490 size_t sz = 0;
491 int i;
493 for (i = 0; i < uio->uio_iovcnt; i++)
494 sz += uio->uio_iov[i].iov_len;
495 if (sz != uio->uio_resid)
496 panic("nnpfs_uio_end_length");
497 #endif
498 return nnpfs_uio_offset(uio) + nnpfs_uio_resid(uio);
502 nnpfs_read_common(struct vnode *vp, struct uio *uio, int ioflag, nnpfs_kernel_cred cred)
504 int error = 0;
505 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
506 struct nnpfs_node *node = VNODE_TO_XNODE(vp);
507 off_t offset = nnpfs_uio_offset(uio);
508 off_t length = nnpfs_uio_end_length(uio);
509 off_t resid_add = 0;
510 off_t eof;
512 NNPFSDEB(XDEBVNOPS, ("nnpfs_read\n"));
515 * Currently, directories are handled in a different way than
516 * ordinary files, so we refuse to read them. Very un-BSD-ish.
518 if (nnpfs_vnode_isdir(vp))
519 return EINVAL;
521 nnpfs_dev_lock(nnpfsp);
523 nnpfs_setcred(&node->rd_cred, cred);
525 error = nnpfs_data_valid(vp, &node->rd_cred, NNPFS_DATA_R,
526 offset, length);
528 if (error == 0)
529 eof = nnpfs_vattr_get_size(&node->attr);
531 if (error == 0 && offset < eof) {
532 if (length > eof) {
533 resid_add = length - eof;
534 nnpfs_uio_setresid(uio, eof - offset);
535 length = eof;
538 while (offset < length) {
539 struct vnode *t;
540 off_t off = offset & (nnpfs_blocksize - 1);
541 off_t nbytes;
543 error = nnpfs_block_open(node,
544 nnpfs_offset(offset),
545 FREAD, &t);
546 if (error)
547 break;
549 nnpfs_uio_setoffset(uio, off);
551 #if defined(__APPLE__)
552 nnpfs_vop_read(t, uio, ioflag, NULL, error);
553 #else
554 nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uio));
555 nnpfs_vop_read(t, uio, ioflag,
556 nnpfs_vfs_context_ucred(nnpfsp->ctx), error);
557 nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uio));
558 #endif
559 nnpfs_block_close(node, t, 0);
561 if (error)
562 break;
564 nbytes = nnpfs_uio_offset(uio) - off;
565 if (nbytes <= 0) {
566 error = EIO; /* XXX maybe should be no error? */
567 printf("nnpfs_read: nbytes is %lld @0x%llx, index 0x%x\n",
568 (long long)nbytes, (unsigned long long)offset,
569 node->index);
570 break;
573 offset += nbytes;
576 nnpfs_uio_setoffset(uio, offset);
577 if (resid_add)
578 nnpfs_uio_setresid(uio, nnpfs_uio_resid(uio) + resid_add);
581 NNPFSDEB(XDEBVNOPS, ("nnpfs_read offset: %lu resid: %lu\n",
582 (unsigned long)nnpfs_uio_offset(uio),
583 (unsigned long)nnpfs_uio_resid(uio)));
584 NNPFSDEB(XDEBVNOPS, ("nnpfs_read error: %d\n", error));
586 nnpfs_dev_unlock(nnpfsp);
588 return error;
592 * update node attributes after write, using cache file 't' as time
593 * stamp source
596 static void
597 nnpfs_update_write_attr(struct vnode *vp, struct nnpfs_node *xn,
598 struct vnode *t, off_t length,
599 nnpfs_vfs_context ctx)
601 off_t eof = nnpfs_vattr_get_size(&xn->attr);
602 struct nnpfs_vfs_vattr sub_attr;
603 int error2 = 0;
605 #ifdef __APPLE__
606 VATTR_INIT(&sub_attr);
607 VATTR_WANTED(&sub_attr, va_modify_time);
608 #endif
610 if (length > eof) {
611 nnpfs_vattr_set_size(&xn->attr, length);
612 nnpfs_vattr_set_bytes(&xn->attr, length);
613 #ifndef __NetBSD__
614 nnpfs_set_vp_size(vp, length);
615 #endif
618 #ifndef __NetBSD__
619 nnpfs_vop_getattr(t, &sub_attr, ctx, error2);
620 if (error2 == 0) {
621 nnpfs_vattr_set_mtime(&xn->attr,
622 nnpfs_vattr_get_mtime_sec(&sub_attr),
623 nnpfs_vattr_get_mtime_nsec(&sub_attr));
624 } else {
625 printf("nnpfs_update_write_attr: "
626 "getattr failed for len 0x%llx\n",
627 (unsigned long long)length);
629 #endif
633 nnpfs_write_common(struct vnode *vp, struct uio *uiop, int ioflag,
634 nnpfs_vfs_context ctx)
636 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
637 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
638 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
639 nnpfs_vfs_context daemon_ctx = NNPFS_FROM_VNODE(vp)->ctx;
640 off_t eof = nnpfs_vattr_get_size(&xn->attr);
641 int error = xn->async_error;
642 off_t offset;
643 off_t length;
645 nnpfs_dev_lock(nnpfsp);
646 NNPFSDEB(XDEBVNOPS, ("nnpfs_write(%p)\n", vp));
648 nnpfs_assert(!nnpfs_vnode_isdir(vp));
650 nnpfs_setcred(&xn->wr_cred, cred);
652 if (error) {
653 xn->async_error = 0;
654 nnpfs_dev_unlock(nnpfsp);
655 return error;
658 if (ioflag & IO_APPEND)
659 nnpfs_uio_setoffset(uiop, eof);
661 offset = nnpfs_uio_offset(uiop);
662 length = nnpfs_uio_end_length(uiop);
664 error = nnpfs_data_valid(vp, &xn->wr_cred, NNPFS_DATA_W, offset, length);
665 if (error) {
666 nnpfs_dev_unlock(nnpfsp);
667 return error;
670 while (offset < length) {
671 off_t off = offset & (nnpfs_blocksize - 1);
672 int flags = FWRITE;
673 off_t resid;
674 struct vnode *t;
675 off_t nbytes;
677 #ifdef __FreeBSD__
678 struct mount *mp;
679 #endif
681 if (offset >= eof)
682 flags = FWRITE | O_CREAT;
684 error = nnpfs_block_open(xn, nnpfs_offset(offset), flags, &t);
685 if (error) {
686 error = EIO;
687 break;
690 resid = nnpfs_blocksize - off;
691 if (offset + resid > length)
692 resid = length - offset;
694 nnpfs_uio_setoffset(uiop, off);
695 nnpfs_uio_setresid(uiop, resid);
697 #ifdef __APPLE__
698 nnpfs_vop_write(t, uiop, ioflag, daemon_ctx, error);
699 #else
701 #ifdef __FreeBSD__
702 (void)vn_start_write(t, &mp, V_WAIT);
703 nnpfs_vfs_writelock(t, nnpfs_vfs_context_proc(ctx));
704 (void)VOP_LEASE(t, nnpfs_vfs_context_proc(ctx), cred, LEASE_WRITE);
705 #endif
707 nnpfs_vop_write(t, uiop, ioflag, cred, error);
708 #endif
710 if (!error) {
711 nbytes = nnpfs_uio_offset(uiop) - off;
712 if (nbytes > 0) {
713 offset += nbytes;
714 } else {
715 error = EIO;
716 printf("nnpfs_write: nbytes is %lld!\n",
717 (long long)nbytes);
720 /* #ifndef __NetBSD__ */
721 /* get time stamp etc from the last cache file */
722 if (offset >= length)
723 nnpfs_update_write_attr(vp, xn, t, offset, daemon_ctx);
724 /* #endif !__NetBSD__ */
727 #ifndef __NetBSD__
728 nnpfs_vfs_unlock(t, nnpfs_vfs_context_proc(ctx));
729 #endif
731 #ifdef __FreeBSD__
732 vn_finished_write(mp);
733 #endif
735 nnpfs_block_close(xn, t, 1);
737 if (error)
738 break;
741 xn->flags |= NNPFS_DATA_DIRTY;
742 nnpfs_uio_setoffset(uiop, offset);
743 nnpfs_uio_setresid(uiop, length - offset);
745 nnpfs_dev_unlock(nnpfsp);
747 NNPFSDEB(XDEBVNOPS, ("nnpfs_write -> %d\n", error));
749 return error;
753 nnpfs_getattr_common(struct vnode *vp, struct nnpfs_vfs_vattr *vap,
754 nnpfs_kernel_cred cred, d_thread_t *p)
756 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
757 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
758 int error = 0;
760 nnpfs_dev_lock(nnpfsp);
761 NNPFSDEB(XDEBVNOPS, ("nnpfs_getattr\n"));
763 error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
764 if (error == 0)
765 *vap = xn->attr;
767 nnpfs_dev_unlock(nnpfsp);
769 return error;
772 static int
773 setattr_is_noop(struct nnpfs_node *xn, struct nnpfs_vfs_vattr *vap)
775 #ifdef __APPLE__
777 #define CHECK_NNPFSATTR(A) (!VATTR_IS_ACTIVE(vap, A) || vap->A == xn->attr.A)
778 if (CHECK_NNPFSATTR(va_mode) &&
779 CHECK_NNPFSATTR(va_nlink) &&
780 CHECK_NNPFSATTR(va_data_size) &&
781 CHECK_NNPFSATTR(va_uid) &&
782 CHECK_NNPFSATTR(va_gid) &&
783 CHECK_NNPFSATTR(va_fileid) && /* we ignore va_type */
784 (!VATTR_IS_ACTIVE(vap, va_modify_time)
785 || vap->va_modify_time.tv_sec == xn->attr.va_modify_time.tv_sec))
786 return 1;
787 #undef CHECK_NNPFSATTR
789 #else
791 #define CHECK_NNPFSATTR(A, cast) (vap->A == cast VNOVAL || vap->A == xn->attr.A)
792 if (CHECK_NNPFSATTR(va_mode,(mode_t)) &&
793 CHECK_NNPFSATTR(va_nlink,(short)) &&
794 CHECK_NNPFSATTR(va_size,(va_size_t)) &&
795 CHECK_NNPFSATTR(va_uid,(uid_t)) &&
796 CHECK_NNPFSATTR(va_gid,(gid_t)) &&
797 CHECK_NNPFSATTR(va_mtime.tv_sec,(time_t)) &&
798 CHECK_NNPFSATTR(va_fileid,(long)) &&
799 CHECK_NNPFSATTR(va_type,(enum vtype)))
800 return 1;
801 #undef CHECK_NNPFSATTR
803 #endif /* ! __APPLE__ */
805 return 0;
809 nnpfs_setattr_common(struct vnode *vp, struct nnpfs_vfs_vattr *vap,
810 nnpfs_kernel_cred cred, d_thread_t *p)
812 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
813 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
814 int error = 0;
816 nnpfs_dev_lock(nnpfsp);
817 NNPFSDEB(XDEBVNOPS, ("nnpfs_setattr\n"));
819 if (setattr_is_noop(xn, vap)) {
820 nnpfs_dev_unlock(nnpfsp);
821 return 0; /* nothing to do */
824 if (NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_W)) {
825 /* Update attributes and mark them dirty. */
826 VNODE_TO_XNODE(vp)->flags |= NNPFS_ATTR_DIRTY;
827 error = EINVAL; /* XXX not yet implemented */
828 goto done;
829 } else {
830 struct nnpfs_message_putattr msg;
831 uint64_t old_length, new_length;
833 msg.header.opcode = NNPFS_MSG_PUTATTR;
834 nnpfs_setcred(&msg.cred, cred);
835 msg.handle = xn->handle;
836 vattr2nnpfs_attr(vap, &msg.attr);
838 if (NNPFS_TOKEN_GOT(xn, NNPFS_DATA_R)) {
839 if (nnpfs_vnode_isreg(vp)) {
840 old_length = nnpfs_vattr_get_size(&xn->attr);
842 if (nnpfs_vattr_size_isactive(vap)) {
843 new_length = nnpfs_vattr_get_size(vap);
845 XA_SET_SIZE(&msg.attr, new_length);
846 } else {
847 XA_SET_SIZE(&msg.attr, old_length);
851 if (nnpfs_vattr_mtime_isactive(vap))
852 XA_SET_MTIME(&msg.attr, nnpfs_vattr_get_mtime_sec(vap));
853 else
854 XA_SET_MTIME(&msg.attr, nnpfs_vattr_get_mtime_sec(&xn->attr));
857 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
858 if (error == 0)
859 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
861 #if 0 /* assume length is always in (loose) sync with daemon nowadays */
862 if (error == 0 && do_fixup)
863 truncate_block_fixup(xn, old_length, new_length);
864 #endif
867 done:
868 nnpfs_dev_unlock(nnpfsp);
869 NNPFS_VN_KNOTE(vp, NOTE_ATTRIB);
871 return error;
874 static int
875 check_rights (nnpfs_rights rights, int mode, int dirp)
877 int error = 0;
879 #ifdef __APPLE__
880 /* VNOP_ACCESS passes a kauth action instead of ordinary unix mode */
882 if (dirp) {
883 if (mode & (KAUTH_VNODE_LIST_DIRECTORY | KAUTH_VNODE_SEARCH))
884 if ((rights & NNPFS_RIGHT_X) == 0)
885 error = EACCES;
886 if (mode & KAUTH_VNODE_DELETE_CHILD)
887 if ((rights & NNPFS_RIGHT_AD) == 0)
888 error = EACCES;
889 if (mode & (KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY))
890 if ((rights & NNPFS_RIGHT_AI) == 0)
891 error = EACCES;
893 /* XXX can't check KAUTH_VNODE_DELETE, have no info */
895 } else {
896 if (mode & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_ATTRIBUTES))
897 if ((rights & NNPFS_RIGHT_AR) == 0)
898 error = EACCES;
899 if (mode & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA | KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_TAKE_OWNERSHIP))
900 if ((rights & NNPFS_RIGHT_W) == 0)
901 error = EACCES;
902 if (mode & KAUTH_VNODE_EXECUTE)
903 if ((rights & NNPFS_RIGHT_X) == 0)
904 error = EACCES;
905 if (mode & KAUTH_VNODE_DELETE)
906 if ((rights & NNPFS_RIGHT_AD) == 0)
907 error = EACCES;
910 #if 0
911 KAUTH_VNODE_READ_EXTATTRIBUTES
912 KAUTH_VNODE_WRITE_EXTATTRIBUTES
913 KAUTH_VNODE_READ_SECURITY
914 KAUTH_VNODE_WRITE_SECURITY
915 KAUTH_VNODE_SYNCHRONIZE notused
916 KAUTH_VNODE_LINKTARGET like insert, but for target???
917 KAUTH_VNODE_CHECKIMMUTABLE always ok
918 KAUTH_VNODE_ACCESS (advisory)
919 KAUTH_VNODE_NOIMMUTABLE ?
920 #endif
922 #else /* !__APPLE__ */
924 if (mode & VREAD)
925 if ((rights & NNPFS_RIGHT_R) == 0)
926 error = EACCES;
927 if (mode & VWRITE)
928 if ((rights & NNPFS_RIGHT_W) == 0)
929 error = EACCES;
930 if (mode & VEXEC)
931 if ((rights & NNPFS_RIGHT_X) == 0)
932 error = EACCES;
934 #endif /* !__APPLE__ */
936 return error;
940 nnpfs_access_common(struct vnode *vp, int mode, nnpfs_kernel_cred cred,
941 d_thread_t *p)
943 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
944 int dirp = nnpfs_vnode_isdir(vp);
945 int error = 0;
946 nnpfs_pag_t pag;
948 nnpfs_dev_lock(nnpfsp);
949 NNPFSDEB(XDEBVNOPS, ("nnpfs_access mode = 0%o\n", mode));
951 pag = nnpfs_get_pag(cred);
953 error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
954 if (error == 0) {
955 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
956 int i;
958 error = check_rights(xn->anonrights, mode, dirp);
960 if (error == 0)
961 goto done;
963 NNPFSDEB(XDEBVNOPS, ("nnpfs_access anonaccess failed\n"));
965 error = EACCES; /* default to EACCES if pag isn't in xn->id */
967 for (i = 0; i < NNPFS_MAXRIGHTS; i++)
968 if (xn->id[i] == pag) {
969 error = check_rights(xn->rights[i], mode, dirp);
970 break;
974 done:
975 NNPFSDEB(XDEBVNOPS, ("nnpfs_access(0%o) = %d\n", mode, error));
976 nnpfs_dev_unlock(nnpfsp);
978 return error;
982 nnpfs_lookup_common(struct vnode *dvp,
983 nnpfs_componentname *cnp,
984 struct vnode **vpp,
985 nnpfs_vfs_context ctx)
987 struct nnpfs_message_getnode msg;
988 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
989 d_thread_t *p = nnpfs_vfs_context_proc(ctx);
990 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
991 struct nnpfs_node *d = VNODE_TO_XNODE(dvp);
992 int error = 0;
994 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: enter\n"));
996 *vpp = NULL;
998 if (cnp->cn_namelen >= NNPFS_MAX_NAME)
999 return ENAMETOOLONG;
1001 if (!nnpfs_vnode_isdir(dvp))
1002 return ENOTDIR;
1004 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
1005 *vpp = dvp;
1006 #ifdef __APPLE__
1007 nnpfs_do_vget(*vpp, 0 /* XXX flag */, NULL /*proc */);
1008 #else
1009 nnpfs_vref(*vpp);
1010 #endif
1011 return 0;
1014 nnpfs_dev_lock(nnpfsp);
1015 do {
1016 nnpfs_lookup_access(dvp, ctx, p, error);
1017 if (error != 0)
1018 goto done;
1020 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: dvp = %lx\n",
1021 (unsigned long) dvp));
1022 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: cnp = %lx, "
1023 "cnp->cn_nameiop = %d\n",
1024 (unsigned long) cnp, (int)cnp->cn_nameiop));
1026 error = nnpfs_dnlc_lookup(dvp, cnp, vpp);
1027 if (error == 0) { /* not cached */
1030 * Doesn't quite work.
1033 #if 0
1034 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
1035 && (cnp->cn_flags & ISLASTCN)) {
1036 error = EJUSTRETURN;
1037 goto done;
1039 #endif
1041 msg.header.opcode = NNPFS_MSG_GETNODE;
1042 nnpfs_setcred(&msg.cred, cred);
1043 msg.parent_handle = d->handle;
1044 memcpy(msg.name, cnp->cn_nameptr, cnp->cn_namelen);
1045 msg.name[cnp->cn_namelen] = '\0';
1046 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1047 if (error == 0)
1048 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1049 if(error == ENOENT && cnp->cn_nameiop != CREATE) {
1050 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup: neg cache %lx (%s, %ld)\n",
1051 (unsigned long)dvp,
1052 cnp->cn_nameptr, cnp->cn_namelen));
1053 nnpfs_dnlc_enter (dvp, cnp, NULL);
1055 } else if (error == -1) { /* found */
1056 error = 0;
1057 goto done;
1059 } while (error == 0);
1061 done:
1062 nnpfs_dev_unlock(nnpfsp);
1063 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1065 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: return %d, vn %p\n",
1066 error, *vpp));
1067 return error;
1071 nnpfs_create_common(struct vnode *dvp,
1072 const char *name,
1073 struct nnpfs_vfs_vattr *vap,
1074 nnpfs_kernel_cred cred,
1075 d_thread_t *p)
1077 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1078 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1079 int error = 0;
1081 nnpfs_dev_lock(nnpfsp);
1082 NNPFSDEB(XDEBVNOPS, ("nnpfs_create: (%lx, %s)\n",
1083 (unsigned long)dvp, name));
1085 struct nnpfs_message_create msg;
1087 msg.header.opcode = NNPFS_MSG_CREATE;
1088 msg.parent_handle = xn->handle;
1089 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1090 return ENAMETOOLONG;
1091 vattr2nnpfs_attr(vap, &msg.attr);
1093 msg.mode = 0; /* XXX - mode */
1094 nnpfs_setcred(&msg.cred, cred);
1096 #ifdef __APPLE__
1097 /* needed for subsequent writes to succeed with n */
1098 msg.attr.valid &= ~XA_V_UID;
1099 #endif
1101 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1102 if (error == 0)
1103 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1106 #if 0
1107 if (error == EEXIST)
1108 error = 0;
1109 #endif
1111 nnpfs_dev_unlock(nnpfsp);
1113 NNPFSDEB(XDEBVNOPS, ("nnpfs_create -> %d\n", error));
1115 return error;
1119 nnpfs_remove_common(struct vnode *dvp,
1120 struct vnode *vp,
1121 const char *name,
1122 nnpfs_kernel_cred cred,
1123 d_thread_t *p)
1125 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1126 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1127 struct nnpfs_message_remove msg;
1128 int error;
1130 nnpfs_dev_lock(nnpfsp);
1131 NNPFSDEB(XDEBVNOPS, ("nnpfs_remove(%p): %s\n", dvp, name));
1133 msg.header.opcode = NNPFS_MSG_REMOVE;
1134 msg.parent_handle = xn->handle;
1135 msg.cred.uid = nnpfs_cred_get_uid(cred);
1136 msg.cred.pag = nnpfs_get_pag(cred);
1138 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1139 error = ENAMETOOLONG;
1140 else
1141 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1142 if (error == 0)
1143 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1145 if (error == 0)
1146 nnpfs_dnlc_purge (vp);
1148 nnpfs_dev_unlock(nnpfsp);
1150 if (error == 0) {
1151 NNPFS_VN_KNOTE(vp, NOTE_DELETE);
1152 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1155 NNPFSDEB(XDEBVNOPS, ("nnpfs_remove -> %d\n", error));
1157 return error;
1161 nnpfs_rename_common(struct vnode *fdvp,
1162 struct vnode *fvp,
1163 const char *fname,
1164 struct vnode *tdvp,
1165 struct vnode *tvp,
1166 const char *tname,
1167 nnpfs_kernel_cred cred,
1168 d_thread_t *p)
1170 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(fdvp);
1171 int error;
1173 nnpfs_dev_lock(nnpfsp);
1174 NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: %s %s\n", fname, tname));
1176 #if 0
1177 if ((fvp->v_mount != tdvp->v_mount)
1178 || (tvp && (fvp->v_mount != tvp->v_mount))) {
1179 return EXDEV;
1181 #endif
1184 struct nnpfs_message_rename msg;
1186 msg.header.opcode = NNPFS_MSG_RENAME;
1187 msg.old_parent_handle = VNODE_TO_XNODE(fdvp)->handle;
1188 if (strlcpy(msg.old_name, fname, sizeof(msg.old_name)) >= NNPFS_MAX_NAME) {
1189 nnpfs_dev_unlock(nnpfsp);
1190 return ENAMETOOLONG;
1193 msg.new_parent_handle = VNODE_TO_XNODE(tdvp)->handle;
1194 if (strlcpy(msg.new_name, tname, sizeof(msg.new_name)) >= NNPFS_MAX_NAME) {
1195 nnpfs_dev_unlock(nnpfsp);
1196 return ENAMETOOLONG;
1199 msg.cred.uid = nnpfs_cred_get_uid(cred);
1200 msg.cred.pag = nnpfs_get_pag(cred);
1201 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1202 if (error == 0)
1203 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1207 nnpfs_dev_unlock(nnpfsp);
1208 NNPFS_VN_KNOTE(fdvp, NOTE_WRITE);
1209 NNPFS_VN_KNOTE(fvp, NOTE_WRITE);
1211 NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: error = %d\n", error));
1213 return error;
1217 nnpfs_mkdir_common(struct vnode *dvp,
1218 const char *name,
1219 struct nnpfs_vfs_vattr *vap,
1220 nnpfs_kernel_cred cred,
1221 d_thread_t *p)
1223 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1224 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1225 int error = 0;
1227 nnpfs_dev_lock(nnpfsp);
1228 NNPFSDEB(XDEBVNOPS, ("nnpfs_mkdir(%p): %s\n", dvp, name));
1230 struct nnpfs_message_mkdir msg;
1232 msg.header.opcode = NNPFS_MSG_MKDIR;
1233 msg.parent_handle = xn->handle;
1234 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1235 nnpfs_dev_unlock(nnpfsp);
1236 return ENAMETOOLONG;
1239 vattr2nnpfs_attr(vap, &msg.attr);
1240 nnpfs_setcred(&msg.cred, cred);
1241 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1242 if (error == 0)
1243 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1246 nnpfs_dev_unlock(nnpfsp);
1248 if (error == 0)
1249 NNPFS_VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1251 NNPFSDEB(XDEBVNOPS, ("nnpfs_mkdir -> %d\n", error));
1252 return error;
1256 nnpfs_rmdir_common(struct vnode *dvp,
1257 struct vnode *vp,
1258 const char *name,
1259 nnpfs_kernel_cred cred,
1260 d_thread_t *p)
1262 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1263 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1264 struct nnpfs_message_rmdir msg;
1265 int error;
1267 nnpfs_dev_lock(nnpfsp);
1268 NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir: %s\n", name));
1270 msg.header.opcode = NNPFS_MSG_RMDIR;
1271 msg.parent_handle = xn->handle;
1272 msg.cred.uid = nnpfs_cred_get_uid(cred);
1273 msg.cred.pag = nnpfs_get_pag(cred);
1274 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1275 error = ENAMETOOLONG;
1276 else
1277 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1278 if (error == 0)
1279 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1281 if (error == 0) {
1282 nnpfs_dnlc_purge (vp);
1284 /* XXX knote even on error? */
1285 NNPFS_VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1286 NNPFS_VN_KNOTE(vp, NOTE_DELETE);
1289 nnpfs_dev_unlock(nnpfsp);
1291 NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir error: %d\n", error));
1293 return error;
1297 nnpfs_readdir_common(struct vnode *vp,
1298 struct uio *uiop,
1299 int *eofflag,
1300 nnpfs_vfs_context ctx)
1302 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1303 struct vnode *t = NULL;
1304 struct nnpfs_node *node;
1305 nnpfs_cred cred;
1306 int error;
1308 nnpfs_dev_lock(nnpfsp);
1309 NNPFSDEB(XDEBVNOPS, ("nnpfs_readdir(%p)\n", vp));
1311 if (eofflag)
1312 *eofflag = 0;
1314 nnpfs_assert(nnpfs_vnode_isdir(vp));
1316 nnpfs_setcred(&cred, nnpfs_vfs_context_ucred(ctx));
1318 /* XXX dir can be removed at any moment, but this is ridiculous. */
1319 while (1) {
1320 error = nnpfs_data_valid(vp, &cred, NNPFS_DATA_R,
1321 nnpfs_uio_offset(uiop),
1322 nnpfs_uio_end_length(uiop));
1323 if (error) {
1324 nnpfs_dev_unlock(nnpfsp);
1325 return error;
1327 node = VNODE_TO_XNODE(vp);
1328 error = nnpfs_block_open(node, 0, FREAD, &t);
1329 if (!error)
1330 break;
1333 nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uiop));
1334 nnpfs_vop_read(t, uiop, 0, NULL, error);
1335 if (eofflag) {
1336 struct nnpfs_vfs_vattr t_attr;
1337 int error2;
1339 #ifdef __APPLE__
1340 VATTR_INIT(&t_attr);
1341 VATTR_WANTED(&t_attr, va_data_size);
1342 #endif
1343 nnpfs_vop_getattr(t, &t_attr, ctx, error2); /* XXX check bitmask */
1344 if (error2 == 0)
1345 *eofflag = nnpfs_vattr_get_size(&t_attr) <= nnpfs_uio_offset(uiop);
1347 nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uiop));
1348 nnpfs_block_close(node, t, 0);
1350 nnpfs_dev_unlock(nnpfsp);
1352 NNPFSDEB(XDEBVNOPS, ("nnpfs_readdir -> %d\n", error));
1354 return error;
1358 nnpfs_link_common(struct vnode *dvp,
1359 struct vnode *vp,
1360 const char *name,
1361 nnpfs_kernel_cred cred,
1362 d_thread_t *p)
1364 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1365 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1366 struct nnpfs_node *xn2 = VNODE_TO_XNODE(vp);
1367 struct nnpfs_message_link msg;
1368 int error = 0;
1370 nnpfs_dev_lock(nnpfsp);
1371 NNPFSDEB(XDEBVNOPS, ("nnpfs_link: %s\n", name));
1373 msg.header.opcode = NNPFS_MSG_LINK;
1374 msg.parent_handle = xn->handle;
1375 msg.from_handle = xn2->handle;
1376 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1377 nnpfs_dev_unlock(nnpfsp);
1378 return ENAMETOOLONG;
1381 msg.cred.uid = nnpfs_cred_get_uid(cred);
1382 msg.cred.pag = nnpfs_get_pag(cred);
1384 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1385 if (error == 0)
1386 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1388 nnpfs_dev_unlock(nnpfsp);
1389 NNPFS_VN_KNOTE(vp, NOTE_LINK);
1391 return error;
1395 nnpfs_symlink_common(struct vnode *dvp,
1396 struct vnode **vpp,
1397 nnpfs_componentname *cnp,
1398 struct nnpfs_vfs_vattr *vap,
1399 char *target,
1400 nnpfs_vfs_context ctx)
1402 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1403 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1404 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
1405 struct nnpfs_message_symlink msg;
1406 const char *name = cnp->cn_nameptr;
1407 int error = 0;
1409 nnpfs_dev_lock(nnpfsp);
1410 NNPFSDEB(XDEBVNOPS, ("nnpfs_symlink: %s\n", name));
1412 msg.header.opcode = NNPFS_MSG_SYMLINK;
1413 msg.parent_handle = xn->handle;
1414 vattr2nnpfs_attr(vap, &msg.attr);
1415 msg.cred.uid = nnpfs_cred_get_uid(cred);
1416 msg.cred.pag = nnpfs_get_pag(cred);
1417 if (strlcpy (msg.contents, target, sizeof(msg.contents)) >= NNPFS_MAX_SYMLINK_CONTENT) {
1418 error = ENAMETOOLONG;
1419 goto done;
1421 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1422 error = ENAMETOOLONG;
1423 goto done;
1425 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg),
1426 nnpfs_vfs_context_proc(ctx));
1427 if (error == 0)
1428 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1430 done:
1431 nnpfs_dev_unlock(nnpfsp);
1432 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1434 return error;
1438 nnpfs_readlink_common(struct vnode *vp, struct uio *uiop, nnpfs_vfs_context ctx)
1440 int error = 0;
1441 nnpfs_cred cred;
1442 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1443 #ifdef HAVE_THREE_ARGUMENT_VOP_UNLOCK
1444 d_thread_t *proc = nnpfs_vfs_context_proc(ctx);
1445 #endif
1447 NNPFSDEB(XDEBVNOPS, ("nnpfs_readlink\n"));
1449 if (!nnpfs_vnode_islnk(vp) || (nnpfs_uio_offset(uiop) != (off_t)0))
1450 return EINVAL;
1452 nnpfs_dev_lock(nnpfsp);
1454 /* XXX check it fits in one block */
1456 nnpfs_setcred(&cred, nnpfs_vfs_context_ucred(ctx));
1457 error = nnpfs_data_valid(vp, &cred, NNPFS_DATA_R,
1458 nnpfs_uio_offset(uiop),
1459 nnpfs_uio_end_length(uiop));
1461 if (error == 0) {
1462 struct nnpfs_node *node = VNODE_TO_XNODE(vp);
1463 off_t eof, resid;
1464 struct vnode *t;
1466 error = nnpfs_block_open(node, 0, FREAD, &t);
1467 if (error)
1468 goto out;
1470 eof = nnpfs_vattr_get_size(&node->attr);
1471 resid = nnpfs_uio_resid(uiop);
1473 if (resid > eof)
1474 nnpfs_uio_setresid(uiop, eof);
1476 #if defined(__APPLE__)
1477 nnpfs_vop_read(t, uiop, 0, ctx, error);
1478 #else
1479 nnpfs_vfs_readlock(t, proc);
1480 nnpfs_vop_read(t, uiop, 0, nnpfs_vfs_context_ucred(ctx), error);
1481 nnpfs_vfs_unlock(t, proc);
1482 #endif
1483 nnpfs_block_close(node, t, 0);
1485 if (resid > eof)
1486 nnpfs_uio_setresid(uiop, nnpfs_uio_resid(uiop) + (resid - eof));
1489 out:
1490 nnpfs_dev_unlock(nnpfsp);
1491 NNPFSDEB(XDEBVNOPS, ("nnpfs_readlink: return %d\n", error));
1493 return error;
1497 nnpfs_inactive_common(struct vnode *vp, d_thread_t *proc)
1499 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1500 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1501 int recyclep;
1502 int error;
1504 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive(%lx)\n", (unsigned long)vp));
1507 * This seems rather bogus, but sometimes we get an already
1508 * cleaned node to be made inactive. Just ignoring it seems safe.
1511 if (xn == NULL) {
1512 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: clean node\n"));
1513 return 0;
1516 /* xn->wr_cred not set -> NOCRED */
1518 if (nnpfs_vnode_isreg(vp))
1519 nnpfs_pushdirty(vp);
1521 nnpfs_dev_lock(nnpfsp);
1523 error = nnpfs_fsync_common(vp, NULL, &xn->wr_cred, 0, proc);
1524 if (error) {
1525 printf ("nnpfs_inactive: failed writing back data: %d\n", error);
1526 xn->flags &= ~NNPFS_DATA_DIRTY;
1529 /* If this node is no longer valid, recycle immediately. */
1530 recyclep = (!NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_R | NNPFS_ATTR_W)
1531 || (xn->flags & NNPFS_STALE) == NNPFS_STALE);
1533 #ifndef __FreeBSD__
1534 nnpfs_vfs_unlock(vp, proc);
1535 #endif
1537 if (recyclep) {
1538 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: vrecycle\n"));
1539 nnpfs_vrecycle(vp, 0, proc);
1542 NNPFSDEB(XDEBVNOPS, ("return: nnpfs_inactive done\n"));
1544 nnpfs_dev_unlock(nnpfsp);
1545 return 0;
1549 nnpfs_reclaim_common(struct vnode *vp)
1551 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1552 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1554 NNPFSDEB(XDEBVNOPS, ("nnpfs_reclaim(%lx)\n", (unsigned long)vp));
1556 nnpfs_dev_lock(nnpfsp);
1558 xn->flags |= NNPFS_LIMBO;
1560 nnpfs_release_data(xn);
1562 nnpfs_dnlc_purge(vp);
1564 NNPQUEUE_INSERT_HEAD(&nnpfsp->freehead, xn, nn_free);
1566 if (nnpfsp->status & CHANNEL_OPENED) {
1567 struct nnpfs_message_inactivenode msg;
1569 msg.header.opcode = NNPFS_MSG_INACTIVENODE;
1570 msg.handle = xn->handle;
1571 msg.flag = NNPFS_NOREFS | NNPFS_DELETE;
1572 nnpfs_message_send(nnpfsp, &msg.header, sizeof(msg));
1573 } else {
1574 nnpfs_free_node(nnpfsp, xn);
1577 nnpfs_dev_unlock(nnpfsp);
1578 NNPFSDEB(XDEBVNOPS, ("nnpfs_reclaim done\n"));
1580 return 0;
1587 #if 0
1590 nnpfs_advlock_common(struct vnode *dvp,
1591 int locktype,
1592 unsigned long lockid, /* XXX this good ? */
1593 nnpfs_kernel_cred cred)
1595 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1596 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1597 int error = 0;
1599 nnpfs_dev_lock(nnpfsp);
1600 NNPFSDEB(XDEBVNOPS, ("nnpfs_advlock\n"));
1602 struct nnpfs_message_advlock msg;
1604 msg.header.opcode = NNPFS_MSG_ADVLOCK;
1605 msg.handle = xn->handle;
1606 msg.locktype = locktype;
1607 msg.lockid = lockid;
1609 nnpfs_setcred(&msg.cred, cred);
1610 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg),
1611 nnpfs_vfs_context_proc(ctx));
1612 if (error == 0)
1613 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1616 if (error == 0) {
1618 /* sleep until woken */
1620 } else {
1622 /* die */
1625 nnpfs_dev_unlock(nnpfsp);
1626 return error;
1629 #endif
1635 void
1636 nnpfs_printnode_common (struct vnode *vp)
1638 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1640 printf ("xnode: fid: %d.%d.%d.%d\n",
1641 xn->handle.a, xn->handle.b, xn->handle.c, xn->handle.d);
1642 printf ("\tattr: %svalid\n",
1643 NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_VALID) ? "": "in");
1644 printf ("\tdata: %svalid\n",
1645 NNPFS_TOKEN_GOT(xn, NNPFS_DATA_VALID) ? "": "in");
1646 printf ("\tflags: 0x%x\n", xn->flags);