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