forget about device fd, we don't need it
[arla.git] / nnpfs / bsd / nnpfs_vnodeops-common.c
blob3455139bf41a8c1315b1e151b00d0a32712677a7
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 #if __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 #endif
704 nnpfs_vfs_writelock(t, nnpfs_vfs_context_proc(ctx));
705 (void)VOP_LEASE(t, nnpfs_vfs_context_proc(ctx), cred, LEASE_WRITE);
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 nnpfs_vfs_unlock(t, nnpfs_vfs_context_proc(ctx));
729 #ifdef __FreeBSD__
730 vn_finished_write(mp);
731 #endif
733 nnpfs_block_close(xn, t, 1);
735 if (error)
736 break;
739 xn->flags |= NNPFS_DATA_DIRTY;
740 nnpfs_uio_setoffset(uiop, offset);
741 nnpfs_uio_setresid(uiop, length - offset);
743 nnpfs_dev_unlock(nnpfsp);
745 NNPFSDEB(XDEBVNOPS, ("nnpfs_write -> %d\n", error));
747 return error;
751 nnpfs_getattr_common(struct vnode *vp, struct nnpfs_vfs_vattr *vap,
752 nnpfs_kernel_cred cred, d_thread_t *p)
754 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
755 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
756 int error = 0;
758 nnpfs_dev_lock(nnpfsp);
759 NNPFSDEB(XDEBVNOPS, ("nnpfs_getattr\n"));
761 error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
762 if (error == 0)
763 *vap = xn->attr;
765 nnpfs_dev_unlock(nnpfsp);
767 return error;
770 static int
771 setattr_is_noop(struct nnpfs_node *xn, struct nnpfs_vfs_vattr *vap)
773 #ifdef __APPLE__
775 #define CHECK_NNPFSATTR(A) (!VATTR_IS_ACTIVE(vap, A) || vap->A == xn->attr.A)
776 if (CHECK_NNPFSATTR(va_mode) &&
777 CHECK_NNPFSATTR(va_nlink) &&
778 CHECK_NNPFSATTR(va_data_size) &&
779 CHECK_NNPFSATTR(va_uid) &&
780 CHECK_NNPFSATTR(va_gid) &&
781 CHECK_NNPFSATTR(va_fileid) && /* we ignore va_type */
782 (!VATTR_IS_ACTIVE(vap, va_modify_time)
783 || vap->va_modify_time.tv_sec == xn->attr.va_modify_time.tv_sec))
784 return 1;
785 #undef CHECK_NNPFSATTR
787 #else
789 #define CHECK_NNPFSATTR(A, cast) (vap->A == cast VNOVAL || vap->A == xn->attr.A)
790 if (CHECK_NNPFSATTR(va_mode,(mode_t)) &&
791 CHECK_NNPFSATTR(va_nlink,(short)) &&
792 CHECK_NNPFSATTR(va_size,(va_size_t)) &&
793 CHECK_NNPFSATTR(va_uid,(uid_t)) &&
794 CHECK_NNPFSATTR(va_gid,(gid_t)) &&
795 CHECK_NNPFSATTR(va_mtime.tv_sec,(time_t)) &&
796 CHECK_NNPFSATTR(va_fileid,(long)) &&
797 CHECK_NNPFSATTR(va_type,(enum vtype)))
798 return 1;
799 #undef CHECK_NNPFSATTR
801 #endif /* ! __APPLE__ */
803 return 0;
807 nnpfs_setattr_common(struct vnode *vp, struct nnpfs_vfs_vattr *vap,
808 nnpfs_kernel_cred cred, d_thread_t *p)
810 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
811 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
812 int error = 0;
814 nnpfs_dev_lock(nnpfsp);
815 NNPFSDEB(XDEBVNOPS, ("nnpfs_setattr\n"));
817 if (setattr_is_noop(xn, vap)) {
818 nnpfs_dev_unlock(nnpfsp);
819 return 0; /* nothing to do */
822 if (NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_W)) {
823 /* Update attributes and mark them dirty. */
824 VNODE_TO_XNODE(vp)->flags |= NNPFS_ATTR_DIRTY;
825 error = EINVAL; /* XXX not yet implemented */
826 goto done;
827 } else {
828 struct nnpfs_message_putattr msg;
829 uint64_t old_length, new_length;
831 msg.header.opcode = NNPFS_MSG_PUTATTR;
832 nnpfs_setcred(&msg.cred, cred);
833 msg.handle = xn->handle;
834 vattr2nnpfs_attr(vap, &msg.attr);
836 if (NNPFS_TOKEN_GOT(xn, NNPFS_DATA_R)) {
837 if (nnpfs_vnode_isreg(vp)) {
838 old_length = nnpfs_vattr_get_size(&xn->attr);
840 if (nnpfs_vattr_size_isactive(vap)) {
841 new_length = nnpfs_vattr_get_size(vap);
843 XA_SET_SIZE(&msg.attr, new_length);
844 } else {
845 XA_SET_SIZE(&msg.attr, old_length);
849 if (nnpfs_vattr_mtime_isactive(vap))
850 XA_SET_MTIME(&msg.attr, nnpfs_vattr_get_mtime_sec(vap));
851 else
852 XA_SET_MTIME(&msg.attr, nnpfs_vattr_get_mtime_sec(&xn->attr));
855 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
856 if (error == 0)
857 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
859 #if 0 /* assume length is always in (loose) sync with daemon nowadays */
860 if (error == 0 && do_fixup)
861 truncate_block_fixup(xn, old_length, new_length);
862 #endif
865 done:
866 nnpfs_dev_unlock(nnpfsp);
867 NNPFS_VN_KNOTE(vp, NOTE_ATTRIB);
869 return error;
872 static int
873 check_rights (nnpfs_rights rights, int mode, int dirp)
875 int error = 0;
877 #ifdef __APPLE__
878 /* VNOP_ACCESS passes a kauth action instead of ordinary unix mode */
880 if (dirp) {
881 if (mode & (KAUTH_VNODE_LIST_DIRECTORY | KAUTH_VNODE_SEARCH))
882 if ((rights & NNPFS_RIGHT_X) == 0)
883 error = EACCES;
884 if (mode & KAUTH_VNODE_DELETE_CHILD)
885 if ((rights & NNPFS_RIGHT_AD) == 0)
886 error = EACCES;
887 if (mode & (KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY))
888 if ((rights & NNPFS_RIGHT_AI) == 0)
889 error = EACCES;
891 /* XXX can't check KAUTH_VNODE_DELETE, have no info */
893 } else {
894 if (mode & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_ATTRIBUTES))
895 if ((rights & NNPFS_RIGHT_AR) == 0)
896 error = EACCES;
897 if (mode & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA | KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_TAKE_OWNERSHIP))
898 if ((rights & NNPFS_RIGHT_W) == 0)
899 error = EACCES;
900 if (mode & KAUTH_VNODE_EXECUTE)
901 if ((rights & NNPFS_RIGHT_X) == 0)
902 error = EACCES;
903 if (mode & KAUTH_VNODE_DELETE)
904 if ((rights & NNPFS_RIGHT_AD) == 0)
905 error = EACCES;
908 #if 0
909 KAUTH_VNODE_READ_EXTATTRIBUTES
910 KAUTH_VNODE_WRITE_EXTATTRIBUTES
911 KAUTH_VNODE_READ_SECURITY
912 KAUTH_VNODE_WRITE_SECURITY
913 KAUTH_VNODE_SYNCHRONIZE notused
914 KAUTH_VNODE_LINKTARGET like insert, but for target???
915 KAUTH_VNODE_CHECKIMMUTABLE always ok
916 KAUTH_VNODE_ACCESS (advisory)
917 KAUTH_VNODE_NOIMMUTABLE ?
918 #endif
920 #else /* !__APPLE__ */
922 if (mode & VREAD)
923 if ((rights & NNPFS_RIGHT_R) == 0)
924 error = EACCES;
925 if (mode & VWRITE)
926 if ((rights & NNPFS_RIGHT_W) == 0)
927 error = EACCES;
928 if (mode & VEXEC)
929 if ((rights & NNPFS_RIGHT_X) == 0)
930 error = EACCES;
932 #endif /* !__APPLE__ */
934 return error;
938 nnpfs_access_common(struct vnode *vp, int mode, nnpfs_kernel_cred cred,
939 d_thread_t *p)
941 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
942 int dirp = nnpfs_vnode_isdir(vp);
943 int error = 0;
944 nnpfs_pag_t pag;
946 nnpfs_dev_lock(nnpfsp);
947 NNPFSDEB(XDEBVNOPS, ("nnpfs_access mode = 0%o\n", mode));
949 pag = nnpfs_get_pag(cred);
951 error = nnpfs_attr_valid(vp, cred, p, NNPFS_ATTR_R);
952 if (error == 0) {
953 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
954 int i;
956 error = check_rights(xn->anonrights, mode, dirp);
958 if (error == 0)
959 goto done;
961 NNPFSDEB(XDEBVNOPS, ("nnpfs_access anonaccess failed\n"));
963 error = EACCES; /* default to EACCES if pag isn't in xn->id */
965 for (i = 0; i < NNPFS_MAXRIGHTS; i++)
966 if (xn->id[i] == pag) {
967 error = check_rights(xn->rights[i], mode, dirp);
968 break;
972 done:
973 NNPFSDEB(XDEBVNOPS, ("nnpfs_access(0%o) = %d\n", mode, error));
974 nnpfs_dev_unlock(nnpfsp);
976 return error;
980 nnpfs_lookup_common(struct vnode *dvp,
981 nnpfs_componentname *cnp,
982 struct vnode **vpp,
983 nnpfs_vfs_context ctx)
985 struct nnpfs_message_getnode msg;
986 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
987 d_thread_t *p = nnpfs_vfs_context_proc(ctx);
988 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
989 struct nnpfs_node *d = VNODE_TO_XNODE(dvp);
990 int error = 0;
992 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: enter\n"));
994 *vpp = NULL;
996 if (cnp->cn_namelen >= NNPFS_MAX_NAME)
997 return ENAMETOOLONG;
999 if (!nnpfs_vnode_isdir(dvp))
1000 return ENOTDIR;
1002 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
1003 *vpp = dvp;
1004 #ifdef __APPLE__
1005 nnpfs_do_vget(*vpp, 0 /* XXX flag */, NULL /*proc */);
1006 #else
1007 nnpfs_vref(*vpp);
1008 #endif
1009 return 0;
1012 nnpfs_dev_lock(nnpfsp);
1013 do {
1014 nnpfs_lookup_access(dvp, ctx, p, error);
1015 if (error != 0)
1016 goto done;
1018 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: dvp = %lx\n",
1019 (unsigned long) dvp));
1020 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: cnp = %lx, "
1021 "cnp->cn_nameiop = %d\n",
1022 (unsigned long) cnp, (int)cnp->cn_nameiop));
1024 error = nnpfs_dnlc_lookup(dvp, cnp, vpp);
1025 if (error == 0) { /* not cached */
1028 * Doesn't quite work.
1031 #if 0
1032 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
1033 && (cnp->cn_flags & ISLASTCN)) {
1034 error = EJUSTRETURN;
1035 goto done;
1037 #endif
1039 msg.header.opcode = NNPFS_MSG_GETNODE;
1040 nnpfs_setcred(&msg.cred, cred);
1041 msg.parent_handle = d->handle;
1042 memcpy(msg.name, cnp->cn_nameptr, cnp->cn_namelen);
1043 msg.name[cnp->cn_namelen] = '\0';
1044 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1045 if (error == 0)
1046 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1047 if(error == ENOENT && cnp->cn_nameiop != CREATE) {
1048 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup: neg cache %lx (%s, %ld)\n",
1049 (unsigned long)dvp,
1050 cnp->cn_nameptr, cnp->cn_namelen));
1051 nnpfs_dnlc_enter (dvp, cnp, NULL);
1053 } else if (error == -1) { /* found */
1054 error = 0;
1055 goto done;
1057 } while (error == 0);
1059 done:
1060 nnpfs_dev_unlock(nnpfsp);
1061 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1063 NNPFSDEB(XDEBVNOPS, ("nnpfs_lookup_common: return %d, vn %p\n",
1064 error, *vpp));
1065 return error;
1069 nnpfs_create_common(struct vnode *dvp,
1070 const char *name,
1071 struct nnpfs_vfs_vattr *vap,
1072 nnpfs_kernel_cred cred,
1073 d_thread_t *p)
1075 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1076 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1077 int error = 0;
1079 nnpfs_dev_lock(nnpfsp);
1080 NNPFSDEB(XDEBVNOPS, ("nnpfs_create: (%lx, %s)\n",
1081 (unsigned long)dvp, name));
1083 struct nnpfs_message_create msg;
1085 msg.header.opcode = NNPFS_MSG_CREATE;
1086 msg.parent_handle = xn->handle;
1087 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1088 return ENAMETOOLONG;
1089 vattr2nnpfs_attr(vap, &msg.attr);
1091 msg.mode = 0; /* XXX - mode */
1092 nnpfs_setcred(&msg.cred, cred);
1094 #ifdef __APPLE__
1095 /* needed for subsequent writes to succeed with n */
1096 msg.attr.valid &= ~XA_V_UID;
1097 #endif
1099 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1100 if (error == 0)
1101 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1104 #if 0
1105 if (error == EEXIST)
1106 error = 0;
1107 #endif
1109 nnpfs_dev_unlock(nnpfsp);
1111 NNPFSDEB(XDEBVNOPS, ("nnpfs_create -> %d\n", error));
1113 return error;
1117 nnpfs_remove_common(struct vnode *dvp,
1118 struct vnode *vp,
1119 const char *name,
1120 nnpfs_kernel_cred cred,
1121 d_thread_t *p)
1123 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1124 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1125 struct nnpfs_message_remove msg;
1126 int error;
1128 nnpfs_dev_lock(nnpfsp);
1129 NNPFSDEB(XDEBVNOPS, ("nnpfs_remove(%p): %s\n", dvp, name));
1131 msg.header.opcode = NNPFS_MSG_REMOVE;
1132 msg.parent_handle = xn->handle;
1133 msg.cred.uid = nnpfs_cred_get_uid(cred);
1134 msg.cred.pag = nnpfs_get_pag(cred);
1136 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1137 error = ENAMETOOLONG;
1138 else
1139 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1140 if (error == 0)
1141 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1143 if (error == 0)
1144 nnpfs_dnlc_purge (vp);
1146 nnpfs_dev_unlock(nnpfsp);
1148 if (error == 0) {
1149 NNPFS_VN_KNOTE(vp, NOTE_DELETE);
1150 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1153 NNPFSDEB(XDEBVNOPS, ("nnpfs_remove -> %d\n", error));
1155 return error;
1159 nnpfs_rename_common(struct vnode *fdvp,
1160 struct vnode *fvp,
1161 const char *fname,
1162 struct vnode *tdvp,
1163 struct vnode *tvp,
1164 const char *tname,
1165 nnpfs_kernel_cred cred,
1166 d_thread_t *p)
1168 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(fdvp);
1169 int error;
1171 nnpfs_dev_lock(nnpfsp);
1172 NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: %s %s\n", fname, tname));
1174 #if 0
1175 if ((fvp->v_mount != tdvp->v_mount)
1176 || (tvp && (fvp->v_mount != tvp->v_mount))) {
1177 return EXDEV;
1179 #endif
1182 struct nnpfs_message_rename msg;
1184 msg.header.opcode = NNPFS_MSG_RENAME;
1185 msg.old_parent_handle = VNODE_TO_XNODE(fdvp)->handle;
1186 if (strlcpy(msg.old_name, fname, sizeof(msg.old_name)) >= NNPFS_MAX_NAME) {
1187 nnpfs_dev_unlock(nnpfsp);
1188 return ENAMETOOLONG;
1191 msg.new_parent_handle = VNODE_TO_XNODE(tdvp)->handle;
1192 if (strlcpy(msg.new_name, tname, sizeof(msg.new_name)) >= NNPFS_MAX_NAME) {
1193 nnpfs_dev_unlock(nnpfsp);
1194 return ENAMETOOLONG;
1197 msg.cred.uid = nnpfs_cred_get_uid(cred);
1198 msg.cred.pag = nnpfs_get_pag(cred);
1199 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1200 if (error == 0)
1201 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1205 nnpfs_dev_unlock(nnpfsp);
1206 NNPFS_VN_KNOTE(fdvp, NOTE_WRITE);
1207 NNPFS_VN_KNOTE(fvp, NOTE_WRITE);
1209 NNPFSDEB(XDEBVNOPS, ("nnpfs_rename: error = %d\n", error));
1211 return error;
1215 nnpfs_mkdir_common(struct vnode *dvp,
1216 const char *name,
1217 struct nnpfs_vfs_vattr *vap,
1218 nnpfs_kernel_cred cred,
1219 d_thread_t *p)
1221 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1222 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1223 int error = 0;
1225 nnpfs_dev_lock(nnpfsp);
1226 NNPFSDEB(XDEBVNOPS, ("nnpfs_mkdir(%p): %s\n", dvp, name));
1228 struct nnpfs_message_mkdir msg;
1230 msg.header.opcode = NNPFS_MSG_MKDIR;
1231 msg.parent_handle = xn->handle;
1232 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1233 nnpfs_dev_unlock(nnpfsp);
1234 return ENAMETOOLONG;
1237 vattr2nnpfs_attr(vap, &msg.attr);
1238 nnpfs_setcred(&msg.cred, cred);
1239 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1240 if (error == 0)
1241 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1244 nnpfs_dev_unlock(nnpfsp);
1246 if (error == 0)
1247 NNPFS_VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1249 NNPFSDEB(XDEBVNOPS, ("nnpfs_mkdir -> %d\n", error));
1250 return error;
1254 nnpfs_rmdir_common(struct vnode *dvp,
1255 struct vnode *vp,
1256 const char *name,
1257 nnpfs_kernel_cred cred,
1258 d_thread_t *p)
1260 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1261 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1262 struct nnpfs_message_rmdir msg;
1263 int error;
1265 nnpfs_dev_lock(nnpfsp);
1266 NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir: %s\n", name));
1268 msg.header.opcode = NNPFS_MSG_RMDIR;
1269 msg.parent_handle = xn->handle;
1270 msg.cred.uid = nnpfs_cred_get_uid(cred);
1271 msg.cred.pag = nnpfs_get_pag(cred);
1272 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME)
1273 error = ENAMETOOLONG;
1274 else
1275 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1276 if (error == 0)
1277 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1279 if (error == 0) {
1280 nnpfs_dnlc_purge (vp);
1282 /* XXX knote even on error? */
1283 NNPFS_VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1284 NNPFS_VN_KNOTE(vp, NOTE_DELETE);
1287 nnpfs_dev_unlock(nnpfsp);
1289 NNPFSDEB(XDEBVNOPS, ("nnpfs_rmdir error: %d\n", error));
1291 return error;
1295 nnpfs_readdir_common(struct vnode *vp,
1296 struct uio *uiop,
1297 int *eofflag,
1298 nnpfs_vfs_context ctx)
1300 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1301 struct vnode *t = NULL;
1302 struct nnpfs_node *node;
1303 nnpfs_cred cred;
1304 int error;
1306 nnpfs_dev_lock(nnpfsp);
1307 NNPFSDEB(XDEBVNOPS, ("nnpfs_readdir(%p)\n", vp));
1309 if (eofflag)
1310 *eofflag = 0;
1312 nnpfs_assert(nnpfs_vnode_isdir(vp));
1314 nnpfs_setcred(&cred, nnpfs_vfs_context_ucred(ctx));
1316 /* XXX dir can be removed at any moment, but this is ridiculous. */
1317 while (1) {
1318 error = nnpfs_data_valid(vp, &cred, NNPFS_DATA_R,
1319 nnpfs_uio_offset(uiop),
1320 nnpfs_uio_end_length(uiop));
1321 if (error) {
1322 nnpfs_dev_unlock(nnpfsp);
1323 return error;
1325 node = VNODE_TO_XNODE(vp);
1326 error = nnpfs_block_open(node, 0, FREAD, &t);
1327 if (!error)
1328 break;
1331 nnpfs_vfs_readlock(t, nnpfs_uio_to_proc(uiop));
1332 nnpfs_vop_read(t, uiop, 0, NULL, error);
1333 if (eofflag) {
1334 struct nnpfs_vfs_vattr t_attr;
1335 int error2;
1337 #ifdef __APPLE__
1338 VATTR_INIT(&t_attr);
1339 VATTR_WANTED(&t_attr, va_data_size);
1340 #endif
1341 nnpfs_vop_getattr(t, &t_attr, ctx, error2); /* XXX check bitmask */
1342 if (error2 == 0)
1343 *eofflag = nnpfs_vattr_get_size(&t_attr) <= nnpfs_uio_offset(uiop);
1345 nnpfs_vfs_unlock(t, nnpfs_uio_to_proc(uiop));
1346 nnpfs_block_close(node, t, 0);
1348 nnpfs_dev_unlock(nnpfsp);
1350 NNPFSDEB(XDEBVNOPS, ("nnpfs_readdir -> %d\n", error));
1352 return error;
1356 nnpfs_link_common(struct vnode *dvp,
1357 struct vnode *vp,
1358 const char *name,
1359 nnpfs_kernel_cred cred,
1360 d_thread_t *p)
1362 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1363 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1364 struct nnpfs_node *xn2 = VNODE_TO_XNODE(vp);
1365 struct nnpfs_message_link msg;
1366 int error = 0;
1368 nnpfs_dev_lock(nnpfsp);
1369 NNPFSDEB(XDEBVNOPS, ("nnpfs_link: %s\n", name));
1371 msg.header.opcode = NNPFS_MSG_LINK;
1372 msg.parent_handle = xn->handle;
1373 msg.from_handle = xn2->handle;
1374 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1375 nnpfs_dev_unlock(nnpfsp);
1376 return ENAMETOOLONG;
1379 msg.cred.uid = nnpfs_cred_get_uid(cred);
1380 msg.cred.pag = nnpfs_get_pag(cred);
1382 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg), p);
1383 if (error == 0)
1384 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1386 nnpfs_dev_unlock(nnpfsp);
1387 NNPFS_VN_KNOTE(vp, NOTE_LINK);
1389 return error;
1393 nnpfs_symlink_common(struct vnode *dvp,
1394 struct vnode **vpp,
1395 nnpfs_componentname *cnp,
1396 struct nnpfs_vfs_vattr *vap,
1397 char *target,
1398 nnpfs_vfs_context ctx)
1400 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1401 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1402 nnpfs_kernel_cred cred = nnpfs_vfs_context_ucred(ctx);
1403 struct nnpfs_message_symlink msg;
1404 const char *name = cnp->cn_nameptr;
1405 int error = 0;
1407 nnpfs_dev_lock(nnpfsp);
1408 NNPFSDEB(XDEBVNOPS, ("nnpfs_symlink: %s\n", name));
1410 msg.header.opcode = NNPFS_MSG_SYMLINK;
1411 msg.parent_handle = xn->handle;
1412 vattr2nnpfs_attr(vap, &msg.attr);
1413 msg.cred.uid = nnpfs_cred_get_uid(cred);
1414 msg.cred.pag = nnpfs_get_pag(cred);
1415 if (strlcpy (msg.contents, target, sizeof(msg.contents)) >= NNPFS_MAX_SYMLINK_CONTENT) {
1416 error = ENAMETOOLONG;
1417 goto done;
1419 if (strlcpy(msg.name, name, sizeof(msg.name)) >= NNPFS_MAX_NAME) {
1420 error = ENAMETOOLONG;
1421 goto done;
1423 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg),
1424 nnpfs_vfs_context_proc(ctx));
1425 if (error == 0)
1426 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1428 done:
1429 nnpfs_dev_unlock(nnpfsp);
1430 NNPFS_VN_KNOTE(dvp, NOTE_WRITE);
1432 return error;
1436 nnpfs_readlink_common(struct vnode *vp, struct uio *uiop, nnpfs_vfs_context ctx)
1438 int error = 0;
1439 nnpfs_cred cred;
1440 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1441 d_thread_t *proc = nnpfs_vfs_context_proc(ctx);
1443 NNPFSDEB(XDEBVNOPS, ("nnpfs_readlink\n"));
1445 if (!nnpfs_vnode_islnk(vp) || (nnpfs_uio_offset(uiop) != (off_t)0))
1446 return EINVAL;
1448 nnpfs_dev_lock(nnpfsp);
1450 /* XXX check it fits in one block */
1452 nnpfs_setcred(&cred, nnpfs_vfs_context_ucred(ctx));
1453 error = nnpfs_data_valid(vp, &cred, NNPFS_DATA_R,
1454 nnpfs_uio_offset(uiop),
1455 nnpfs_uio_end_length(uiop));
1457 if (error == 0) {
1458 struct nnpfs_node *node = VNODE_TO_XNODE(vp);
1459 off_t eof, resid;
1460 struct vnode *t;
1462 error = nnpfs_block_open(node, 0, FREAD, &t);
1463 if (error)
1464 goto out;
1466 eof = nnpfs_vattr_get_size(&node->attr);
1467 resid = nnpfs_uio_resid(uiop);
1469 if (resid > eof)
1470 nnpfs_uio_setresid(uiop, eof);
1472 #if defined(__APPLE__)
1473 nnpfs_vop_read(t, uiop, 0, ctx, error);
1474 #else
1475 nnpfs_vfs_readlock(t, proc);
1476 nnpfs_vop_read(t, uiop, 0, nnpfs_vfs_context_ucred(ctx), error);
1477 nnpfs_vfs_unlock(t, proc);
1478 #endif
1479 nnpfs_block_close(node, t, 0);
1481 if (resid > eof)
1482 nnpfs_uio_setresid(uiop, nnpfs_uio_resid(uiop) + (resid - eof));
1485 out:
1486 nnpfs_dev_unlock(nnpfsp);
1487 NNPFSDEB(XDEBVNOPS, ("nnpfs_readlink: return %d\n", error));
1489 return error;
1493 nnpfs_inactive_common(struct vnode *vp, d_thread_t *proc)
1495 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1496 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1497 int recyclep;
1498 int error;
1500 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive(%lx)\n", (unsigned long)vp));
1503 * This seems rather bogus, but sometimes we get an already
1504 * cleaned node to be made inactive. Just ignoring it seems safe.
1507 if (xn == NULL) {
1508 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: clean node\n"));
1509 return 0;
1512 /* xn->wr_cred not set -> NOCRED */
1514 if (nnpfs_vnode_isreg(vp))
1515 nnpfs_pushdirty(vp);
1517 nnpfs_dev_lock(nnpfsp);
1519 error = nnpfs_fsync_common(vp, NULL, &xn->wr_cred, 0, proc);
1520 if (error) {
1521 printf ("nnpfs_inactive: failed writing back data: %d\n", error);
1522 xn->flags &= ~NNPFS_DATA_DIRTY;
1525 /* If this node is no longer valid, recycle immediately. */
1526 recyclep = (!NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_R | NNPFS_ATTR_W)
1527 || (xn->flags & NNPFS_STALE) == NNPFS_STALE);
1529 #ifndef __FreeBSD__
1530 nnpfs_vfs_unlock(vp, proc);
1531 #endif
1533 if (recyclep) {
1534 NNPFSDEB(XDEBVNOPS, ("nnpfs_inactive: vrecycle\n"));
1535 nnpfs_vrecycle(vp, 0, proc);
1538 NNPFSDEB(XDEBVNOPS, ("return: nnpfs_inactive done\n"));
1540 nnpfs_dev_unlock(nnpfsp);
1541 return 0;
1545 nnpfs_reclaim_common(struct vnode *vp)
1547 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(vp);
1548 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1550 NNPFSDEB(XDEBVNOPS, ("nnpfs_reclaim(%lx)\n", (unsigned long)vp));
1552 nnpfs_dev_lock(nnpfsp);
1554 xn->flags |= NNPFS_LIMBO;
1556 nnpfs_release_data(xn);
1558 nnpfs_dnlc_purge(vp);
1560 NNPQUEUE_INSERT_HEAD(&nnpfsp->freehead, xn, nn_free);
1562 if (nnpfsp->status & CHANNEL_OPENED) {
1563 struct nnpfs_message_inactivenode msg;
1565 msg.header.opcode = NNPFS_MSG_INACTIVENODE;
1566 msg.handle = xn->handle;
1567 msg.flag = NNPFS_NOREFS | NNPFS_DELETE;
1568 nnpfs_message_send(nnpfsp, &msg.header, sizeof(msg));
1569 } else {
1570 nnpfs_free_node(nnpfsp, xn);
1573 nnpfs_dev_unlock(nnpfsp);
1574 NNPFSDEB(XDEBVNOPS, ("nnpfs_reclaim done\n"));
1576 return 0;
1583 #if 0
1586 nnpfs_advlock_common(struct vnode *dvp,
1587 int locktype,
1588 unsigned long lockid, /* XXX this good ? */
1589 nnpfs_kernel_cred cred)
1591 struct nnpfs *nnpfsp = NNPFS_FROM_VNODE(dvp);
1592 struct nnpfs_node *xn = VNODE_TO_XNODE(dvp);
1593 int error = 0;
1595 nnpfs_dev_lock(nnpfsp);
1596 NNPFSDEB(XDEBVNOPS, ("nnpfs_advlock\n"));
1598 struct nnpfs_message_advlock msg;
1600 msg.header.opcode = NNPFS_MSG_ADVLOCK;
1601 msg.handle = xn->handle;
1602 msg.locktype = locktype;
1603 msg.lockid = lockid;
1605 nnpfs_setcred(&msg.cred, cred);
1606 error = nnpfs_message_rpc(nnpfsp, &msg.header, sizeof(msg),
1607 nnpfs_vfs_context_proc(ctx));
1608 if (error == 0)
1609 error = NNPFS_MSG_WAKEUP_ERROR(&msg);
1612 if (error == 0) {
1614 /* sleep until woken */
1616 } else {
1618 /* die */
1621 nnpfs_dev_unlock(nnpfsp);
1622 return error;
1625 #endif
1631 void
1632 nnpfs_printnode_common (struct vnode *vp)
1634 struct nnpfs_node *xn = VNODE_TO_XNODE(vp);
1636 printf ("xnode: fid: %d.%d.%d.%d\n",
1637 xn->handle.a, xn->handle.b, xn->handle.c, xn->handle.d);
1638 printf ("\tattr: %svalid\n",
1639 NNPFS_TOKEN_GOT(xn, NNPFS_ATTR_VALID) ? "": "in");
1640 printf ("\tdata: %svalid\n",
1641 NNPFS_TOKEN_GOT(xn, NNPFS_DATA_VALID) ? "": "in");
1642 printf ("\tflags: 0x%x\n", xn->flags);