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