xref: /openbsd-src/sys/miscfs/fuse/fuse_vnops.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: fuse_vnops.c,v 1.33 2016/09/07 17:53:35 natano Exp $ */
2 /*
3  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/dirent.h>
21 #include <sys/fcntl.h>
22 #include <sys/file.h>
23 #include <sys/lockf.h>
24 #include <sys/malloc.h>
25 #include <sys/mount.h>
26 #include <sys/namei.h>
27 #include <sys/poll.h>
28 #include <sys/proc.h>
29 #include <sys/specdev.h>
30 #include <sys/stat.h>
31 #include <sys/statvfs.h>
32 #include <sys/vnode.h>
33 #include <sys/lock.h>
34 #include <sys/fusebuf.h>
35 
36 #include "fusefs_node.h"
37 #include "fusefs.h"
38 
39 /* Prototypes for fusefs vnode ops */
40 int	fusefs_kqfilter(void *);
41 int	fusefs_lookup(void *);
42 int	fusefs_open(void *);
43 int	fusefs_close(void *);
44 int	fusefs_access(void *);
45 int	fusefs_getattr(void *);
46 int	fusefs_setattr(void *);
47 int	fusefs_ioctl(void *);
48 int	fusefs_link(void *);
49 int	fusefs_symlink(void *);
50 int	fusefs_readdir(void *);
51 int	fusefs_readlink(void *);
52 int	fusefs_inactive(void *);
53 int	fusefs_reclaim(void *);
54 int	fusefs_print(void *);
55 int	fusefs_create(void *);
56 int	fusefs_mknod(void *);
57 int	fusefs_read(void *);
58 int	fusefs_write(void *);
59 int	fusefs_poll(void *);
60 int	fusefs_remove(void *);
61 int	fusefs_rename(void *);
62 int	fusefs_mkdir(void *);
63 int	fusefs_rmdir(void *);
64 int	fusefs_strategy(void *);
65 int	fusefs_lock(void *);
66 int	fusefs_unlock(void *);
67 int	fusefs_islocked(void *);
68 int	fusefs_advlock(void *);
69 
70 /* Prototypes for fusefs kqfilter */
71 int	filt_fusefsread(struct knote *, long);
72 int	filt_fusefswrite(struct knote *, long);
73 int	filt_fusefsvnode(struct knote *, long);
74 void	filt_fusefsdetach(struct knote *);
75 
76 struct vops fusefs_vops = {
77 	.vop_lookup	= fusefs_lookup,
78 	.vop_create	= fusefs_create,
79 	.vop_mknod	= fusefs_mknod,
80 	.vop_open	= fusefs_open,
81 	.vop_close	= fusefs_close,
82 	.vop_access	= fusefs_access,
83 	.vop_getattr	= fusefs_getattr,
84 	.vop_setattr	= fusefs_setattr,
85 	.vop_read	= fusefs_read,
86 	.vop_write	= fusefs_write,
87 	.vop_ioctl	= fusefs_ioctl,
88 	.vop_poll	= fusefs_poll,
89 	.vop_kqfilter	= fusefs_kqfilter,
90 	.vop_fsync	= nullop,
91 	.vop_remove	= fusefs_remove,
92 	.vop_link	= fusefs_link,
93 	.vop_rename	= fusefs_rename,
94 	.vop_mkdir	= fusefs_mkdir,
95 	.vop_rmdir	= fusefs_rmdir,
96 	.vop_symlink	= fusefs_symlink,
97 	.vop_readdir	= fusefs_readdir,
98 	.vop_readlink	= fusefs_readlink,
99 	.vop_abortop	= vop_generic_abortop,
100 	.vop_inactive	= fusefs_inactive,
101 	.vop_reclaim	= fusefs_reclaim,
102 	.vop_lock	= fusefs_lock,
103 	.vop_unlock	= fusefs_unlock,
104 	.vop_bmap	= vop_generic_bmap,
105 	.vop_strategy	= fusefs_strategy,
106 	.vop_print	= fusefs_print,
107 	.vop_islocked	= fusefs_islocked,
108 	.vop_pathconf	= spec_pathconf,
109 	.vop_advlock	= fusefs_advlock,
110 };
111 
112 struct filterops fusefsread_filtops =
113 	{ 1, NULL, filt_fusefsdetach, filt_fusefsread };
114 struct filterops fusefswrite_filtops =
115 	{ 1, NULL, filt_fusefsdetach, filt_fusefswrite };
116 struct filterops fusefsvnode_filtops =
117 	{ 1, NULL, filt_fusefsdetach, filt_fusefsvnode };
118 
119 int
120 fusefs_kqfilter(void *v)
121 {
122 	struct vop_kqfilter_args *ap = v;
123 	struct vnode *vp = ap->a_vp;
124 	struct knote *kn = ap->a_kn;
125 
126 	switch (kn->kn_filter) {
127 	case EVFILT_READ:
128 		kn->kn_fop = &fusefsread_filtops;
129 		break;
130 	case EVFILT_WRITE:
131 		kn->kn_fop = &fusefswrite_filtops;
132 		break;
133 	case EVFILT_VNODE:
134 		kn->kn_fop = &fusefsvnode_filtops;
135 		break;
136 	default:
137 		return (EINVAL);
138 	}
139 
140 	kn->kn_hook = (caddr_t)vp;
141 
142 	SLIST_INSERT_HEAD(&vp->v_selectinfo.si_note, kn, kn_selnext);
143 
144 	return (0);
145 }
146 
147 void
148 filt_fusefsdetach(struct knote *kn)
149 {
150 	struct vnode *vp = (struct vnode *)kn->kn_hook;
151 
152 	SLIST_REMOVE(&vp->v_selectinfo.si_note, kn, knote, kn_selnext);
153 }
154 
155 int
156 filt_fusefsread(struct knote *kn, long hint)
157 {
158 	struct vnode *vp = (struct vnode *)kn->kn_hook;
159 	struct fusefs_node *ip = VTOI(vp);
160 
161 	/*
162 	 * filesystem is gone, so set the EOF flag and schedule
163 	 * the knote for deletion
164 	 */
165 	if (hint == NOTE_REVOKE) {
166 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
167 		return (1);
168 	}
169 
170 	kn->kn_data = ip->filesize - kn->kn_fp->f_offset;
171 	if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
172 		kn->kn_fflags |= NOTE_EOF;
173 		return (1);
174 	}
175 
176 	return (kn->kn_data != 0);
177 }
178 
179 int
180 filt_fusefswrite(struct knote *kn, long hint)
181 {
182 	/*
183 	 * filesystem is gone, so set the EOF flag and schedule
184 	 * the knote for deletion
185 	 */
186 	if (hint == NOTE_REVOKE) {
187 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
188 		return (1);
189 	}
190 
191 	kn->kn_data = 0;
192 	return (1);
193 }
194 
195 int
196 filt_fusefsvnode(struct knote *kn, long int hint)
197 {
198 	if (kn->kn_sfflags & hint)
199 		kn->kn_fflags |= hint;
200 	if (hint == NOTE_REVOKE) {
201 		kn->kn_flags |= EV_EOF;
202 		return (1);
203 	}
204 	return (kn->kn_fflags != 0);
205 }
206 
207 int
208 fusefs_open(void *v)
209 {
210 	struct vop_open_args *ap;
211 	struct fusefs_node *ip;
212 	struct fusefs_mnt *fmp;
213 	enum fufh_type fufh_type = FUFH_RDONLY;
214 	int flags = O_RDONLY;
215 	int error;
216 	int isdir;
217 
218 	ap = v;
219 	ip = VTOI(ap->a_vp);
220 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
221 
222 	if (!fmp->sess_init)
223 		return (ENXIO);
224 
225 	isdir = 0;
226 	if (ap->a_vp->v_type == VDIR)
227 		isdir = 1;
228 	else {
229 		if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) {
230 			fufh_type = FUFH_RDWR;
231 			flags = O_RDWR;
232 		} else if (ap->a_mode  & (FWRITE)) {
233 			fufh_type = FUFH_WRONLY;
234 			flags = O_WRONLY;
235 		}
236 	}
237 
238 	/* already open i think all is ok */
239 	if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
240 		return (0);
241 
242 	error = fusefs_file_open(fmp, ip, fufh_type, flags, isdir, ap->a_p);
243 	if (error)
244 		return (error);
245 
246 	return (error);
247 }
248 
249 int
250 fusefs_close(void *v)
251 {
252 	struct vop_close_args *ap;
253 	struct fusefs_node *ip;
254 	struct fusefs_mnt *fmp;
255 	enum fufh_type fufh_type = FUFH_RDONLY;
256 	int isdir, i;
257 
258 	ap = v;
259 	ip = VTOI(ap->a_vp);
260 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
261 
262 	if (!fmp->sess_init)
263 		return (0);
264 
265 	if (ap->a_vp->v_type == VDIR) {
266 		isdir = 1;
267 
268 		if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
269 			return (fusefs_file_close(fmp, ip, fufh_type, O_RDONLY,
270 			    isdir, ap->a_p));
271 	} else {
272 		if (ap->a_fflag & IO_NDELAY)
273 			return (0);
274 
275 		if ((ap->a_fflag & FREAD) && (ap->a_fflag & FWRITE))
276 			fufh_type = FUFH_RDWR;
277 		else if (ap->a_fflag  & (FWRITE))
278 			fufh_type = FUFH_WRONLY;
279 	}
280 
281 	/*
282 	 * if fh not valid lookup for another valid fh in vnode.
283 	 * Do we need panic if there's not a valid fh ?
284 	 */
285 	if (ip->fufh[fufh_type].fh_type != FUFH_INVALID) {
286 		for (i = 0; i < FUFH_MAXTYPE; i++)
287 			if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
288 				break;
289 		return (0);
290 	}
291 
292 	return (0);
293 }
294 
295 int
296 fusefs_access(void *v)
297 {
298 	struct vop_access_args *ap;
299 	struct fusefs_node *ip;
300 	struct fusefs_mnt *fmp;
301 	struct fusebuf *fbuf;
302 	struct ucred *cred;
303 	struct vattr vattr;
304 	struct proc *p;
305 	uint32_t mask = 0;
306 	int error = 0;
307 
308 	ap = v;
309 	p = ap->a_p;
310 	cred = p->p_ucred;
311 	ip = VTOI(ap->a_vp);
312 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
313 
314 	if (!fmp->sess_init)
315 		return (ENXIO);
316 
317 	if (fmp->undef_op & UNDEF_ACCESS)
318 		goto system_check;
319 
320 	if (ap->a_vp->v_type == VLNK)
321 		goto system_check;
322 
323 	if (ap->a_vp->v_type == VREG && (ap->a_mode & VWRITE & VEXEC))
324 		goto system_check;
325 
326 	if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY))
327 		return (EACCES);
328 
329 	if ((ap->a_mode & VWRITE) != 0)
330 		mask |= 0x2;
331 
332 	if ((ap->a_mode & VREAD) != 0)
333 		mask |= 0x4;
334 
335 	if ((ap->a_mode & VEXEC) != 0)
336 		mask |= 0x1;
337 
338 	fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_ACCESS, p);
339 	fbuf->fb_io_mode = mask;
340 
341 	error = fb_queue(fmp->dev, fbuf);
342 	if (error) {
343 		if (error == ENOSYS) {
344 			fmp->undef_op |= UNDEF_ACCESS;
345 			fb_delete(fbuf);
346 			goto system_check;
347 		}
348 
349 		printf("fusefs: access error %i\n", error);
350 		fb_delete(fbuf);
351 		return (error);
352 	}
353 
354 	fb_delete(fbuf);
355 	return (error);
356 
357 system_check:
358 	if ((error = VOP_GETATTR(ap->a_vp, &vattr, cred, p)) != 0)
359 		return (error);
360 
361 	return (vaccess(ap->a_vp->v_type, vattr.va_mode & ALLPERMS,
362 	    vattr.va_uid, vattr.va_gid, ap->a_mode,
363 	    ap->a_cred));
364 }
365 
366 int
367 fusefs_getattr(void *v)
368 {
369 	struct vop_getattr_args *ap = v;
370 	struct vnode *vp = ap->a_vp;
371 	struct fusefs_mnt *fmp;
372 	struct vattr *vap = ap->a_vap;
373 	struct proc *p = ap->a_p;
374 	struct fusefs_node *ip;
375 	struct fusebuf *fbuf;
376 	struct stat *st;
377 	int error = 0;
378 
379 	ip = VTOI(vp);
380 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
381 
382 	if (!fmp->sess_init)
383 		return (ENXIO);
384 
385 	fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_GETATTR, p);
386 
387 	error = fb_queue(fmp->dev, fbuf);
388 	if (error) {
389 		fb_delete(fbuf);
390 		return (error);
391 	}
392 
393 	VATTR_NULL(vap);
394 	st = &fbuf->fb_attr;
395 
396 	vap->va_type = IFTOVT(st->st_mode);
397 	vap->va_mode = st->st_mode & ~S_IFMT;
398 	vap->va_nlink = st->st_nlink;
399 	vap->va_uid = st->st_uid;
400 	vap->va_gid = st->st_gid;
401 	vap->va_fsid = fmp->mp->mnt_stat.f_fsid.val[0];
402 	vap->va_fileid = st->st_ino;
403 	vap->va_size = st->st_size;
404 	vap->va_blocksize = st->st_blksize;
405 	vap->va_atime = st->st_atim;
406 	vap->va_mtime = st->st_mtim;
407 	vap->va_ctime = st->st_ctim;
408 	vap->va_rdev = st->st_rdev;
409 	vap->va_bytes = st->st_blocks * S_BLKSIZE;
410 
411 	fb_delete(fbuf);
412 	return (error);
413 }
414 
415 int
416 fusefs_setattr(void *v)
417 {
418 	struct vop_setattr_args *ap = v;
419 	struct vattr *vap = ap->a_vap;
420 	struct vnode *vp = ap->a_vp;
421 	struct fusefs_node *ip = VTOI(vp);
422 	struct proc *p = ap->a_p;
423 	struct fusefs_mnt *fmp;
424 	struct fusebuf *fbuf;
425 	struct fb_io *io;
426 	int error = 0;
427 
428 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
429 	/*
430 	 * Check for unsettable attributes.
431 	 */
432 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
433 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
434 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
435 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
436 		return (EINVAL);
437 
438 	if (!fmp->sess_init)
439 		return (ENXIO);
440 
441 	if (fmp->undef_op & UNDEF_SETATTR)
442 		return (ENOSYS);
443 
444 	fbuf = fb_setup(sizeof(*io), ip->ufs_ino.i_number, FBT_SETATTR, p);
445 	io = fbtod(fbuf, struct fb_io *);
446 	io->fi_flags = 0;
447 
448 	if (vap->va_uid != (uid_t)VNOVAL) {
449 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
450 			error = EROFS;
451 			goto out;
452 		}
453 		fbuf->fb_attr.st_uid = vap->va_uid;
454 		io->fi_flags |= FUSE_FATTR_UID;
455 	}
456 
457 	if (vap->va_gid != (gid_t)VNOVAL) {
458 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
459 			error = EROFS;
460 			goto out;
461 		}
462 		fbuf->fb_attr.st_gid = vap->va_gid;
463 		io->fi_flags |= FUSE_FATTR_GID;
464 	}
465 
466 	if (vap->va_size != VNOVAL) {
467 		switch (vp->v_type) {
468 		case VDIR:
469 			error = EISDIR;
470 			goto out;
471 		case VLNK:
472 		case VREG:
473 			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
474 				error = EROFS;
475 				goto out;
476 			}
477 			break;
478 		default:
479 			break;
480 		}
481 
482 		fbuf->fb_attr.st_size = vap->va_size;
483 		io->fi_flags |= FUSE_FATTR_SIZE;
484 	}
485 
486 	if (vap->va_atime.tv_nsec != VNOVAL) {
487 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
488 			error = EROFS;
489 			goto out;
490 		}
491 		fbuf->fb_attr.st_atim = vap->va_atime;
492 		io->fi_flags |= FUSE_FATTR_ATIME;
493 	}
494 
495 	if (vap->va_mtime.tv_nsec != VNOVAL) {
496 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
497 			error = EROFS;
498 			goto out;
499 		}
500 		fbuf->fb_attr.st_mtim = vap->va_mtime;
501 		io->fi_flags |= FUSE_FATTR_MTIME;
502 	}
503 	/* XXX should set a flag if (vap->va_vaflags & VA_UTIMES_CHANGE) */
504 
505 	if (vap->va_mode != (mode_t)VNOVAL) {
506 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
507 			error = EROFS;
508 			goto out;
509 		}
510 		fbuf->fb_attr.st_mode = vap->va_mode & ALLPERMS;
511 		io->fi_flags |= FUSE_FATTR_MODE;
512 	}
513 
514 	if (!io->fi_flags) {
515 		goto out;
516 	}
517 
518 	error = fb_queue(fmp->dev, fbuf);
519 	if (error) {
520 		if (error == ENOSYS)
521 			fmp->undef_op |= UNDEF_SETATTR;
522 		goto out;
523 	}
524 
525 	VN_KNOTE(ap->a_vp, NOTE_ATTRIB);
526 
527 out:
528 	fb_delete(fbuf);
529 	return (error);
530 }
531 
532 int
533 fusefs_ioctl(void *v)
534 {
535 	return (ENOTTY);
536 }
537 
538 int
539 fusefs_link(void *v)
540 {
541 	struct vop_link_args *ap = v;
542 	struct vnode *dvp = ap->a_dvp;
543 	struct vnode *vp = ap->a_vp;
544 	struct componentname *cnp = ap->a_cnp;
545 	struct proc *p = cnp->cn_proc;
546 	struct fusefs_mnt *fmp;
547 	struct fusefs_node *ip;
548 	struct fusefs_node *dip;
549 	struct fusebuf *fbuf;
550 	int error = 0;
551 
552 	ip = VTOI(vp);
553 	dip = VTOI(dvp);
554 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
555 
556 	if (!fmp->sess_init) {
557 		VOP_ABORTOP(dvp, cnp);
558 		error = ENXIO;
559 		goto out2;
560 	}
561 	if (fmp->undef_op & UNDEF_LINK) {
562 		VOP_ABORTOP(dvp, cnp);
563 		error = ENOSYS;
564 		goto out2;
565 	}
566 	if (vp->v_type == VDIR) {
567 		VOP_ABORTOP(dvp, cnp);
568 		error = EISDIR;
569 		goto out2;
570 	}
571 	if (dvp->v_mount != vp->v_mount) {
572 		VOP_ABORTOP(dvp, cnp);
573 		error = EXDEV;
574 		goto out2;
575 	}
576 	if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
577 		VOP_ABORTOP(dvp, cnp);
578 		goto out2;
579 	}
580 
581 	fbuf = fb_setup(cnp->cn_namelen + 1, dip->ufs_ino.i_number,
582 	    FBT_LINK, p);
583 
584 	fbuf->fb_io_ino = ip->ufs_ino.i_number;
585 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
586 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
587 
588 	error = fb_queue(fmp->dev, fbuf);
589 
590 	if (error) {
591 		if (error == ENOSYS)
592 			fmp->undef_op |= UNDEF_LINK;
593 
594 		fb_delete(fbuf);
595 		goto out1;
596 	}
597 
598 	fb_delete(fbuf);
599 	VN_KNOTE(vp, NOTE_LINK);
600 	VN_KNOTE(dvp, NOTE_WRITE);
601 
602 out1:
603 	if (dvp != vp)
604 		VOP_UNLOCK(vp, p);
605 out2:
606 	vput(dvp);
607 	return (error);
608 }
609 
610 int
611 fusefs_symlink(void *v)
612 {
613 	struct vop_symlink_args *ap = v;
614 	struct vnode **vpp = ap->a_vpp;
615 	struct componentname *cnp = ap->a_cnp;
616 	struct vnode *dvp = ap->a_dvp;
617 	struct proc *p = cnp->cn_proc;
618 	char *target = ap->a_target;
619 	struct fusefs_node *dp;
620 	struct fusefs_mnt *fmp;
621 	struct fusebuf *fbuf;
622 	struct vnode *tdp;
623 	int error = 0;
624 	int len;
625 
626 	dp = VTOI(dvp);
627 	fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump;
628 
629 	if (!fmp->sess_init) {
630 		error = ENXIO;
631 		goto bad;
632 	}
633 
634 	if (fmp->undef_op & UNDEF_SYMLINK) {
635 		error = ENOSYS;
636 		goto bad;
637 	}
638 
639 	len = strlen(target) + 1;
640 
641 	fbuf = fb_setup(len + cnp->cn_namelen + 1, dp->ufs_ino.i_number,
642 	    FBT_SYMLINK, p);
643 
644 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
645 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
646 	memcpy(&fbuf->fb_dat[cnp->cn_namelen + 1], target, len);
647 
648 	error = fb_queue(fmp->dev, fbuf);
649 	if (error) {
650 		if (error == ENOSYS)
651 			fmp->undef_op |= UNDEF_SYMLINK;
652 
653 		fb_delete(fbuf);
654 		goto bad;
655 	}
656 
657 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
658 		fb_delete(fbuf);
659 		goto bad;
660 	}
661 
662 	tdp->v_type = VLNK;
663 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
664 
665 	*vpp = tdp;
666 	fb_delete(fbuf);
667 	vput(tdp);
668 bad:
669 	vput(dvp);
670 	return (error);
671 }
672 
673 int
674 fusefs_readdir(void *v)
675 {
676 	struct vop_readdir_args *ap = v;
677 	struct fusefs_node *ip;
678 	struct fusefs_mnt *fmp;
679 	struct fusebuf *fbuf;
680 	struct vnode *vp;
681 	struct proc *p;
682 	struct uio *uio;
683 	int error = 0, eofflag = 0;
684 
685 	vp = ap->a_vp;
686 	uio = ap->a_uio;
687 	p = uio->uio_procp;
688 
689 	ip = VTOI(vp);
690 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
691 
692 	if (!fmp->sess_init)
693 		return (ENXIO);
694 
695 	if (uio->uio_resid < sizeof(struct dirent))
696 		return (EINVAL);
697 
698 	while (uio->uio_resid > 0) {
699 		fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READDIR, p);
700 
701 		if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) {
702 			/* TODO open the file */
703 			fb_delete(fbuf);
704 			return (error);
705 		}
706 		fbuf->fb_io_fd = ip->fufh[FUFH_RDONLY].fh_id;
707 		fbuf->fb_io_off = uio->uio_offset;
708 		fbuf->fb_io_len = MIN(uio->uio_resid, fmp->max_read);
709 
710 		error = fb_queue(fmp->dev, fbuf);
711 
712 		if (error) {
713 			fb_delete(fbuf);
714 			break;
715 		}
716 
717 		/* ack end of readdir */
718 		if (fbuf->fb_len == 0) {
719 			eofflag = 1;
720 			fb_delete(fbuf);
721 			break;
722 		}
723 
724 		if ((error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio))) {
725 			fb_delete(fbuf);
726 			break;
727 		}
728 
729 		fb_delete(fbuf);
730 	}
731 
732 	if (!error && ap->a_eofflag != NULL)
733 		*ap->a_eofflag = eofflag;
734 
735 	return (error);
736 }
737 
738 int
739 fusefs_inactive(void *v)
740 {
741 	struct vop_inactive_args *ap = v;
742 	struct vnode *vp = ap->a_vp;
743 	struct proc *p = ap->a_p;
744 	struct ucred *cred = p->p_ucred;
745 	struct fusefs_node *ip = VTOI(vp);
746 	struct fusefs_filehandle *fufh = NULL;
747 	struct fusefs_mnt *fmp;
748 	struct vattr vattr;
749 	int error = 0;
750 	int type;
751 
752 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
753 
754 	for (type = 0; type < FUFH_MAXTYPE; type++) {
755 		fufh = &(ip->fufh[type]);
756 		if (fufh->fh_type != FUFH_INVALID)
757 			fusefs_file_close(fmp, ip, fufh->fh_type, type,
758 			    (vp->v_type == VDIR), ap->a_p);
759 	}
760 
761 	error = VOP_GETATTR(vp, &vattr, cred, p);
762 
763 	VOP_UNLOCK(vp, p);
764 
765 	if (error)
766 		vrecycle(vp, p);
767 
768 	return (0);
769 }
770 
771 int
772 fusefs_readlink(void *v)
773 {
774 	struct vop_readlink_args *ap = v;
775 	struct vnode *vp = ap->a_vp;
776 	struct fusefs_node *ip;
777 	struct fusefs_mnt *fmp;
778 	struct fusebuf *fbuf;
779 	struct uio *uio;
780 	struct proc *p;
781 	int error = 0;
782 
783 	ip = VTOI(vp);
784 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
785 	uio = ap->a_uio;
786 	p = uio->uio_procp;
787 
788 	if (!fmp->sess_init)
789 		return (ENXIO);
790 
791 	if (fmp->undef_op & UNDEF_READLINK)
792 		return (ENOSYS);
793 
794 	fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READLINK, p);
795 
796 	error = fb_queue(fmp->dev, fbuf);
797 
798 	if (error) {
799 		if (error == ENOSYS)
800 			fmp->undef_op |= UNDEF_READLINK;
801 
802 		fb_delete(fbuf);
803 		return (error);
804 	}
805 
806 	error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio);
807 	fb_delete(fbuf);
808 
809 	return (error);
810 }
811 
812 int
813 fusefs_reclaim(void *v)
814 {
815 	struct vop_reclaim_args *ap = v;
816 	struct vnode *vp = ap->a_vp;
817 	struct fusefs_node *ip = VTOI(vp);
818 	struct fusefs_filehandle *fufh = NULL;
819 	struct fusefs_mnt *fmp;
820 	struct fusebuf *fbuf;
821 	int type;
822 
823 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
824 
825 	/*close opened files*/
826 	for (type = 0; type < FUFH_MAXTYPE; type++) {
827 		fufh = &(ip->fufh[type]);
828 		if (fufh->fh_type != FUFH_INVALID) {
829 			printf("fusefs: vnode being reclaimed is valid\n");
830 			fusefs_file_close(fmp, ip, fufh->fh_type, type,
831 			    (vp->v_type == VDIR), ap->a_p);
832 		}
833 	}
834 
835 	/*
836 	 * if the fuse connection is opened
837 	 * ask libfuse to free the vnodes
838 	 */
839 	if (fmp->sess_init && ip->ufs_ino.i_number != FUSE_ROOTINO) {
840 		fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_RECLAIM, ap->a_p);
841 		if (fb_queue(fmp->dev, fbuf))
842 			printf("fusefs: libfuse vnode reclaim failed\n");
843 		fb_delete(fbuf);
844 	}
845 
846 	/*
847 	 * Remove the inode from its hash chain.
848 	 */
849 	ufs_ihashrem(&ip->ufs_ino);
850 
851 	free(ip, M_FUSEFS, 0);
852 	vp->v_data = NULL;
853 	return (0);
854 }
855 
856 int
857 fusefs_print(void *v)
858 {
859 	struct vop_print_args *ap = v;
860 	struct vnode *vp = ap->a_vp;
861 	struct fusefs_node *ip = VTOI(vp);
862 
863 	/* Complete the information given by vprint(). */
864 	printf("tag VT_FUSE, hash id %u ", ip->ufs_ino.i_number);
865 	printf("\n");
866 	return (0);
867 }
868 
869 int
870 fusefs_create(void *v)
871 {
872 	struct vop_create_args *ap = v;
873 	struct componentname *cnp = ap->a_cnp;
874 	struct vnode **vpp = ap->a_vpp;
875 	struct vnode *dvp = ap->a_dvp;
876 	struct vattr *vap = ap->a_vap;
877 	struct proc *p = cnp->cn_proc;
878 	struct vnode *tdp = NULL;
879 	struct fusefs_mnt *fmp;
880 	struct fusefs_node *ip;
881 	struct fusebuf *fbuf;
882 	int error = 0;
883 	mode_t mode;
884 
885 	ip = VTOI(dvp);
886 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
887 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
888 
889 	if (!fmp->sess_init) {
890 		error = ENXIO;
891 		goto out;
892 	}
893 
894 	if (fmp->undef_op & UNDEF_CREATE) {
895 		error = ENOSYS;
896 		goto out;
897 	}
898 
899 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
900 	    FBT_CREATE, p);
901 
902 	fbuf->fb_io_mode = mode;
903 	fbuf->fb_io_flags = O_CREAT | O_RDWR;
904 
905 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
906 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
907 
908 	error = fb_queue(fmp->dev, fbuf);
909 	if (error) {
910 		if (error == ENOSYS)
911 			fmp->undef_op |= UNDEF_CREATE;
912 
913 		fb_delete(fbuf);
914 		goto out;
915 	}
916 
917 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
918 		fb_delete(fbuf);
919 		goto out;
920 	}
921 
922 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
923 
924 	*vpp = tdp;
925 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
926 	fb_delete(fbuf);
927 out:
928 	vput(ap->a_dvp);
929 	return (error);
930 }
931 
932 int
933 fusefs_mknod(void *v)
934 {
935 	struct vop_mknod_args *ap = v;
936 	struct componentname *cnp = ap->a_cnp;
937 	struct vnode **vpp = ap->a_vpp;
938 	struct vnode *dvp = ap->a_dvp;
939 	struct vattr *vap = ap->a_vap;
940 	struct proc *p = cnp->cn_proc;
941 	struct vnode *tdp = NULL;
942 	struct fusefs_mnt *fmp;
943 	struct fusefs_node *ip;
944 	struct fusebuf *fbuf;
945 	int error = 0;
946 
947 	ip = VTOI(dvp);
948 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
949 
950 	if (!fmp->sess_init) {
951 		error = ENXIO;
952 		goto out;
953 	}
954 
955 	if (fmp->undef_op & UNDEF_MKNOD) {
956 		error = ENOSYS;
957 		goto out;
958 	}
959 
960 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
961 	    FBT_MKNOD, p);
962 
963 	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
964 	if (vap->va_rdev != VNOVAL)
965 		fbuf->fb_io_rdev = vap->va_rdev;
966 
967 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
968 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
969 
970 	error = fb_queue(fmp->dev, fbuf);
971 	if (error) {
972 		if (error == ENOSYS)
973 			fmp->undef_op |= UNDEF_MKNOD;
974 
975 		fb_delete(fbuf);
976 		goto out;
977 	}
978 
979 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
980 		fb_delete(fbuf);
981 		goto out;
982 	}
983 
984 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
985 
986 	*vpp = tdp;
987 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
988 	fb_delete(fbuf);
989 	vput(ap->a_dvp);
990 
991 	/* Remove inode so that it will be reloaded by VFS_VGET and
992 	 * checked to see if it is an alias of an existing entry in
993 	 * the inode cache.
994 	 */
995 	vput(*vpp);
996 	(*vpp)->v_type = VNON;
997 	vgone(*vpp);
998 	*vpp = NULL;
999 	return (0);
1000 out:
1001 	vput(ap->a_dvp);
1002 	return (error);
1003 }
1004 
1005 int
1006 fusefs_read(void *v)
1007 {
1008 	struct vop_read_args *ap = v;
1009 	struct vnode *vp = ap->a_vp;
1010 	struct uio *uio = ap->a_uio;
1011 	struct proc *p = uio->uio_procp;
1012 	struct fusefs_node *ip;
1013 	struct fusefs_mnt *fmp;
1014 	struct fusebuf *fbuf = NULL;
1015 	size_t size;
1016 	int error=0;
1017 
1018 	ip = VTOI(vp);
1019 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1020 
1021 	if (!fmp->sess_init)
1022 		return (ENXIO);
1023 	if (uio->uio_resid == 0)
1024 		return (error);
1025 	if (uio->uio_offset < 0)
1026 		return (EINVAL);
1027 
1028 	while (uio->uio_resid > 0) {
1029 		fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READ, p);
1030 
1031 		size = MIN(uio->uio_resid, fmp->max_read);
1032 		fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_RDONLY);
1033 		fbuf->fb_io_off = uio->uio_offset;
1034 		fbuf->fb_io_len = size;
1035 
1036 		error = fb_queue(fmp->dev, fbuf);
1037 
1038 		if (error)
1039 			break;
1040 
1041 		error = uiomove(fbuf->fb_dat, ulmin(size, fbuf->fb_len), uio);
1042 		if (error)
1043 			break;
1044 
1045 		if (fbuf->fb_len < size)
1046 			break;
1047 
1048 		fb_delete(fbuf);
1049 		fbuf = NULL;
1050 	}
1051 
1052 	fb_delete(fbuf);
1053 	return (error);
1054 }
1055 
1056 int
1057 fusefs_write(void *v)
1058 {
1059 	struct vop_write_args *ap = v;
1060 	struct vnode *vp = ap->a_vp;
1061 	struct uio *uio = ap->a_uio;
1062 	struct proc *p = uio->uio_procp;
1063 	struct ucred *cred = p->p_ucred;
1064 	struct vattr vattr;
1065 	int ioflag = ap->a_ioflag;
1066 	struct fusefs_node *ip;
1067 	struct fusefs_mnt *fmp;
1068 	struct fusebuf *fbuf = NULL;
1069 	size_t len, diff;
1070 	int error=0;
1071 
1072 	ip = VTOI(vp);
1073 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1074 
1075 	if (!fmp->sess_init)
1076 		return (ENXIO);
1077 	if (uio->uio_resid == 0)
1078 		return (error);
1079 
1080 	if (ioflag & IO_APPEND) {
1081 		if ((error = VOP_GETATTR(vp, &vattr, cred, p)) != 0)
1082 			return (error);
1083 
1084 		uio->uio_offset = vattr.va_size;
1085 	}
1086 
1087 	while (uio->uio_resid > 0) {
1088 		len = MIN(uio->uio_resid, fmp->max_read);
1089 		fbuf = fb_setup(len, ip->ufs_ino.i_number, FBT_WRITE, p);
1090 
1091 		fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_WRONLY);
1092 		fbuf->fb_io_off = uio->uio_offset;
1093 		fbuf->fb_io_len = len;
1094 
1095 		if ((error = uiomove(fbuf->fb_dat, len, uio))) {
1096 			printf("fusefs: uio error %i\n", error);
1097 			break;
1098 		}
1099 
1100 		error = fb_queue(fmp->dev, fbuf);
1101 
1102 		if (error)
1103 			break;
1104 
1105 		diff = len - fbuf->fb_io_len;
1106 		if (fbuf->fb_io_len > len) {
1107 			error = EINVAL;
1108 			break;
1109 		}
1110 
1111 		uio->uio_resid += diff;
1112 		uio->uio_offset -= diff;
1113 
1114 		fb_delete(fbuf);
1115 		fbuf = NULL;
1116 	}
1117 
1118 	fb_delete(fbuf);
1119 	return (error);
1120 }
1121 
1122 int
1123 fusefs_poll(void *v)
1124 {
1125 	struct vop_poll_args *ap = v;
1126 
1127 	/*
1128 	 * We should really check to see if I/O is possible.
1129 	 */
1130 	return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
1131 }
1132 
1133 int
1134 fusefs_rename(void *v)
1135 {
1136 	struct vop_rename_args *ap = v;
1137 	struct vnode *tvp = ap->a_tvp;
1138 	struct vnode *tdvp = ap->a_tdvp;
1139 	struct vnode *fvp = ap->a_fvp;
1140 	struct vnode *fdvp = ap->a_fdvp;
1141 	struct componentname *tcnp = ap->a_tcnp;
1142 	struct componentname *fcnp = ap->a_fcnp;
1143 	struct proc *p = fcnp->cn_proc;
1144 	struct fusefs_node *ip, *dp;
1145 	struct fusefs_mnt *fmp;
1146 	struct fusebuf *fbuf;
1147 	int error = 0;
1148 
1149 #ifdef DIAGNOSTIC
1150 	if ((tcnp->cn_flags & HASBUF) == 0 ||
1151 	    (fcnp->cn_flags & HASBUF) == 0)
1152 		panic("fusefs_rename: no name");
1153 #endif
1154 	/*
1155 	 * Check for cross-device rename.
1156 	 */
1157 	if ((fvp->v_mount != tdvp->v_mount) ||
1158 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
1159 		error = EXDEV;
1160 abortit:
1161 		VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1162 		if (tdvp == tvp)
1163 			vrele(tdvp);
1164 		else
1165 			vput(tdvp);
1166 		if (tvp)
1167 			vput(tvp);
1168 		VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1169 		vrele(fdvp);
1170 		vrele(fvp);
1171 		return (error);
1172 	}
1173 
1174 	/*
1175 	 * If source and dest are the same, do nothing.
1176 	 */
1177 	if (tvp == fvp) {
1178 		error = 0;
1179 		goto abortit;
1180 	}
1181 
1182 	if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
1183 		goto abortit;
1184 	dp = VTOI(fdvp);
1185 	ip = VTOI(fvp);
1186 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1187 
1188 	/*
1189 	 * Be sure we are not renaming ".", "..", or an alias of ".". This
1190 	 * leads to a crippled directory tree.  It's pretty tough to do a
1191 	 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
1192 	 * doesn't work if the ".." entry is missing.
1193 	 */
1194 	if (fvp->v_type == VDIR) {
1195 		/*
1196 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
1197 		 */
1198 		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1199 		    dp == ip ||
1200 		    (fcnp->cn_flags & ISDOTDOT) ||
1201 		    (tcnp->cn_flags & ISDOTDOT)) {
1202 			VOP_UNLOCK(fvp, p);
1203 			error = EINVAL;
1204 			goto abortit;
1205 		}
1206 	}
1207 	VN_KNOTE(fdvp, NOTE_WRITE);	/* XXX right place? */
1208 
1209 	if (!fmp->sess_init) {
1210 		error = ENXIO;
1211 		VOP_UNLOCK(fvp, p);
1212 		goto abortit;
1213 	}
1214 
1215 	if (fmp->undef_op & UNDEF_RENAME) {
1216 		error = ENOSYS;
1217 		VOP_UNLOCK(fvp, p);
1218 		goto abortit;
1219 	}
1220 
1221 	fbuf = fb_setup(fcnp->cn_namelen + tcnp->cn_namelen + 2,
1222 	    dp->ufs_ino.i_number, FBT_RENAME, p);
1223 
1224 	memcpy(fbuf->fb_dat, fcnp->cn_nameptr, fcnp->cn_namelen);
1225 	fbuf->fb_dat[fcnp->cn_namelen] = '\0';
1226 	memcpy(fbuf->fb_dat + fcnp->cn_namelen + 1, tcnp->cn_nameptr,
1227 	    tcnp->cn_namelen);
1228 	fbuf->fb_dat[fcnp->cn_namelen + tcnp->cn_namelen + 1] = '\0';
1229 	fbuf->fb_io_ino = VTOI(tdvp)->ufs_ino.i_number;
1230 
1231 	error = fb_queue(fmp->dev, fbuf);
1232 
1233 	if (error) {
1234 		if (error == ENOSYS) {
1235 			fmp->undef_op |= UNDEF_RENAME;
1236 		}
1237 
1238 		fb_delete(fbuf);
1239 		VOP_UNLOCK(fvp, p);
1240 		goto abortit;
1241 	}
1242 
1243 	fb_delete(fbuf);
1244 	VN_KNOTE(fvp, NOTE_RENAME);
1245 
1246 	VOP_UNLOCK(fvp, p);
1247 	if (tdvp == tvp)
1248 		vrele(tdvp);
1249 	else
1250 		vput(tdvp);
1251 	vrele(fdvp);
1252 	vrele(fvp);
1253 
1254 	return (error);
1255 }
1256 
1257 int
1258 fusefs_mkdir(void *v)
1259 {
1260 	struct vop_mkdir_args *ap = v;
1261 	struct vnode *dvp = ap->a_dvp;
1262 	struct vnode **vpp = ap->a_vpp;
1263 	struct componentname *cnp = ap->a_cnp;
1264 	struct vattr *vap = ap->a_vap;
1265 	struct proc *p = cnp->cn_proc;
1266 	struct vnode *tdp = NULL;
1267 	struct fusefs_node *ip;
1268 	struct fusefs_mnt *fmp;
1269 	struct fusebuf *fbuf;
1270 	int error = 0;
1271 
1272 	ip = VTOI(dvp);
1273 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1274 
1275 
1276 	if (!fmp->sess_init) {
1277 		error = ENXIO;
1278 		goto out;
1279 	}
1280 
1281 	if (fmp->undef_op & UNDEF_MKDIR) {
1282 		error = ENOSYS;
1283 		goto out;
1284 	}
1285 
1286 	fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
1287 	    FBT_MKDIR, p);
1288 
1289 	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1290 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1291 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1292 
1293 	error = fb_queue(fmp->dev, fbuf);
1294 	if (error) {
1295 		if (error == ENOSYS)
1296 			fmp->undef_op |= UNDEF_MKDIR;
1297 
1298 		fb_delete(fbuf);
1299 		goto out;
1300 	}
1301 
1302 	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
1303 		fb_delete(fbuf);
1304 		goto out;
1305 	}
1306 
1307 	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
1308 
1309 	*vpp = tdp;
1310 	VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
1311 	fb_delete(fbuf);
1312 out:
1313 	vput(dvp);
1314 	return (error);
1315 }
1316 
1317 int
1318 fusefs_rmdir(void *v)
1319 {
1320 	struct vop_rmdir_args *ap = v;
1321 	struct vnode *vp = ap->a_vp;
1322 	struct vnode *dvp = ap->a_dvp;
1323 	struct componentname *cnp = ap->a_cnp;
1324 	struct proc *p = cnp->cn_proc;
1325 	struct fusefs_node *ip, *dp;
1326 	struct fusefs_mnt *fmp;
1327 	struct fusebuf *fbuf;
1328 	int error;
1329 
1330 	ip = VTOI(vp);
1331 	dp = VTOI(dvp);
1332 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1333 
1334 	if (!fmp->sess_init) {
1335 		error = ENXIO;
1336 		goto out;
1337 	}
1338 
1339 	if (fmp->undef_op & UNDEF_RMDIR) {
1340 		error = ENOSYS;
1341 		goto out;
1342 	}
1343 
1344 	/*
1345 	 * No rmdir "." please.
1346 	 */
1347 	if (dp == ip) {
1348 		vrele(dvp);
1349 		vput(vp);
1350 		return (EINVAL);
1351 	}
1352 
1353 	VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1354 
1355 	fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number,
1356 	    FBT_RMDIR, p);
1357 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1358 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1359 
1360 	error = fb_queue(fmp->dev, fbuf);
1361 
1362 	if (error) {
1363 		if (error == ENOSYS)
1364 			fmp->undef_op |= UNDEF_RMDIR;
1365 		if (error != ENOTEMPTY)
1366 			VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1367 
1368 		fb_delete(fbuf);
1369 		goto out;
1370 	}
1371 
1372 	vput(dvp);
1373 	dvp = NULL;
1374 
1375 	fb_delete(fbuf);
1376 out:
1377 	if (dvp)
1378 		vput(dvp);
1379 	VN_KNOTE(vp, NOTE_DELETE);
1380 	vput(vp);
1381 	return (error);
1382 }
1383 
1384 int
1385 fusefs_remove(void *v)
1386 {
1387 	struct vop_remove_args *ap = v;
1388 	struct vnode *vp = ap->a_vp;
1389 	struct vnode *dvp = ap->a_dvp;
1390 	struct componentname *cnp = ap->a_cnp;
1391 	struct proc *p = cnp->cn_proc;
1392 	struct fusefs_node *ip;
1393 	struct fusefs_node *dp;
1394 	struct fusefs_mnt *fmp;
1395 	struct fusebuf *fbuf;
1396 	int error = 0;
1397 
1398 	ip = VTOI(vp);
1399 	dp = VTOI(dvp);
1400 	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
1401 
1402 	if (!fmp->sess_init) {
1403 		error = ENXIO;
1404 		goto out;
1405 	}
1406 
1407 	if (fmp->undef_op & UNDEF_REMOVE) {
1408 		error = ENOSYS;
1409 		goto out;
1410 	}
1411 
1412 	fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number,
1413 	    FBT_UNLINK, p);
1414 	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
1415 	fbuf->fb_dat[cnp->cn_namelen] = '\0';
1416 
1417 	error = fb_queue(fmp->dev, fbuf);
1418 	if (error) {
1419 		if (error == ENOSYS)
1420 			fmp->undef_op |= UNDEF_REMOVE;
1421 
1422 		fb_delete(fbuf);
1423 		goto out;
1424 	}
1425 
1426 	VN_KNOTE(vp, NOTE_DELETE);
1427 	VN_KNOTE(dvp, NOTE_WRITE);
1428 	fb_delete(fbuf);
1429 out:
1430 	if (dvp == vp)
1431 		vrele(vp);
1432 	else
1433 		vput(vp);
1434 	vput(dvp);
1435 	return (error);
1436 }
1437 
1438 int
1439 fusefs_strategy(void *v)
1440 {
1441 	return (0);
1442 }
1443 
1444 int
1445 fusefs_lock(void *v)
1446 {
1447 	struct vop_lock_args *ap = v;
1448 	struct vnode *vp = ap->a_vp;
1449 
1450 	return rrw_enter(&VTOI(vp)->ufs_ino.i_lock, ap->a_flags & LK_RWFLAGS);
1451 }
1452 
1453 int
1454 fusefs_unlock(void *v)
1455 {
1456 	struct vop_unlock_args *ap = v;
1457 	struct vnode *vp = ap->a_vp;
1458 
1459 	rrw_exit(&VTOI(vp)->ufs_ino.i_lock);
1460 	return 0;
1461 }
1462 
1463 int
1464 fusefs_islocked(void *v)
1465 {
1466 	struct vop_islocked_args *ap = v;
1467 
1468 	return rrw_status(&VTOI(ap->a_vp)->ufs_ino.i_lock);
1469 }
1470 
1471 int
1472 fusefs_advlock(void *v)
1473 {
1474 	struct vop_advlock_args *ap = v;
1475 	struct fusefs_node *ip = VTOI(ap->a_vp);
1476 
1477 	return (lf_advlock(&ip->ufs_ino.i_lockf, ip->filesize, ap->a_id,
1478 	    ap->a_op, ap->a_fl, ap->a_flags));
1479 }
1480