| 1 |
/*- |
| 2 |
* SPDX-License-Identifier: BSD-3-Clause |
| 3 |
* |
| 4 |
* Copyright (c) 2007-2009 Google Inc. and Amit Singh |
| 5 |
* All rights reserved. |
| 6 |
* |
| 7 |
* Redistribution and use in source and binary forms, with or without |
| 8 |
* modification, are permitted provided that the following conditions are |
| 9 |
* met: |
| 10 |
* |
| 11 |
* * Redistributions of source code must retain the above copyright |
| 12 |
* notice, this list of conditions and the following disclaimer. |
| 13 |
* * Redistributions in binary form must reproduce the above |
| 14 |
* copyright notice, this list of conditions and the following disclaimer |
| 15 |
* in the documentation and/or other materials provided with the |
| 16 |
* distribution. |
| 17 |
* * Neither the name of Google Inc. nor the names of its |
| 18 |
* contributors may be used to endorse or promote products derived from |
| 19 |
* this software without specific prior written permission. |
| 20 |
* |
| 21 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 22 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 23 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 24 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 25 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 26 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 27 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 28 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 29 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 30 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 31 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 32 |
* |
| 33 |
* Copyright (C) 2005 Csaba Henk. |
| 34 |
* All rights reserved. |
| 35 |
* |
| 36 |
* Redistribution and use in source and binary forms, with or without |
| 37 |
* modification, are permitted provided that the following conditions |
| 38 |
* are met: |
| 39 |
* 1. Redistributions of source code must retain the above copyright |
| 40 |
* notice, this list of conditions and the following disclaimer. |
| 41 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 42 |
* notice, this list of conditions and the following disclaimer in the |
| 43 |
* documentation and/or other materials provided with the distribution. |
| 44 |
* |
| 45 |
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 46 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 47 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 48 |
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
| 49 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 50 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 51 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 52 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 53 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 54 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 55 |
* SUCH DAMAGE. |
| 56 |
*/ |
| 57 |
|
| 58 |
#include <sys/cdefs.h> |
| 59 |
__FBSDID("$FreeBSD$"); |
| 60 |
|
| 61 |
#include <sys/types.h> |
| 62 |
#include <sys/module.h> |
| 63 |
#include <sys/systm.h> |
| 64 |
#include <sys/errno.h> |
| 65 |
#include <sys/param.h> |
| 66 |
#include <sys/kernel.h> |
| 67 |
#include <sys/conf.h> |
| 68 |
#include <sys/uio.h> |
| 69 |
#include <sys/malloc.h> |
| 70 |
#include <sys/queue.h> |
| 71 |
#include <sys/lock.h> |
| 72 |
#include <sys/mutex.h> |
| 73 |
#include <sys/sx.h> |
| 74 |
#include <sys/proc.h> |
| 75 |
#include <sys/mount.h> |
| 76 |
#include <sys/vnode.h> |
| 77 |
#include <sys/namei.h> |
| 78 |
#include <sys/stat.h> |
| 79 |
#include <sys/unistd.h> |
| 80 |
#include <sys/filedesc.h> |
| 81 |
#include <sys/file.h> |
| 82 |
#include <sys/fcntl.h> |
| 83 |
#include <sys/dirent.h> |
| 84 |
#include <sys/bio.h> |
| 85 |
#include <sys/buf.h> |
| 86 |
#include <sys/sysctl.h> |
| 87 |
#include <sys/priv.h> |
| 88 |
|
| 89 |
#include "fuse.h" |
| 90 |
#include "fuse_file.h" |
| 91 |
#include "fuse_internal.h" |
| 92 |
#include "fuse_ipc.h" |
| 93 |
#include "fuse_node.h" |
| 94 |
#include "fuse_file.h" |
| 95 |
#include "fuse_param.h" |
| 96 |
|
| 97 |
#define FUSE_DEBUG_MODULE INTERNAL |
| 98 |
#include "fuse_debug.h" |
| 99 |
|
| 100 |
#ifdef ZERO_PAD_INCOMPLETE_BUFS |
| 101 |
static int isbzero(void *buf, size_t len); |
| 102 |
|
| 103 |
#endif |
| 104 |
|
| 105 |
/* access */ |
| 106 |
|
| 107 |
int |
| 108 |
fuse_internal_access(struct vnode *vp, |
| 109 |
mode_t mode, |
| 110 |
struct fuse_access_param *facp, |
| 111 |
struct thread *td, |
| 112 |
struct ucred *cred) |
| 113 |
{ |
| 114 |
int err = 0; |
| 115 |
uint32_t mask = 0; |
| 116 |
int dataflags; |
| 117 |
int vtype; |
| 118 |
struct mount *mp; |
| 119 |
struct fuse_dispatcher fdi; |
| 120 |
struct fuse_access_in *fai; |
| 121 |
struct fuse_data *data; |
| 122 |
|
| 123 |
/* NOT YET DONE */ |
| 124 |
/* |
| 125 |
* If this vnop gives you trouble, just return 0 here for a lazy |
| 126 |
* kludge. |
| 127 |
*/ |
| 128 |
/* return 0;*/ |
| 129 |
|
| 130 |
fuse_trace_printf_func(); |
| 131 |
|
| 132 |
mp = vnode_mount(vp); |
| 133 |
vtype = vnode_vtype(vp); |
| 134 |
|
| 135 |
data = fuse_get_mpdata(mp); |
| 136 |
dataflags = data->dataflags; |
| 137 |
|
| 138 |
if ((mode & VWRITE) && vfs_isrdonly(mp)) { |
| 139 |
return EACCES; |
| 140 |
} |
| 141 |
/* Unless explicitly permitted, deny everyone except the fs owner. */ |
| 142 |
if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { |
| 143 |
if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { |
| 144 |
int denied = fuse_match_cred(data->daemoncred, |
| 145 |
cred); |
| 146 |
|
| 147 |
if (denied) { |
| 148 |
return EPERM; |
| 149 |
} |
| 150 |
} |
| 151 |
facp->facc_flags |= FACCESS_NOCHECKSPY; |
| 152 |
} |
| 153 |
if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { |
| 154 |
return 0; |
| 155 |
} |
| 156 |
if (((vtype == VREG) && (mode & VEXEC))) { |
| 157 |
#ifdef NEED_MOUNT_ARGUMENT_FOR_THIS |
| 158 |
/* Let the kernel handle this through open / close heuristics.*/ |
| 159 |
return ENOTSUP; |
| 160 |
#else |
| 161 |
/* Let the kernel handle this. */ |
| 162 |
return 0; |
| 163 |
#endif |
| 164 |
} |
| 165 |
if (!fsess_isimpl(mp, FUSE_ACCESS)) { |
| 166 |
/* Let the kernel handle this. */ |
| 167 |
return 0; |
| 168 |
} |
| 169 |
if (dataflags & FSESS_DEFAULT_PERMISSIONS) { |
| 170 |
/* Let the kernel handle this. */ |
| 171 |
return 0; |
| 172 |
} |
| 173 |
if ((mode & VADMIN) != 0) { |
| 174 |
err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); |
| 175 |
if (err) { |
| 176 |
return err; |
| 177 |
} |
| 178 |
} |
| 179 |
if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) { |
| 180 |
mask |= W_OK; |
| 181 |
} |
| 182 |
if ((mode & VREAD) != 0) { |
| 183 |
mask |= R_OK; |
| 184 |
} |
| 185 |
if ((mode & VEXEC) != 0) { |
| 186 |
mask |= X_OK; |
| 187 |
} |
| 188 |
bzero(&fdi, sizeof(fdi)); |
| 189 |
|
| 190 |
fdisp_init(&fdi, sizeof(*fai)); |
| 191 |
fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); |
| 192 |
|
| 193 |
fai = fdi.indata; |
| 194 |
fai->mask = F_OK; |
| 195 |
fai->mask |= mask; |
| 196 |
|
| 197 |
err = fdisp_wait_answ(&fdi); |
| 198 |
fdisp_destroy(&fdi); |
| 199 |
|
| 200 |
if (err == ENOSYS) { |
| 201 |
fsess_set_notimpl(mp, FUSE_ACCESS); |
| 202 |
err = 0; |
| 203 |
} |
| 204 |
return err; |
| 205 |
} |
| 206 |
|
| 207 |
/* fsync */ |
| 208 |
|
| 209 |
int |
| 210 |
fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio) |
| 211 |
{ |
| 212 |
fuse_trace_printf_func(); |
| 213 |
|
| 214 |
if (tick->tk_aw_ohead.error == ENOSYS) { |
| 215 |
fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick)); |
| 216 |
} |
| 217 |
return 0; |
| 218 |
} |
| 219 |
|
| 220 |
int |
| 221 |
fuse_internal_fsync(struct vnode *vp, |
| 222 |
struct thread *td, |
| 223 |
struct ucred *cred, |
| 224 |
struct fuse_filehandle *fufh) |
| 225 |
{ |
| 226 |
int op = FUSE_FSYNC; |
| 227 |
struct fuse_fsync_in *ffsi; |
| 228 |
struct fuse_dispatcher fdi; |
| 229 |
|
| 230 |
fuse_trace_printf_func(); |
| 231 |
|
| 232 |
if (vnode_isdir(vp)) { |
| 233 |
op = FUSE_FSYNCDIR; |
| 234 |
} |
| 235 |
fdisp_init(&fdi, sizeof(*ffsi)); |
| 236 |
fdisp_make_vp(&fdi, op, vp, td, cred); |
| 237 |
ffsi = fdi.indata; |
| 238 |
ffsi->fh = fufh->fh_id; |
| 239 |
|
| 240 |
ffsi->fsync_flags = 1; /* datasync */ |
| 241 |
|
| 242 |
fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback); |
| 243 |
fuse_insert_message(fdi.tick); |
| 244 |
|
| 245 |
fdisp_destroy(&fdi); |
| 246 |
|
| 247 |
return 0; |
| 248 |
|
| 249 |
} |
| 250 |
|
| 251 |
/* readdir */ |
| 252 |
|
| 253 |
int |
| 254 |
fuse_internal_readdir(struct vnode *vp, |
| 255 |
struct uio *uio, |
| 256 |
struct fuse_filehandle *fufh, |
| 257 |
struct fuse_iov *cookediov) |
| 258 |
{ |
| 259 |
int err = 0; |
| 260 |
struct fuse_dispatcher fdi; |
| 261 |
struct fuse_read_in *fri; |
| 262 |
|
| 263 |
if (uio_resid(uio) == 0) { |
| 264 |
return 0; |
| 265 |
} |
| 266 |
fdisp_init(&fdi, 0); |
| 267 |
|
| 268 |
/* |
| 269 |
* Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p |
| 270 |
* I/O). |
| 271 |
*/ |
| 272 |
|
| 273 |
while (uio_resid(uio) > 0) { |
| 274 |
|
| 275 |
fdi.iosize = sizeof(*fri); |
| 276 |
fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); |
| 277 |
|
| 278 |
fri = fdi.indata; |
| 279 |
fri->fh = fufh->fh_id; |
| 280 |
fri->offset = uio_offset(uio); |
| 281 |
fri->size = min(uio_resid(uio), FUSE_DEFAULT_IOSIZE); |
| 282 |
/* mp->max_read */ |
| 283 |
|
| 284 |
if ((err = fdisp_wait_answ(&fdi))) { |
| 285 |
break; |
| 286 |
} |
| 287 |
if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ, |
| 288 |
fdi.iosize, cookediov))) { |
| 289 |
break; |
| 290 |
} |
| 291 |
} |
| 292 |
|
| 293 |
fdisp_destroy(&fdi); |
| 294 |
return ((err == -1) ? 0 : err); |
| 295 |
} |
| 296 |
|
| 297 |
int |
| 298 |
fuse_internal_readdir_processdata(struct uio *uio, |
| 299 |
size_t reqsize, |
| 300 |
void *buf, |
| 301 |
size_t bufsize, |
| 302 |
void *param) |
| 303 |
{ |
| 304 |
int err = 0; |
| 305 |
int cou = 0; |
| 306 |
int bytesavail; |
| 307 |
size_t freclen; |
| 308 |
|
| 309 |
struct dirent *de; |
| 310 |
struct fuse_dirent *fudge; |
| 311 |
struct fuse_iov *cookediov = param; |
| 312 |
|
| 313 |
if (bufsize < FUSE_NAME_OFFSET) { |
| 314 |
return -1; |
| 315 |
} |
| 316 |
for (;;) { |
| 317 |
|
| 318 |
if (bufsize < FUSE_NAME_OFFSET) { |
| 319 |
err = -1; |
| 320 |
break; |
| 321 |
} |
| 322 |
fudge = (struct fuse_dirent *)buf; |
| 323 |
freclen = FUSE_DIRENT_SIZE(fudge); |
| 324 |
|
| 325 |
cou++; |
| 326 |
|
| 327 |
if (bufsize < freclen) { |
| 328 |
err = ((cou == 1) ? -1 : 0); |
| 329 |
break; |
| 330 |
} |
| 331 |
#ifdef ZERO_PAD_INCOMPLETE_BUFS |
| 332 |
if (isbzero(buf, FUSE_NAME_OFFSET)) { |
| 333 |
err = -1; |
| 334 |
break; |
| 335 |
} |
| 336 |
#endif |
| 337 |
|
| 338 |
if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { |
| 339 |
err = EINVAL; |
| 340 |
break; |
| 341 |
} |
| 342 |
bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) |
| 343 |
&fudge->namelen); |
| 344 |
|
| 345 |
if (bytesavail > uio_resid(uio)) { |
| 346 |
err = -1; |
| 347 |
break; |
| 348 |
} |
| 349 |
fiov_refresh(cookediov); |
| 350 |
fiov_adjust(cookediov, bytesavail); |
| 351 |
|
| 352 |
de = (struct dirent *)cookediov->base; |
| 353 |
de->d_fileno = fudge->ino; /* XXX: truncation */ |
| 354 |
de->d_reclen = bytesavail; |
| 355 |
de->d_type = fudge->type; |
| 356 |
de->d_namlen = fudge->namelen; |
| 357 |
memcpy((char *)cookediov->base + sizeof(struct dirent) - |
| 358 |
MAXNAMLEN - 1, |
| 359 |
(char *)buf + FUSE_NAME_OFFSET, fudge->namelen); |
| 360 |
((char *)cookediov->base)[bytesavail - 1] = '\0'; |
| 361 |
|
| 362 |
err = uiomove(cookediov->base, cookediov->len, uio); |
| 363 |
if (err) { |
| 364 |
break; |
| 365 |
} |
| 366 |
buf = (char *)buf + freclen; |
| 367 |
bufsize -= freclen; |
| 368 |
uio_setoffset(uio, fudge->off); |
| 369 |
} |
| 370 |
|
| 371 |
return err; |
| 372 |
} |
| 373 |
|
| 374 |
/* remove */ |
| 375 |
|
| 376 |
#define INVALIDATE_CACHED_VATTRS_UPON_UNLINK 1 |
| 377 |
int |
| 378 |
fuse_internal_remove(struct vnode *dvp, |
| 379 |
struct vnode *vp, |
| 380 |
struct componentname *cnp, |
| 381 |
enum fuse_opcode op) |
| 382 |
{ |
| 383 |
struct fuse_dispatcher fdi; |
| 384 |
|
| 385 |
struct vattr *vap = VTOVA(vp); |
| 386 |
|
| 387 |
#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK |
| 388 |
int need_invalidate = 0; |
| 389 |
uint64_t target_nlink = 0; |
| 390 |
|
| 391 |
#endif |
| 392 |
int err = 0; |
| 393 |
|
| 394 |
debug_printf("dvp=%p, cnp=%p, op=%d\n", vp, cnp, op); |
| 395 |
|
| 396 |
fdisp_init(&fdi, cnp->cn_namelen + 1); |
| 397 |
fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred); |
| 398 |
|
| 399 |
memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); |
| 400 |
((char *)fdi.indata)[cnp->cn_namelen] = '\0'; |
| 401 |
|
| 402 |
#if INVALIDATE_CACHED_VATTRS_UPON_UNLINK |
| 403 |
if (vap->va_nlink > 1) { |
| 404 |
need_invalidate = 1; |
| 405 |
target_nlink = vap->va_nlink; |
| 406 |
} |
| 407 |
#endif |
| 408 |
|
| 409 |
err = fdisp_wait_answ(&fdi); |
| 410 |
fdisp_destroy(&fdi); |
| 411 |
return err; |
| 412 |
} |
| 413 |
|
| 414 |
/* rename */ |
| 415 |
|
| 416 |
int |
| 417 |
fuse_internal_rename(struct vnode *fdvp, |
| 418 |
struct componentname *fcnp, |
| 419 |
struct vnode *tdvp, |
| 420 |
struct componentname *tcnp) |
| 421 |
{ |
| 422 |
struct fuse_dispatcher fdi; |
| 423 |
struct fuse_rename_in *fri; |
| 424 |
int err = 0; |
| 425 |
|
| 426 |
fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); |
| 427 |
fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred); |
| 428 |
|
| 429 |
fri = fdi.indata; |
| 430 |
fri->newdir = VTOI(tdvp); |
| 431 |
memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, |
| 432 |
fcnp->cn_namelen); |
| 433 |
((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; |
| 434 |
memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, |
| 435 |
tcnp->cn_nameptr, tcnp->cn_namelen); |
| 436 |
((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + |
| 437 |
tcnp->cn_namelen + 1] = '\0'; |
| 438 |
|
| 439 |
err = fdisp_wait_answ(&fdi); |
| 440 |
fdisp_destroy(&fdi); |
| 441 |
return err; |
| 442 |
} |
| 443 |
|
| 444 |
/* strategy */ |
| 445 |
|
| 446 |
/* entity creation */ |
| 447 |
|
| 448 |
void |
| 449 |
fuse_internal_newentry_makerequest(struct mount *mp, |
| 450 |
uint64_t dnid, |
| 451 |
struct componentname *cnp, |
| 452 |
enum fuse_opcode op, |
| 453 |
void *buf, |
| 454 |
size_t bufsize, |
| 455 |
struct fuse_dispatcher *fdip) |
| 456 |
{ |
| 457 |
debug_printf("fdip=%p\n", fdip); |
| 458 |
|
| 459 |
fdip->iosize = bufsize + cnp->cn_namelen + 1; |
| 460 |
|
| 461 |
fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred); |
| 462 |
memcpy(fdip->indata, buf, bufsize); |
| 463 |
memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); |
| 464 |
((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; |
| 465 |
} |
| 466 |
|
| 467 |
int |
| 468 |
fuse_internal_newentry_core(struct vnode *dvp, |
| 469 |
struct vnode **vpp, |
| 470 |
struct componentname *cnp, |
| 471 |
enum vtype vtyp, |
| 472 |
struct fuse_dispatcher *fdip) |
| 473 |
{ |
| 474 |
int err = 0; |
| 475 |
struct fuse_entry_out *feo; |
| 476 |
struct mount *mp = vnode_mount(dvp); |
| 477 |
|
| 478 |
if ((err = fdisp_wait_answ(fdip))) { |
| 479 |
return err; |
| 480 |
} |
| 481 |
feo = fdip->answ; |
| 482 |
|
| 483 |
if ((err = fuse_internal_checkentry(feo, vtyp))) { |
| 484 |
return err; |
| 485 |
} |
| 486 |
err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, vtyp); |
| 487 |
if (err) { |
| 488 |
fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred, |
| 489 |
feo->nodeid, 1); |
| 490 |
return err; |
| 491 |
} |
| 492 |
cache_attrs(*vpp, feo); |
| 493 |
|
| 494 |
return err; |
| 495 |
} |
| 496 |
|
| 497 |
int |
| 498 |
fuse_internal_newentry(struct vnode *dvp, |
| 499 |
struct vnode **vpp, |
| 500 |
struct componentname *cnp, |
| 501 |
enum fuse_opcode op, |
| 502 |
void *buf, |
| 503 |
size_t bufsize, |
| 504 |
enum vtype vtype) |
| 505 |
{ |
| 506 |
int err; |
| 507 |
struct fuse_dispatcher fdi; |
| 508 |
struct mount *mp = vnode_mount(dvp); |
| 509 |
|
| 510 |
fdisp_init(&fdi, 0); |
| 511 |
fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, |
| 512 |
bufsize, &fdi); |
| 513 |
err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi); |
| 514 |
fdisp_destroy(&fdi); |
| 515 |
|
| 516 |
return err; |
| 517 |
} |
| 518 |
|
| 519 |
/* entity destruction */ |
| 520 |
|
| 521 |
int |
| 522 |
fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio) |
| 523 |
{ |
| 524 |
fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL, |
| 525 |
((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1); |
| 526 |
|
| 527 |
return 0; |
| 528 |
} |
| 529 |
|
| 530 |
void |
| 531 |
fuse_internal_forget_send(struct mount *mp, |
| 532 |
struct thread *td, |
| 533 |
struct ucred *cred, |
| 534 |
uint64_t nodeid, |
| 535 |
uint64_t nlookup) |
| 536 |
{ |
| 537 |
|
| 538 |
struct fuse_dispatcher fdi; |
| 539 |
struct fuse_forget_in *ffi; |
| 540 |
|
| 541 |
debug_printf("mp=%p, nodeid=%ju, nlookup=%ju\n", |
| 542 |
mp, (uintmax_t)nodeid, (uintmax_t)nlookup); |
| 543 |
|
| 544 |
/* |
| 545 |
* KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", |
| 546 |
* (long long unsigned) nodeid)); |
| 547 |
*/ |
| 548 |
|
| 549 |
fdisp_init(&fdi, sizeof(*ffi)); |
| 550 |
fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred); |
| 551 |
|
| 552 |
ffi = fdi.indata; |
| 553 |
ffi->nlookup = nlookup; |
| 554 |
|
| 555 |
fuse_insert_message(fdi.tick); |
| 556 |
fdisp_destroy(&fdi); |
| 557 |
} |
| 558 |
|
| 559 |
void |
| 560 |
fuse_internal_vnode_disappear(struct vnode *vp) |
| 561 |
{ |
| 562 |
struct fuse_vnode_data *fvdat = VTOFUD(vp); |
| 563 |
|
| 564 |
ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear"); |
| 565 |
fvdat->flag |= FN_REVOKED; |
| 566 |
cache_purge(vp); |
| 567 |
} |
| 568 |
|
| 569 |
/* fuse start/stop */ |
| 570 |
|
| 571 |
int |
| 572 |
fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio) |
| 573 |
{ |
| 574 |
int err = 0; |
| 575 |
struct fuse_data *data = tick->tk_data; |
| 576 |
struct fuse_init_out *fiio; |
| 577 |
|
| 578 |
if ((err = tick->tk_aw_ohead.error)) { |
| 579 |
goto out; |
| 580 |
} |
| 581 |
if ((err = fticket_pull(tick, uio))) { |
| 582 |
goto out; |
| 583 |
} |
| 584 |
fiio = fticket_resp(tick)->base; |
| 585 |
|
| 586 |
/* XXX: Do we want to check anything further besides this? */ |
| 587 |
if (fiio->major < 7) { |
| 588 |
debug_printf("userpace version too low\n"); |
| 589 |
err = EPROTONOSUPPORT; |
| 590 |
goto out; |
| 591 |
} |
| 592 |
data->fuse_libabi_major = fiio->major; |
| 593 |
data->fuse_libabi_minor = fiio->minor; |
| 594 |
|
| 595 |
if (fuse_libabi_geq(data, 7, 5)) { |
| 596 |
if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) { |
| 597 |
data->max_write = fiio->max_write; |
| 598 |
} else { |
| 599 |
err = EINVAL; |
| 600 |
} |
| 601 |
} else { |
| 602 |
/* Old fix values */ |
| 603 |
data->max_write = 4096; |
| 604 |
} |
| 605 |
|
| 606 |
out: |
| 607 |
if (err) { |
| 608 |
fdata_set_dead(data); |
| 609 |
} |
| 610 |
FUSE_LOCK(); |
| 611 |
data->dataflags |= FSESS_INITED; |
| 612 |
wakeup(&data->ticketer); |
| 613 |
FUSE_UNLOCK(); |
| 614 |
|
| 615 |
return 0; |
| 616 |
} |
| 617 |
|
| 618 |
void |
| 619 |
fuse_internal_send_init(struct fuse_data *data, struct thread *td) |
| 620 |
{ |
| 621 |
struct fuse_init_in *fiii; |
| 622 |
struct fuse_dispatcher fdi; |
| 623 |
|
| 624 |
fdisp_init(&fdi, sizeof(*fiii)); |
| 625 |
fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL); |
| 626 |
fiii = fdi.indata; |
| 627 |
fiii->major = FUSE_KERNEL_VERSION; |
| 628 |
fiii->minor = FUSE_KERNEL_MINOR_VERSION; |
| 629 |
fiii->max_readahead = FUSE_DEFAULT_IOSIZE * 16; |
| 630 |
fiii->flags = 0; |
| 631 |
|
| 632 |
fuse_insert_callback(fdi.tick, fuse_internal_init_callback); |
| 633 |
fuse_insert_message(fdi.tick); |
| 634 |
fdisp_destroy(&fdi); |
| 635 |
} |
| 636 |
|
| 637 |
#ifdef ZERO_PAD_INCOMPLETE_BUFS |
| 638 |
static int |
| 639 |
isbzero(void *buf, size_t len) |
| 640 |
{ |
| 641 |
int i; |
| 642 |
|
| 643 |
for (i = 0; i < len; i++) { |
| 644 |
if (((char *)buf)[i]) |
| 645 |
return (0); |
| 646 |
} |
| 647 |
|
| 648 |
return (1); |
| 649 |
} |
| 650 |
|
| 651 |
#endif |