Browse Source

Merge branch 'freebsd/current/master' into hardened/current/master

* freebsd/current/master: (247 commits)
  readelf: Close input files when done with them.
  Expose zlib's utility functions in Z_SOLO library when building kernel. This allows kernel code to reuse zlib's implementation.
  Tidy up the list of auth and encryption algorithms for IPsec stats.
  fusefs: remove superfluous counter_u64_zero
  fusefs: fix the build after r350446
  fusefs: proofread man pages
  Bump __FreeBSD_version
  fusefs: fix building tests with GCC 8
  fusefs: nul-terminate some strings in the readdir test
  MFHead @350390
  [skip ci] Add me to MAINTAINERS for fusefs
  fusefs: fix panic when writing with O_DIRECT and using writeback cache
  fusefs: fix warnings in the tests reported by GCC
  sendfile: don't panic when VOP_GETPAGES_ASYNC returns an error
  fusefs: add a intr/nointr mount option
  fusefs: fix another semi-infinite loop bug regarding signal handling
  fusefs: multiple interruptility improvements
  style changes to getvfsbyname
  Revert r346608
  fusefs: fix the build with some NODEBUG kernels
  ...
hardened/current/master
Oliver Pinter + 11 months ago
parent
commit
44d9a2ad7b
86 changed files with 20598 additions and 2332 deletions
  1. +1
    -0
      MAINTAINERS
  2. +12
    -0
      UPDATING
  3. +4
    -2
      contrib/elftoolchain/readelf/readelf.c
  4. +2
    -0
      etc/mtree/BSD.tests.dist
  5. +50
    -30
      sbin/mount_fusefs/mount_fusefs.8
  6. +11
    -25
      sbin/mount_fusefs/mount_fusefs.c
  7. +22
    -31
      share/man/man5/fusefs.5
  8. +17
    -22
      sys/conf/files
  9. +0
    -4
      sys/conf/kern.pre.mk
  10. +0
    -2
      sys/conf/kmod.mk
  11. +2
    -2
      sys/contrib/zlib/deflate.c
  12. +2
    -2
      sys/contrib/zlib/infback.c
  13. +2
    -2
      sys/contrib/zlib/inflate.c
  14. +9
    -3
      sys/contrib/zlib/zconf.h
  15. +4
    -1
      sys/contrib/zlib/zlib.h
  16. +1
    -1
      sys/contrib/zlib/zutil.h
  17. +7
    -0
      sys/dev/zlib/zcalloc.c
  18. +4
    -3
      sys/dev/zlib/zcalloc.h
  19. +6
    -78
      sys/fs/fuse/fuse.h
  20. +197
    -66
      sys/fs/fuse/fuse_device.c
  21. +180
    -86
      sys/fs/fuse/fuse_file.c
  22. +122
    -44
      sys/fs/fuse/fuse_file.h
  23. +687
    -165
      sys/fs/fuse/fuse_internal.c
  24. +89
    -37
      sys/fs/fuse/fuse_internal.h
  25. +559
    -233
      sys/fs/fuse/fuse_io.c
  26. +6
    -1
      sys/fs/fuse/fuse_io.h
  27. +351
    -78
      sys/fs/fuse/fuse_ipc.c
  28. +65
    -33
      sys/fs/fuse/fuse_ipc.h
  29. +521
    -150
      sys/fs/fuse/fuse_kernel.h
  30. +19
    -8
      sys/fs/fuse/fuse_main.c
  31. +188
    -116
      sys/fs/fuse/fuse_node.c
  32. +85
    -15
      sys/fs/fuse/fuse_node.h
  33. +0
    -82
      sys/fs/fuse/fuse_param.h
  34. +215
    -52
      sys/fs/fuse/fuse_vfsops.c
  35. +1022
    -927
      sys/fs/fuse/fuse_vnops.c
  36. +0
    -1
      sys/modules/crypto/Makefile
  37. +0
    -2
      sys/modules/mxge/mxge/Makefile
  38. +0
    -1
      sys/modules/zfs/Makefile
  39. +2
    -2
      sys/modules/zlib/Makefile
  40. +1
    -1
      sys/sys/param.h
  41. +5
    -0
      tests/sys/fs/Makefile
  42. +81
    -0
      tests/sys/fs/fusefs/Makefile
  43. +119
    -0
      tests/sys/fs/fusefs/access.cc
  44. +303
    -0
      tests/sys/fs/fusefs/allow_other.cc
  45. +159
    -0
      tests/sys/fs/fusefs/bmap.cc
  46. +449
    -0
      tests/sys/fs/fusefs/create.cc
  47. +1305
    -0
      tests/sys/fs/fusefs/default_permissions.cc
  48. +124
    -0
      tests/sys/fs/fusefs/default_permissions_privileged.cc
  49. +158
    -0
      tests/sys/fs/fusefs/destroy.cc
  50. +227
    -0
      tests/sys/fs/fusefs/dev_fuse_poll.cc
  51. +207
    -0
      tests/sys/fs/fusefs/fifo.cc
  52. +232
    -0
      tests/sys/fs/fusefs/flush.cc
  53. +154
    -0
      tests/sys/fs/fusefs/forget.cc
  54. +249
    -0
      tests/sys/fs/fusefs/fsync.cc
  55. +186
    -0
      tests/sys/fs/fusefs/fsyncdir.cc
  56. +300
    -0
      tests/sys/fs/fusefs/getattr.cc
  57. +790
    -0
      tests/sys/fs/fusefs/interrupt.cc
  58. +543
    -0
      tests/sys/fs/fusefs/io.cc
  59. +233
    -0
      tests/sys/fs/fusefs/link.cc
  60. +478
    -0
      tests/sys/fs/fusefs/locks.cc
  61. +381
    -0
      tests/sys/fs/fusefs/lookup.cc
  62. +222
    -0
      tests/sys/fs/fusefs/mkdir.cc
  63. +238
    -0
      tests/sys/fs/fusefs/mknod.cc
  64. +733
    -0
      tests/sys/fs/fusefs/mockfs.cc
  65. +394
    -0
      tests/sys/fs/fusefs/mockfs.hh
  66. +152
    -0
      tests/sys/fs/fusefs/mount.cc
  67. +344
    -0
      tests/sys/fs/fusefs/nfs.cc
  68. +545
    -0
      tests/sys/fs/fusefs/notify.cc
  69. +262
    -0
      tests/sys/fs/fusefs/open.cc
  70. +155
    -0
      tests/sys/fs/fusefs/opendir.cc
  71. +916
    -0
      tests/sys/fs/fusefs/read.cc
  72. +375
    -0
      tests/sys/fs/fusefs/readdir.cc
  73. +123
    -0
      tests/sys/fs/fusefs/readlink.cc
  74. +224
    -0
      tests/sys/fs/fusefs/release.cc
  75. +116
    -0
      tests/sys/fs/fusefs/releasedir.cc
  76. +321
    -0
      tests/sys/fs/fusefs/rename.cc
  77. +172
    -0
      tests/sys/fs/fusefs/rmdir.cc
  78. +774
    -0
      tests/sys/fs/fusefs/setattr.cc
  79. +171
    -0
      tests/sys/fs/fusefs/statfs.cc
  80. +178
    -0
      tests/sys/fs/fusefs/symlink.cc
  81. +251
    -0
      tests/sys/fs/fusefs/unlink.cc
  82. +593
    -0
      tests/sys/fs/fusefs/utils.cc
  83. +236
    -0
      tests/sys/fs/fusefs/utils.hh
  84. +1309
    -0
      tests/sys/fs/fusefs/write.cc
  85. +641
    -0
      tests/sys/fs/fusefs/xattr.cc
  86. +5
    -24
      usr.bin/netstat/ipsec.c

+ 1
- 0
MAINTAINERS View File

@@ -53,6 +53,7 @@ contrib/pjdfstest asomers,ngie,pjd,#test Pre-commit review requested.
etc/mail gshapiro Pre-commit review requested. Keep in sync with -STABLE.
etc/sendmail gshapiro Pre-commit review requested. Keep in sync with -STABLE.
fetch des Pre-commit review requested, email only.
fusefs(5) asomers Pre-commit review requested.
geli pjd Pre-commit review requested (both sys/geom/eli/ and sbin/geom/class/eli/).
isci(4) jimharris Pre-commit review requested.
iwm(4) adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org

+ 12
- 0
UPDATING View File

@@ -26,6 +26,18 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)

20190727:
The vfs.fusefs.sync_unmount and vfs.fusefs.init_backgrounded sysctls
and the "-o sync_unmount" and "-o init_backgrounded" mount options have
been removed from mount_fusefs(8). You can safely remove them from
your scripts, because they had no effect.

The vfs.fusefs.fix_broken_io, vfs.fusefs.sync_resize,
vfs.fusefs.refresh_size, vfs.fusefs.mmap_enable,
vfs.fusefs.reclaim_revoked, and vfs.fusefs.data_cache_invalidate
sysctls have been removed. If you felt the need to set any of them to
a non-default value, please tell asomers@FreeBSD.org why.

20190713:
Default permissions on the /var/account/acct file (and copies of it
rotated by periodic daily scripts) are changed from 0644 to 0640

+ 4
- 2
contrib/elftoolchain/readelf/readelf.c View File

@@ -7732,10 +7732,12 @@ main(int argc, char **argv)
for (i = 0; i < argc; i++) {
re->filename = argv[i];
fd = fileargs_open(fa, re->filename);
if (fd < 0)
if (fd < 0) {
warn("open %s failed", re->filename);
else
} else {
dump_object(re, fd);
close(fd);
}
}

exit(EXIT_SUCCESS);

+ 2
- 0
etc/mtree/BSD.tests.dist View File

@@ -731,6 +731,8 @@
file
..
fs
fusefs
..
tmpfs
..
..

+ 50
- 30
sbin/mount_fusefs/mount_fusefs.8 View File

@@ -3,6 +3,11 @@
.\" Copyright (c) 2005, 2006 Csaba Henk
.\" All rights reserved.
.\"
.\" Copyright (c) 2019 The FreeBSD Foundation
.\"
.\" Portions of this documentation were written by BFF Storage Systems under
.\" sponsorship from the FreeBSD Foundation.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -29,7 +34,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 17, 2018
.Dd July 31, 2019
.Dt MOUNT_FUSEFS 8
.Os
.Sh NAME
@@ -108,27 +113,27 @@ Intended for use in scripts and the
.Xr sudoers 5
file.
.It Fl S , Ic --safe
Run in safe mode (i.e. reject invoking a filesystem daemon)
Run in safe mode (i.e., reject invoking a filesystem daemon).
.It Fl v
Be verbose
.It Fl D, Ic --daemon Ar daemon
Be verbose.
.It Fl D , Ic --daemon Ar daemon
Call the specified
.Ar daemon
.It Fl O, Ic --daemon_opts Ar opts
.Ar daemon .
.It Fl O , Ic --daemon_opts Ar opts
Add
.Ar opts
to the daemon's command line
.It Fl s, Ic --special Ar special
to the daemon's command line.
.It Fl s , Ic --special Ar special
Use
.Ar special
as special
.It Fl m, Ic --mountpath Ar node
as special.
.It Fl m , Ic --mountpath Ar node
Mount on
.Ar node
.It Fl h, Ic --help
Show help
.It Fl V, Ic --version
Show version information
.Ar node .
.It Fl h , Ic --help
Show help.
.It Fl V , Ic --version
Show version information.
.It Fl o
Mount options are specified via
.Fl o .
@@ -136,23 +141,38 @@ The following options are available (and also their negated versions,
by prefixing them with
.Dq no ) :
.Bl -tag -width indent
.It Cm default_permissions
Enable traditional (file mode based) permission checking in kernel
.It Cm allow_other
Do not apply
.Sx STRICT ACCESS POLICY .
Only root can use this option
Only root can use this option.
.It Cm async
I/O to the file system may be done asynchronously.
Writes may be delayed and/or reordered.
.It Cm default_permissions
Enable traditional (file mode based) permission checking in kernel.
.It Cm intr
Allow signals to interrupt operations that are blocked waiting for a reply from the server.
When this option is in use, system calls may fail with
.Er EINTR
whenever a signal is received.
.It Cm max_read Ns = Ns Ar n
Limit size of read requests to
.Ar n
.Ar n .
.It Cm neglect_shares
Do not refuse unmounting if there are secondary mounts.
.It Cm private
Refuse shared mounting of the daemon.
This is the default behaviour, to allow sharing, expicitly use
.Fl o Cm noprivate
.It Cm neglect_shares
Do not refuse unmounting if there are secondary mounts
.Fl o Cm noprivate .
.It Cm push_symlinks_in
Prefix absolute symlinks with the mountpoint
Prefix absolute symlinks with the mountpoint.
.It Cm subtype Ns = Ns Ar fsname
Suffix
.Ar fsname
to the file system name as reported by
.Xr statfs 2 .
This option can be used to identify the file system implemented by
.Ar fuse_daemon .
.El
.El
.Pp
@@ -167,11 +187,11 @@ However, there are some which do require in-kernel support.
Currently the options supported by the kernel are:
.Bl -tag -width indent
.It Cm direct_io
Bypass the buffer cache system
Bypass the buffer cache system.
.It Cm kernel_cache
By default cached buffers of a given file are flushed at each
.Xr open 2 .
This option disables this behaviour
This option disables this behaviour.
.El
.Sh DAEMON MOUNTS
Usually users do not need to use
@@ -194,7 +214,7 @@ only if the filesystem daemon has the same credentials (uid, real uid, gid,
real gid) as the user.
.Pp
This is applied for Fuse mounts by default and only root can mount without
the strict access policy (i.e. the
the strict access policy (i.e., the
.Cm allow_other
mount option).
.Pp
@@ -206,7 +226,7 @@ Users might opt to willingly relax strict access policy (as far they
are concerned) by doing their own secondary mount (See
.Sx SHARED MOUNTS ) .
.Sh SHARED MOUNTS
A Fuse daemon can be shared (i.e. mounted multiple times).
A Fuse daemon can be shared (i.e., mounted multiple times).
When doing the first (primary) mount, the spawner and the mounter of the daemon
must have the same uid, or the mounter should be the superuser.
.Pp
@@ -225,7 +245,7 @@ is used or not.
.Pp
The device name of a secondary mount is the device name of the corresponding
primary mount, followed by a '#' character and the index of the secondary
mount; e.g.
mount; e.g.,
.Pa /dev/fuse0#3 .
.Sh SECURITY
System administrators might want to use a custom mount policy (ie., one going
@@ -239,7 +259,7 @@ However, given that
is capable of invoking an arbitrary program, one must be careful when doing this.
.Nm
is designed in a way such that it makes that easy.
For this purpose, there are options which disable certain risky features (i.e.
For this purpose, there are options which disable certain risky features (
.Fl S
and
.Fl A ) ,
@@ -342,7 +362,7 @@ does not call any external utility and also provides a hacky
was written as the part of the
.Fx
implementation of the Fuse userspace filesystem framework (see
.Xr https://github.com/libfuse/libfuse )
.Lk https://github.com/libfuse/libfuse )
and first appeared in the
.Pa sysutils/fusefs-kmod
port, supporting

+ 11
- 25
sbin/mount_fusefs/mount_fusefs.c View File

@@ -5,6 +5,11 @@
* Copyright (c) 2005 Csaba Henk
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -60,7 +65,6 @@ void __usage_short(void);
void usage(void);
void helpmsg(void);
void showversion(void);
int init_backgrounded(void);

static struct mntopt mopts[] = {
#define ALTF_PRIVATE 0x01
@@ -73,8 +77,6 @@ static struct mntopt mopts[] = {
{ "max_read=", 0, ALTF_MAXREAD, 1 },
#define ALTF_SUBTYPE 0x40
{ "subtype=", 0, ALTF_SUBTYPE, 1 },
#define ALTF_SYNC_UNMOUNT 0x80
{ "sync_unmount", 0, ALTF_SYNC_UNMOUNT, 1 },
/*
* MOPT_AUTOMOUNTED, included by MOPT_STDOPTS, does not fit into
* the 'flags' argument to nmount(2). We have to abuse altflags
@@ -82,6 +84,8 @@ static struct mntopt mopts[] = {
*/
#define ALTF_AUTOMOUNTED 0x100
{ "automounted", 0, ALTF_AUTOMOUNTED, 1 },
#define ALTF_INTR 0x200
{ "intr", 0, ALTF_INTR, 1 },
/* Linux specific options, we silently ignore them */
{ "fsname=", 0, 0x00, 1 },
{ "fd=", 0, 0x00, 1 },
@@ -91,6 +95,8 @@ static struct mntopt mopts[] = {
{ "large_read", 0, 0x00, 1 },
/* "nonempty", just the first two chars are stripped off during parsing */
{ "nempty", 0, 0x00, 1 },
{ "async", 0, MNT_ASYNC, 0},
{ "noasync", 1, MNT_ASYNC, 0},
MOPT_STDOPTS,
MOPT_END
};
@@ -107,7 +113,7 @@ static struct mntval mvals[] = {
{ 0, NULL, 0 }
};

#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE | ALTF_SYNC_UNMOUNT
#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE

int
main(int argc, char *argv[])
@@ -409,12 +415,6 @@ main(int argc, char *argv[])
}
}

if (fd >= 0 && ! init_backgrounded() && close(fd) < 0) {
if (pid)
kill(pid, SIGKILL);
err(1, "failed to close fuse device");
}

/* Prepare the options vector for nmount(). build_iovec() is declared
* in mntopts.h. */
sprintf(fdstr, "%d", fd);
@@ -471,6 +471,7 @@ helpmsg(void)
" -o allow_other allow access to other users\n"
/* " -o nonempty allow mounts over non-empty file/dir\n" */
" -o default_permissions enable permission checking by kernel\n"
" -o intr interruptible mount\n"
/*
" -o fsname=NAME set filesystem name\n"
" -o large_read issue large read requests (2.4 only)\n"
@@ -481,7 +482,6 @@ helpmsg(void)
" -o neglect_shares don't report EBUSY when unmount attempted\n"
" in presence of secondary mounts\n"
" -o push_symlinks_in prefix absolute symlinks with mountpoint\n"
" -o sync_unmount do unmount synchronously\n"
);
exit(EX_USAGE);
}
@@ -492,17 +492,3 @@ showversion(void)
puts("mount_fusefs [fuse4bsd] version: " FUSE4BSD_VERSION);
exit(EX_USAGE);
}

int
init_backgrounded(void)
{
int ibg;
size_t len;

len = sizeof(ibg);

if (sysctlbyname("vfs.fusefs.init_backgrounded", &ibg, &len, NULL, 0))
return (0);

return (ibg);
}

+ 22
- 31
share/man/man5/fusefs.5 View File

@@ -3,8 +3,8 @@
.\"
.\" Copyright (c) 2019 The FreeBSD Foundation
.\"
.\" This software was developed by BFF Storage Systems, LLC under sponsorship
.\" from the FreeBSD Foundation.
.\" This documentation was written by BFF Storage Systems, LLC under
.\" sponsorship from the FreeBSD Foundation.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.Dd April 13, 2019
.Dd July 31, 2019
.Dt FUSEFS 5
.Os
.Sh NAME
@@ -60,11 +60,9 @@ Finally, the
API is portable.
Many daemons can run on multiple operating systems with minimal modifications.
.Sh SYSCTL VARIABLES
The following variables are available as both
The following
.Xr sysctl 8
variables and
.Xr loader 8
tunables:
variables are available:
.Bl -tag -width indent
.It Va vfs.fusefs.kernelabi_major
Major version of the FUSE kernel ABI supported by this driver.
@@ -73,7 +71,7 @@ Minor version of the FUSE kernel ABI supported by this driver.
.It Va vfs.fusefs.data_cache_mode
Controls how
.Nm
will cache file data.
will cache file data for pre-7.23 file systems.
A value of 0 will disable caching entirely.
Every data access will be forwarded to the daemon.
A value of 1 will select write-through caching.
@@ -84,33 +82,26 @@ Reads and writes will both be cached, and writes will occasionally be flushed
to the daemon by the page daemon.
Write-back caching is usually unsafe, especially for FUSE file systems that
require network access.
.It Va vfs.fusefs.lookup_cache_enable
Controls whether
.Nm
will cache lookup responses from the file system.
FUSE file systems indicate whether lookup responses should be cacheable, but
it may be useful to globally disable caching them if a file system is
misbehaving.
.Pp
FUSE file systems using protocol 7.23 or later specify their cache behavior
on a per-mountpoint basis, ignoring this sysctl.
.It Va vfs.fusefs.stats.filehandle_count
Current number of open FUSE file handles.
.It Va vfs.fusefs.stats.lookup_cache_hits
Total number of lookup cache hits.
.It Va vfs.fusefs.stats.lookup_cache_misses
Total number of lookup cache misses.
.It Va vfs.fusefs.stats.node_count
Current number of allocated FUSE vnodes.
.It Va vfs.fusefs.stats.ticket_count
Current number of allocated FUSE tickets, which is roughly equal to the number
of FUSE operations currently being processed by daemons.
.\" Undocumented sysctls
.\" ====================
.\" Counters: I intend to rename to vfs.fusefs.stats.* for clarity
.\" vfs.fusefs.lookup_cache_{hits, misses}
.\" vfs.fusefs.filehandle_count
.\" vfs.fusefs.ticker_count
.\" vfs.fusefs.node_count
.\"
.\" vfs.fusefs.version - useless since the driver moved in-tree
.\" vfs.fusefs.reclaim_revoked: I don't understand it well-enough
.\" vfs.fusefs.sync_unmount: dead code
.\" vfs.fusefs.enforce_dev_perms: I don't understand it well enough.
.\" vfs.fusefs.init_backgrounded: dead code
.\" vfs.fusefs.iov_credit: I don't understand it well enough
.\" vfs.fusefs.iov_permanent_bufsize: I don't understand it well enough
.\" vfs.fusefs.fix_broken_io: I don't understand it well enough
.\" vfs.fusefs.sync_resize: useless and should be removed
.\" vfs.fusefs.refresh_size: probably useless?
.\" vfs.fusefs.mmap_enable: why is this optional?
.\" vfs.fusefs.data_cache_invalidate: what is this needed for?
.El
.Sh SEE ALSO
.Xr mount_fusefs 8
.Sh HISTORY
@@ -119,7 +110,7 @@ The
driver was written as the part of the
.Fx
implementation of the FUSE userspace file system framework (see
.Xr https://github.com/libfuse/libfuse )
.Lk https://github.com/libfuse/libfuse )
and first appeared in the
.Pa sysutils/fusefs-kmod
port, supporting

+ 17
- 22
sys/conf/files View File

@@ -273,7 +273,7 @@ cddl/contrib/opensolaris/uts/common/os/callb.c optional zfs compile-with "${Z
cddl/contrib/opensolaris/uts/common/os/fm.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/uts/common/os/list.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/uts/common/os/nvpair_alloc_system.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/uts/common/zmod/zmod.c optional zfs compile-with "${ZFS_C} ${ZLIB_CFLAGS}"
cddl/contrib/opensolaris/uts/common/zmod/zmod.c optional zfs compile-with "${ZFS_C}"
# zfs lua support
cddl/contrib/opensolaris/uts/common/fs/zfs/lua/lapi.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/uts/common/fs/zfs/lua/lauxlib.c optional zfs compile-with "${ZFS_C}"
@@ -2443,8 +2443,7 @@ mwlboot.fw optional mwlfw \
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "mwlboot.fw"
dev/mxge/if_mxge.c optional mxge pci \
compile-with "${ZLIB_C}"
dev/mxge/if_mxge.c optional mxge pci
dev/mxge/mxge_eth_z8e.c optional mxge pci
dev/mxge/mxge_ethp_z8e.c optional mxge pci
dev/mxge/mxge_rss_eth_z8e.c optional mxge pci
@@ -4008,35 +4007,32 @@ libkern/timingsafe_bcmp.c standard
libkern/zlib.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | netgraph_deflate | ddb_ctf | gzio
contrib/zlib/adler32.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/compress.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
compile-with "${NORMAL_C} -Wno-cast-qual"
contrib/zlib/crc32.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C} -Wno-cast-qual"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/deflate.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C} -Wno-cast-qual"
compile-with "${NORMAL_C} -Wno-cast-qual"
contrib/zlib/inffast.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/inflate.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/inftrees.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/trees.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
contrib/zlib/uncompr.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
compile-with "${NORMAL_C} -Wno-cast-qual"
contrib/zlib/zutil.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
dev/zlib/zlib_mod.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
dev/zlib/zcalloc.c optional crypto | geom_uzip | ipsec | \
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib \
compile-with "${ZLIB_C}"
ipsec_support | mxge | ddb_ctf | gzio | zfs | zlib
net/altq/altq_cbq.c optional altq
net/altq/altq_codel.c optional altq
net/altq/altq_hfsc.c optional altq
@@ -4789,8 +4785,7 @@ opencrypto/crypto.c optional crypto | ipsec | ipsec_support
opencrypto/cryptodev.c optional cryptodev
opencrypto/cryptodev_if.m optional crypto | ipsec | ipsec_support
opencrypto/cryptosoft.c optional crypto | ipsec | ipsec_support
opencrypto/cryptodeflate.c optional crypto | ipsec | ipsec_support \
compile-with "${ZLIB_C}"
opencrypto/cryptodeflate.c optional crypto | ipsec | ipsec_support
opencrypto/gmac.c optional crypto | ipsec | ipsec_support
opencrypto/gfmult.c optional crypto | ipsec | ipsec_support
opencrypto/rmd160.c optional crypto | ipsec | ipsec_support

+ 0
- 4
sys/conf/kern.pre.mk View File

@@ -173,10 +173,6 @@ NORMAL_FW= uudecode -o ${.TARGET} ${.ALLSRC}
NORMAL_FWO= ${LD} -b binary --no-warn-mismatch -d -warn-common -r \
-m ${LD_EMULATION} -o ${.TARGET} ${.ALLSRC:M*.fw}

# for zlib in the kernel
ZLIB_CFLAGS+= -DZ_SOLO
ZLIB_C= ${CC} -c ${ZLIB_CFLAGS} ${CFLAGS} ${.IMPSRC}

# for ZSTD in the kernel (include zstd/lib/freebsd before other CFLAGS)
ZSTD_C= ${CC} -c -DZSTD_HEAPMODE=1 -I$S/contrib/zstd/lib/freebsd ${CFLAGS} -I$S/contrib/zstd/lib -I$S/contrib/zstd/lib/common ${WERROR} -Wno-inline -Wno-missing-prototypes ${PROF} -U__BMI__ ${.IMPSRC}


+ 0
- 2
sys/conf/kmod.mk View File

@@ -104,8 +104,6 @@ __KLD_SHARED=yes
__KLD_SHARED=no
.endif

ZLIB_CFLAGS+= -DZ_SOLO

.if !empty(CFLAGS:M-O[23s]) && empty(CFLAGS:M-fno-strict-aliasing)
CFLAGS+= -fno-strict-aliasing
.endif

+ 2
- 2
sys/contrib/zlib/deflate.c View File

@@ -266,7 +266,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,

strm->msg = Z_NULL;
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
@@ -274,7 +274,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
#endif
}
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;

+ 2
- 2
sys/contrib/zlib/infback.c View File

@@ -42,7 +42,7 @@ int stream_size;
return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
@@ -50,7 +50,7 @@ int stream_size;
#endif
}
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;

+ 2
- 2
sys/contrib/zlib/inflate.c View File

@@ -207,7 +207,7 @@ int stream_size;
if (strm == Z_NULL) return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
@@ -215,7 +215,7 @@ int stream_size;
#endif
}
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
#if defined(Z_SOLO) && !defined(_KERNEL)
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;

+ 9
- 3
sys/contrib/zlib/zconf.h View File

@@ -8,6 +8,12 @@
#ifndef ZCONF_H
#define ZCONF_H

#ifdef __FreeBSD__
#ifdef _KERNEL
#define Z_SOLO
#endif
#endif

/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
@@ -30,7 +36,7 @@
# define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64
# define adler32_z z_adler32_z
# ifndef Z_SOLO
# if !defined(Z_SOLO) && !defined(_KERNEL)
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
@@ -125,12 +131,12 @@
# define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table
# ifndef Z_SOLO
# if !defined(Z_SOLO) && !defined(_KERNEL)
# define uncompress z_uncompress
# define uncompress2 z_uncompress2
# endif
# define zError z_zError
# ifndef Z_SOLO
# if !defined(Z_SOLO) && !defined(_KERNEL)
# define zcalloc z_zcalloc
# define zcfree z_zcfree
# endif

+ 4
- 1
sys/contrib/zlib/zlib.h View File

@@ -1213,7 +1213,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
27-31: 0 (reserved)
*/

#ifndef Z_SOLO
#if !defined(Z_SOLO) || defined(_KERNEL)

/* utility functions */

@@ -1288,6 +1288,9 @@ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,
length of the source is *sourceLen. On return, *sourceLen is the number of
source bytes consumed.
*/
#endif /* !Z_SOLO || _KERNEL */

#ifndef Z_SOLO

/* gzip file access functions */


+ 1
- 1
sys/contrib/zlib/zutil.h View File

@@ -256,7 +256,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define Tracecv(c,x)
#endif

#ifndef Z_SOLO
#if !defined(Z_SOLO) || defined(_KERNEL)
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
unsigned size));
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));

+ 7
- 0
sys/dev/zlib/zcalloc.c View File

@@ -24,6 +24,13 @@ zcalloc_nowait(void *nil, u_int items, u_int size)
return mallocarray(items, size, M_ZLIB, M_NOWAIT);
}

void *
zcalloc(void *nil, u_int items, u_int size)
{

return zcalloc_nowait(nil, items, size);
}

void
zcfree(void *nil, void *ptr)
{

+ 4
- 3
sys/dev/zlib/zcalloc.h View File

@@ -6,8 +6,9 @@
#ifndef _DEV_ZLIB_ZCALLOC_
#define _DEV_ZLIB_ZCALLOC_

void * zcalloc_waitok(void *nil, u_int items, u_int size);
void * zcalloc_nowait(void *nil, u_int items, u_int size);
void zcfree(void *nil, void *ptr);
#include <contrib/zlib/zutil.h>
#undef local

void *zcalloc_waitok(void *, u_int, u_int);
void *zcalloc_nowait(void *, u_int, u_int);
#endif

+ 6
- 78
sys/fs/fuse/fuse.h View File

@@ -32,6 +32,11 @@
*
* Copyright (C) 2005 Csaba Henk.
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems, LLC under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -63,87 +68,10 @@
#define FUSE_MIN_DAEMON_TIMEOUT 0 /* s */
#define FUSE_MAX_DAEMON_TIMEOUT 600 /* s */

#ifndef FUSE_FREEBSD_VERSION
#define FUSE_FREEBSD_VERSION "0.4.4"
#endif

/* Mapping versions to features */

#define FUSE_KERNELABI_GEQ(maj, min) \
(FUSE_KERNEL_VERSION > (maj) || (FUSE_KERNEL_VERSION == (maj) && FUSE_KERNEL_MINOR_VERSION >= (min)))

/*
* Appearance of new FUSE operations is not always in par with version
* numbering... At least, 7.3 is a sufficient condition for having
* FUSE_{ACCESS,CREATE}.
*/
#if FUSE_KERNELABI_GEQ(7, 3)
#ifndef FUSE_HAS_ACCESS
#define FUSE_HAS_ACCESS 1
#endif
#ifndef FUSE_HAS_CREATE
#define FUSE_HAS_CREATE 1
#endif
#else /* FUSE_KERNELABI_GEQ(7, 3) */
#ifndef FUSE_HAS_ACCESS
#define FUSE_HAS_ACCESS 0
#endif
#ifndef FUSE_HAS_CREATE
#define FUSE_HAS_CREATE 0
#endif
#endif

#if FUSE_KERNELABI_GEQ(7, 7)
#ifndef FUSE_HAS_GETLK
#define FUSE_HAS_GETLK 1
#endif
#ifndef FUSE_HAS_SETLK
#define FUSE_HAS_SETLK 1
#endif
#ifndef FUSE_HAS_SETLKW
#define FUSE_HAS_SETLKW 1
#endif
#ifndef FUSE_HAS_INTERRUPT
#define FUSE_HAS_INTERRUPT 1
#endif
#else /* FUSE_KERNELABI_GEQ(7, 7) */
#ifndef FUSE_HAS_GETLK
#define FUSE_HAS_GETLK 0
#endif
#ifndef FUSE_HAS_SETLK
#define FUSE_HAS_SETLK 0
#endif
#ifndef FUSE_HAS_SETLKW
#define FUSE_HAS_SETLKW 0
#endif
#ifndef FUSE_HAS_INTERRUPT
#define FUSE_HAS_INTERRUPT 0
#endif
#endif

#if FUSE_KERNELABI_GEQ(7, 8)
#ifndef FUSE_HAS_FLUSH_RELEASE
#define FUSE_HAS_FLUSH_RELEASE 1
/*
* "DESTROY" came in the middle of the 7.8 era,
* so this is not completely exact...
*/
#ifndef FUSE_HAS_DESTROY
#define FUSE_HAS_DESTROY 1
#endif
#endif
#else /* FUSE_KERNELABI_GEQ(7, 8) */
#ifndef FUSE_HAS_FLUSH_RELEASE
#define FUSE_HAS_FLUSH_RELEASE 0
#ifndef FUSE_HAS_DESTROY
#define FUSE_HAS_DESTROY 0
#endif
#endif
#endif

/* misc */

SYSCTL_DECL(_vfs_fusefs);
SYSCTL_DECL(_vfs_fusefs_stats);

/* Fuse locking */


+ 197
- 66
sys/fs/fuse/fuse_device.c View File

@@ -33,6 +33,11 @@
* Copyright (C) 2005 Csaba Henk.
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems, LLC under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -81,27 +86,28 @@ __FBSDID("$FreeBSD$");
#include <sys/selinfo.h>

#include "fuse.h"
#include "fuse_internal.h"
#include "fuse_ipc.h"

SDT_PROVIDER_DECLARE(fuse);
SDT_PROVIDER_DECLARE(fusefs);
/*
* Fuse trace probe:
* arg0: verbosity. Higher numbers give more verbose messages
* arg1: Textual message
*/
SDT_PROBE_DEFINE2(fuse, , device, trace, "int", "char*");
SDT_PROBE_DEFINE2(fusefs, , device, trace, "int", "char*");

static struct cdev *fuse_dev;

static d_kqfilter_t fuse_device_filter;
static d_open_t fuse_device_open;
static d_close_t fuse_device_close;
static d_poll_t fuse_device_poll;
static d_read_t fuse_device_read;
static d_write_t fuse_device_write;

static struct cdevsw fuse_device_cdevsw = {
.d_kqfilter = fuse_device_filter,
.d_open = fuse_device_open,
.d_close = fuse_device_close,
.d_name = "fuse",
.d_poll = fuse_device_poll,
.d_read = fuse_device_read,
@@ -109,6 +115,15 @@ static struct cdevsw fuse_device_cdevsw = {
.d_version = D_VERSION,
};

static int fuse_device_filt_read(struct knote *kn, long hint);
static void fuse_device_filt_detach(struct knote *kn);

struct filterops fuse_device_rfiltops = {
.f_isfd = 1,
.f_detach = fuse_device_filt_detach,
.f_event = fuse_device_filt_read,
};

/****************************
*
* >>> Fuse device op defs
@@ -119,11 +134,100 @@ static void
fdata_dtor(void *arg)
{
struct fuse_data *fdata;
struct fuse_ticket *tick;

fdata = arg;
if (fdata == NULL)
return;

fdata_set_dead(fdata);

FUSE_LOCK();
fuse_lck_mtx_lock(fdata->aw_mtx);
/* wakup poll()ers */
selwakeuppri(&fdata->ks_rsel, PZERO + 1);
/* Don't let syscall handlers wait in vain */
while ((tick = fuse_aw_pop(fdata))) {
fuse_lck_mtx_lock(tick->tk_aw_mtx);
fticket_set_answered(tick);
tick->tk_aw_errno = ENOTCONN;
wakeup(tick);
fuse_lck_mtx_unlock(tick->tk_aw_mtx);
FUSE_ASSERT_AW_DONE(tick);
fuse_ticket_drop(tick);
}
fuse_lck_mtx_unlock(fdata->aw_mtx);

/* Cleanup unsent operations */
fuse_lck_mtx_lock(fdata->ms_mtx);
while ((tick = fuse_ms_pop(fdata))) {
fuse_ticket_drop(tick);
}
fuse_lck_mtx_unlock(fdata->ms_mtx);
FUSE_UNLOCK();

fdata_trydestroy(fdata);
}

static int
fuse_device_filter(struct cdev *dev, struct knote *kn)
{
struct fuse_data *data;
int error;

error = devfs_get_cdevpriv((void **)&data);

/* EVFILT_WRITE is not supported; the device is always ready to write */
if (error == 0 && kn->kn_filter == EVFILT_READ) {
kn->kn_fop = &fuse_device_rfiltops;
kn->kn_hook = data;
knlist_add(&data->ks_rsel.si_note, kn, 0);
error = 0;
} else if (error == 0) {
error = EINVAL;
kn->kn_data = error;
}

return (error);
}

static void
fuse_device_filt_detach(struct knote *kn)
{
struct fuse_data *data;

data = (struct fuse_data*)kn->kn_hook;
MPASS(data != NULL);
knlist_remove(&data->ks_rsel.si_note, kn, 0);
kn->kn_hook = NULL;
}

static int
fuse_device_filt_read(struct knote *kn, long hint)
{
struct fuse_data *data;
int ready;

data = (struct fuse_data*)kn->kn_hook;
MPASS(data != NULL);

mtx_assert(&data->ms_mtx, MA_OWNED);
if (fdata_get_dead(data)) {
kn->kn_flags |= EV_EOF;
kn->kn_fflags = ENODEV;
kn->kn_data = 1;
ready = 1;
} else if (STAILQ_FIRST(&data->ms_head)) {
MPASS(data->ms_count >= 1);
kn->kn_data = data->ms_count;
ready = 1;
} else {
ready = 0;
}

return (ready);
}

/*
* Resources are set up on a per-open basis
*/
@@ -133,52 +237,17 @@ fuse_device_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
struct fuse_data *fdata;
int error;

SDT_PROBE2(fuse, , device, trace, 1, "device open");
SDT_PROBE2(fusefs, , device, trace, 1, "device open");

fdata = fdata_alloc(dev, td->td_ucred);
error = devfs_set_cdevpriv(fdata, fdata_dtor);
if (error != 0)
fdata_trydestroy(fdata);
else
SDT_PROBE2(fuse, , device, trace, 1, "device open success");
SDT_PROBE2(fusefs, , device, trace, 1, "device open success");
return (error);
}

static int
fuse_device_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct fuse_data *data;
struct fuse_ticket *tick;
int error;

error = devfs_get_cdevpriv((void **)&data);
if (error != 0)
return (error);
if (!data)
panic("no fuse data upon fuse device close");
fdata_set_dead(data);

FUSE_LOCK();
fuse_lck_mtx_lock(data->aw_mtx);
/* wakup poll()ers */
selwakeuppri(&data->ks_rsel, PZERO + 1);
/* Don't let syscall handlers wait in vain */
while ((tick = fuse_aw_pop(data))) {
fuse_lck_mtx_lock(tick->tk_aw_mtx);
fticket_set_answered(tick);
tick->tk_aw_errno = ENOTCONN;
wakeup(tick);
fuse_lck_mtx_unlock(tick->tk_aw_mtx);
FUSE_ASSERT_AW_DONE(tick);
fuse_ticket_drop(tick);
}
fuse_lck_mtx_unlock(data->aw_mtx);
FUSE_UNLOCK();

SDT_PROBE2(fuse, , device, trace, 1, "device close");
return (0);
}

int
fuse_device_poll(struct cdev *dev, int events, struct thread *td)
{
@@ -219,7 +288,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, int ioflag)
int buflen[3];
int i;

SDT_PROBE2(fuse, , device, trace, 1, "fuse device read");
SDT_PROBE2(fusefs, , device, trace, 1, "fuse device read");

err = devfs_get_cdevpriv((void **)&data);
if (err != 0)
@@ -228,7 +297,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, int ioflag)
fuse_lck_mtx_lock(data->ms_mtx);
again:
if (fdata_get_dead(data)) {
SDT_PROBE2(fuse, , device, trace, 2,
SDT_PROBE2(fusefs, , device, trace, 2,
"we know early on that reader should be kicked so we "
"don't wait for news");
fuse_lck_mtx_unlock(data->ms_mtx);
@@ -256,7 +325,7 @@ again:
* -- and some other cases, too, tho not totally clear, when
* (cv_signal/wakeup_one signals the whole process ?)
*/
SDT_PROBE2(fuse, , device, trace, 1, "no message on thread");
SDT_PROBE2(fusefs, , device, trace, 1, "no message on thread");
goto again;
}
fuse_lck_mtx_unlock(data->ms_mtx);
@@ -266,9 +335,10 @@ again:
* somebody somewhere -- eg., umount routine --
* wants this liaison finished off
*/
SDT_PROBE2(fuse, , device, trace, 2, "reader is to be sacked");
SDT_PROBE2(fusefs, , device, trace, 2,
"reader is to be sacked");
if (tick) {
SDT_PROBE2(fuse, , device, trace, 2, "weird -- "
SDT_PROBE2(fusefs, , device, trace, 2, "weird -- "
"\"kick\" is set tho there is message");
FUSE_ASSERT_MS_DONE(tick);
fuse_ticket_drop(tick);
@@ -276,7 +346,7 @@ again:
return (ENODEV); /* This should make the daemon get off
* of us */
}
SDT_PROBE2(fuse, , device, trace, 1,
SDT_PROBE2(fusefs, , device, trace, 1,
"fuse device read message successfully");

KASSERT(tick->tk_ms_bufdata || tick->tk_ms_bufsize == 0,
@@ -311,7 +381,7 @@ again:
*/
if (uio->uio_resid < buflen[i]) {
fdata_set_dead(data);
SDT_PROBE2(fuse, , device, trace, 2,
SDT_PROBE2(fusefs, , device, trace, 2,
"daemon is stupid, kick it off...");
err = ENODEV;
break;
@@ -331,23 +401,26 @@ static inline int
fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio)
{
if (uio->uio_resid + sizeof(struct fuse_out_header) != ohead->len) {
SDT_PROBE2(fuse, , device, trace, 1, "Format error: body size "
SDT_PROBE2(fusefs, , device, trace, 1,
"Format error: body size "
"differs from size claimed by header");
return (EINVAL);
}
if (uio->uio_resid && ohead->error) {
SDT_PROBE2(fuse, , device, trace, 1,
if (uio->uio_resid && ohead->unique != 0 && ohead->error) {
SDT_PROBE2(fusefs, , device, trace, 1,
"Format error: non zero error but message had a body");
return (EINVAL);
}
/* Sanitize the linuxism of negative errnos */
ohead->error = -(ohead->error);

return (0);
}

SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_bumped_into_callback,
"uint64_t");
SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_notify,
"struct fuse_out_header*");
SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_missing_ticket,
"uint64_t");
SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_found,
"struct fuse_ticket*");
/*
* fuse_device_write first reads the header sent by the daemon.
* If that's OK, looks up ticket/callback node by the unique id seen in header.
@@ -360,15 +433,17 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
struct fuse_out_header ohead;
int err = 0;
struct fuse_data *data;
struct fuse_ticket *tick, *x_tick;
struct mount *mp;
struct fuse_ticket *tick, *itick, *x_tick;
int found = 0;

err = devfs_get_cdevpriv((void **)&data);
if (err != 0)
return (err);
mp = data->mp;

if (uio->uio_resid < sizeof(struct fuse_out_header)) {
SDT_PROBE2(fuse, , device, trace, 1,
SDT_PROBE2(fusefs, , device, trace, 1,
"fuse_device_write got less than a header!");
fdata_set_dead(data);
return (EINVAL);
@@ -393,15 +468,29 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
fuse_lck_mtx_lock(data->aw_mtx);
TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link,
x_tick) {
SDT_PROBE1(fuse, , device,
fuse_device_write_bumped_into_callback,
tick->tk_unique);
if (tick->tk_unique == ohead.unique) {
SDT_PROBE1(fusefs, , device, fuse_device_write_found,
tick);
found = 1;
fuse_aw_remove(tick);
break;
}
}
if (found && tick->irq_unique > 0) {
/*
* Discard the FUSE_INTERRUPT ticket that tried to interrupt
* this operation
*/
TAILQ_FOREACH_SAFE(itick, &data->aw_head, tk_aw_link,
x_tick) {
if (itick->tk_unique == tick->irq_unique) {
fuse_aw_remove(itick);
fuse_ticket_drop(itick);
break;
}
}
tick->irq_unique = 0;
}
fuse_lck_mtx_unlock(data->aw_mtx);

if (found) {
@@ -414,13 +503,15 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
* via ticket_drop(), so no manual mucking
* around...)
*/
SDT_PROBE2(fuse, , device, trace, 1,
SDT_PROBE2(fusefs, , device, trace, 1,
"pass ticket to a callback");
/* Sanitize the linuxism of negative errnos */
ohead.error *= -1;
memcpy(&tick->tk_aw_ohead, &ohead, sizeof(ohead));
err = tick->tk_aw_handler(tick, uio);
} else {
/* pretender doesn't wanna do anything with answer */
SDT_PROBE2(fuse, , device, trace, 1,
SDT_PROBE2(fusefs, , device, trace, 1,
"stuff devalidated, so we drop it");
}

@@ -430,11 +521,51 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
* because fuse_ticket_drop() will deal with refcount anyway.
*/
fuse_ticket_drop(tick);
} else if (ohead.unique == 0){
/* unique == 0 means asynchronous notification */
SDT_PROBE1(fusefs, , device, fuse_device_write_notify, &ohead);
switch (ohead.error) {
case FUSE_NOTIFY_INVAL_ENTRY:
err = fuse_internal_invalidate_entry(mp, uio);
break;
case FUSE_NOTIFY_INVAL_INODE:
err = fuse_internal_invalidate_inode(mp, uio);
break;
case FUSE_NOTIFY_RETRIEVE:
case FUSE_NOTIFY_STORE:
/*
* Unimplemented. I don't know of any file systems
* that use them, and the protocol isn't sound anyway,
* since the notification messages don't include the
* inode's generation number. Without that, it's
* possible to manipulate the cache of the wrong vnode.
* Finally, it's not defined what this message should
* do for a file with dirty cache.
*/
case FUSE_NOTIFY_POLL:
/* Unimplemented. See comments in fuse_vnops */
default:
/* Not implemented */
err = ENOSYS;
}
} else {
/* no callback at all! */
SDT_PROBE2(fuse, , device, trace, 1,
"erhm, no handler for this response");
err = EINVAL;
SDT_PROBE1(fusefs, , device, fuse_device_write_missing_ticket,
ohead.unique);
if (ohead.error == -EAGAIN) {
/*
* This was probably a response to a FUSE_INTERRUPT
* operation whose original operation is already
* complete. We can't store FUSE_INTERRUPT tickets
* indefinitely because their responses are optional.
* So we delete them when the original operation
* completes. And sadly the fuse_header_out doesn't
* identify the opcode, so we have to guess.
*/
err = 0;
} else {
err = EINVAL;
}
}

return (err);
@@ -445,7 +576,7 @@ fuse_device_init(void)
{

fuse_dev = make_dev(&fuse_device_cdevsw, 0, UID_ROOT, GID_OPERATOR,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, "fuse");
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, "fuse");
if (fuse_dev == NULL)
return (ENOMEM);
return (0);

+ 180
- 86
sys/fs/fuse/fuse_file.c View File

@@ -33,6 +33,11 @@
* Copyright (C) 2005 Csaba Henk.
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems, LLC under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -59,8 +64,9 @@
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/counter.h>
#include <sys/module.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/conf.h>
@@ -79,52 +85,61 @@ __FBSDID("$FreeBSD$");
#include "fuse.h"
#include "fuse_file.h"
#include "fuse_internal.h"
#include "fuse_io.h"
#include "fuse_ipc.h"
#include "fuse_node.h"

SDT_PROVIDER_DECLARE(fuse);
MALLOC_DEFINE(M_FUSE_FILEHANDLE, "fuse_filefilehandle", "FUSE file handle");

SDT_PROVIDER_DECLARE(fusefs);
/*
* Fuse trace probe:
* arg0: verbosity. Higher numbers give more verbose messages
* arg1: Textual message
*/
SDT_PROBE_DEFINE2(fuse, , file, trace, "int", "char*");
SDT_PROBE_DEFINE2(fusefs, , file, trace, "int", "char*");

static counter_u64_t fuse_fh_count;

static int fuse_fh_count = 0;
SYSCTL_COUNTER_U64(_vfs_fusefs_stats, OID_AUTO, filehandle_count, CTLFLAG_RD,
&fuse_fh_count, "number of open FUSE filehandles");

SYSCTL_INT(_vfs_fusefs, OID_AUTO, filehandle_count, CTLFLAG_RD,
&fuse_fh_count, 0, "number of open FUSE filehandles");
/* Get the FUFH type for a particular access mode */
static inline fufh_type_t
fflags_2_fufh_type(int fflags)
{
if ((fflags & FREAD) && (fflags & FWRITE))
return FUFH_RDWR;
else if (fflags & (FWRITE))
return FUFH_WRONLY;
else if (fflags & (FREAD))
return FUFH_RDONLY;
else if (fflags & (FEXEC))
return FUFH_EXEC;
else
panic("FUSE: What kind of a flag is this (%x)?", fflags);
}

int
fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
fuse_filehandle_open(struct vnode *vp, int a_mode,
struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred)
{
struct fuse_dispatcher fdi;
struct fuse_open_in *foi;
struct fuse_open_out *foo;
fufh_type_t fufh_type;

int err = 0;
int oflags = 0;
int op = FUSE_OPEN;

if (fuse_filehandle_valid(vp, fufh_type)) {
panic("FUSE: filehandle_open called despite valid fufh (type=%d)",
fufh_type);
/* NOTREACHED */
}
/*
* Note that this means we are effectively FILTERING OUT open() flags.
*/
oflags = fuse_filehandle_xlate_to_oflags(fufh_type);
fufh_type = fflags_2_fufh_type(a_mode);
oflags = fufh_type_2_fflags(fufh_type);

if (vnode_isdir(vp)) {
op = FUSE_OPENDIR;
if (fufh_type != FUFH_RDONLY) {
SDT_PROBE2(fuse, , file, trace, 1,
"non-rdonly fh requested for a directory?");
printf("FUSE:non-rdonly fh requested for a directory?\n");
fufh_type = FUFH_RDONLY;
}
/* vn_open_vnode already rejects FWRITE on directories */
MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC);
}
fdisp_init(&fdi, sizeof(*foi));
fdisp_make_vp(&fdi, op, vp, td, cred);
@@ -133,7 +148,7 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
foi->flags = oflags;

if ((err = fdisp_wait_answ(&fdi))) {
SDT_PROBE2(fuse, , file, trace, 1,
SDT_PROBE2(fusefs, , file, trace, 1,
"OUCH ... daemon didn't give fh");
if (err == ENOENT) {
fuse_internal_vnode_disappear(vp);
@@ -142,18 +157,8 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
}
foo = fdi.answ;

fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh);

/*
* For WRONLY opens, force DIRECT_IO. This is necessary
* since writing a partial block through the buffer cache
* will result in a read of the block and that read won't
* be allowed by the WRONLY open.
*/
if (fufh_type == FUFH_WRONLY)
fuse_vnode_open(vp, foo->open_flags | FOPEN_DIRECT_IO, td);
else
fuse_vnode_open(vp, foo->open_flags, td);
fuse_filehandle_init(vp, fufh_type, fufhp, td, cred, foo);
fuse_vnode_open(vp, foo->open_flags, td);

out:
fdisp_destroy(&fdi);
@@ -161,23 +166,15 @@ out:
}

int
fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
struct thread *td, struct ucred *cred)
{
struct fuse_dispatcher fdi;
struct fuse_release_in *fri;
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh = NULL;

int err = 0;
int op = FUSE_RELEASE;

fufh = &(fvdat->fufh[fufh_type]);
if (!FUFH_IS_VALID(fufh)) {
panic("FUSE: filehandle_put called on invalid fufh (type=%d)",
fufh_type);
/* NOTREACHED */
}
if (fuse_isdeadfs(vp)) {
goto out;
}
@@ -187,96 +184,193 @@ fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
fdisp_make_vp(&fdi, op, vp, td, cred);
fri = fdi.indata;
fri->fh = fufh->fh_id;
fri->flags = fuse_filehandle_xlate_to_oflags(fufh_type);
fri->flags = fufh_type_2_fflags(fufh->fufh_type);
/*
* If the file has a POSIX lock then we're supposed to set lock_owner.
* If not, then lock_owner is undefined. So we may as well always set
* it.
*/
fri->lock_owner = td->td_proc->p_pid;

err = fdisp_wait_answ(&fdi);
fdisp_destroy(&fdi);

out:
atomic_subtract_acq_int(&fuse_fh_count, 1);
fufh->fh_id = (uint64_t)-1;
fufh->fh_type = FUFH_INVALID;
counter_u64_add(fuse_fh_count, -1);
LIST_REMOVE(fufh, next);
free(fufh, M_FUSE_FILEHANDLE);

return err;
}

int
fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;

fufh = &(fvdat->fufh[fufh_type]);
return FUFH_IS_VALID(fufh);
}

/*
* Check for a valid file handle, first the type requested, but if that
* isn't valid, try for FUFH_RDWR.
* Return the FUFH type that is valid or FUFH_INVALID if there are none.
* This is a variant of fuse_filehandle_vaild() analogous to
* fuse_filehandle_getrw().
* Return true if there is any file handle with the correct credentials and
* a fufh type that includes the provided one.
* A pid of 0 means "don't care"
*/
fufh_type_t
fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type)
bool
fuse_filehandle_validrw(struct vnode *vp, int mode,
struct ucred *cred, pid_t pid)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;
fufh_type_t fufh_type = fflags_2_fufh_type(mode);

/*
* Unlike fuse_filehandle_get, we want to search for a filehandle with
* the exact cred, and no fallback
*/
LIST_FOREACH(fufh, &fvdat->handles, next) {
if (fufh->fufh_type == fufh_type &&
fufh->uid == cred->cr_uid &&
fufh->gid == cred->cr_rgid &&
(pid == 0 || fufh->pid == pid))
return true;
}

if (fufh_type == FUFH_EXEC)
return false;

/* Fallback: find a RDWR list entry with the right cred */
LIST_FOREACH(fufh, &fvdat->handles, next) {
if (fufh->fufh_type == FUFH_RDWR &&
fufh->uid == cred->cr_uid &&
fufh->gid == cred->cr_rgid &&
(pid == 0 || fufh->pid == pid))
return true;
}

fufh = &fvdat->fufh[fufh_type];
if (FUFH_IS_VALID(fufh) != 0)
return (fufh_type);
fufh = &fvdat->fufh[FUFH_RDWR];
if (FUFH_IS_VALID(fufh) != 0)
return (FUFH_RDWR);
return (FUFH_INVALID);
return false;
}

int
fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp)
fuse_filehandle_get(struct vnode *vp, int fflag,
struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;
fufh_type_t fufh_type;

fufh_type = fflags_2_fufh_type(fflag);
/* cred can be NULL for in-kernel clients */
if (cred == NULL)
goto fallback;

LIST_FOREACH(fufh, &fvdat->handles, next) {
if (fufh->fufh_type == fufh_type &&
fufh->uid == cred->cr_uid &&
fufh->gid == cred->cr_rgid &&
(pid == 0 || fufh->pid == pid))
goto found;
}

fallback:
/* Fallback: find a list entry with the right flags */
LIST_FOREACH(fufh, &fvdat->handles, next) {
if (fufh->fufh_type == fufh_type)
break;
}

fufh = &(fvdat->fufh[fufh_type]);
if (!FUFH_IS_VALID(fufh))
if (fufh == NULL)
return EBADF;

found:
if (fufhp != NULL)
*fufhp = fufh;
return 0;
}

/* Get a file handle with any kind of flags */
int
fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp)
fuse_filehandle_get_anyflags(struct vnode *vp,
struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;

fufh = &(fvdat->fufh[fufh_type]);
if (!FUFH_IS_VALID(fufh)) {
fufh_type = FUFH_RDWR;
if (cred == NULL)
goto fallback;

LIST_FOREACH(fufh, &fvdat->handles, next) {
if (fufh->uid == cred->cr_uid &&
fufh->gid == cred->cr_rgid &&
(pid == 0 || fufh->pid == pid))
goto found;
}
return fuse_filehandle_get(vp, fufh_type, fufhp);

fallback:
/* Fallback: find any list entry */
fufh = LIST_FIRST(&fvdat->handles);

if (fufh == NULL)
return EBADF;

found:
if (fufhp != NULL)
*fufhp = fufh;
return 0;
}

int
fuse_filehandle_getrw(struct vnode *vp, int fflag,
struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
{
int err;

err = fuse_filehandle_get(vp, fflag, fufhp, cred, pid);
if (err)
err = fuse_filehandle_get(vp, FREAD | FWRITE, fufhp, cred, pid);
return err;
}

void
fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp, uint64_t fh_id)
struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred,
struct fuse_open_out *foo)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
struct fuse_filehandle *fufh;

fufh = &(fvdat->fufh[fufh_type]);
MPASS(!FUFH_IS_VALID(fufh));
fufh->fh_id = fh_id;
fufh->fh_type = fufh_type;
fufh = malloc(sizeof(struct fuse_filehandle), M_FUSE_FILEHANDLE,
M_WAITOK);
MPASS(fufh != NULL);
fufh->fh_id = foo->fh;
fufh->fufh_type = fufh_type;
fufh->gid = cred->cr_rgid;
fufh->uid = cred->cr_uid;
fufh->pid = td->td_proc->p_pid;
fufh->fuse_open_flags = foo->open_flags;
if (!FUFH_IS_VALID(fufh)) {
panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
}
LIST_INSERT_HEAD(&fvdat->handles, fufh, next);
if (fufhp != NULL)
*fufhp = fufh;

atomic_add_acq_int(&fuse_fh_count, 1);
counter_u64_add(fuse_fh_count, 1);

if (foo->open_flags & FOPEN_DIRECT_IO) {
ASSERT_VOP_ELOCKED(vp, __func__);
VTOFUD(vp)->flag |= FN_DIRECTIO;
fuse_io_invalbuf(vp, td);
} else {
if ((foo->open_flags & FOPEN_KEEP_CACHE) == 0)
fuse_io_invalbuf(vp, td);
VTOFUD(vp)->flag &= ~FN_DIRECTIO;
}

}

void
fuse_file_init(void)
{
fuse_fh_count = counter_u64_alloc(M_WAITOK);
}

void
fuse_file_destroy(void)
{
counter_u64_free(fuse_fh_count);
}

+ 122
- 44
sys/fs/fuse/fuse_file.h View File

@@ -32,6 +32,11 @@
*
* Copyright (C) 2005 Csaba Henk.
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems, LLC under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -66,52 +71,115 @@
#include <sys/mman.h>
#include <sys/vnode.h>

/*
* The fufh type is the access mode of the fuse file handle. It's the portion
* of the open(2) flags related to permission.
*/
typedef enum fufh_type {
FUFH_INVALID = -1,
FUFH_RDONLY = 0,
FUFH_WRONLY = 1,
FUFH_RDWR = 2,
FUFH_MAXTYPE = 3,
FUFH_RDONLY = O_RDONLY,
FUFH_WRONLY = O_WRONLY,
FUFH_RDWR = O_RDWR,
FUFH_EXEC = O_EXEC,
} fufh_type_t;
_Static_assert(FUFH_RDONLY == O_RDONLY, "RDONLY");
_Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY");
_Static_assert(FUFH_RDWR == O_RDWR, "RDWR");

/*
* FUSE File Handles
*
* The FUSE protocol says that a server may assign a unique 64-bit file handle
* every time that a file is opened. Effectively, that's once for each file
* descriptor.
*
* Unfortunately, the VFS doesn't help us here. VOPs don't have a
* struct file* argument. fileops do, but many syscalls bypass the fileops
* layer and go straight to a vnode. Some, like writing from cache, can't
* track a file handle even in theory. The entire concept of the file handle
* is a product of FUSE's Linux origins; Linux lacks vnodes and almost every
* file system operation takes a struct file* argument.
*
* Since FreeBSD's VFS is more file descriptor-agnostic, we must store FUSE
* filehandles in the vnode. One option would be to only store a single file
* handle and never open FUSE files concurrently. That's what NetBSD does.
* But that violates FUSE's security model. FUSE expects the server to do all
* authorization (except when mounted with -o default_permissions). In order
* to do that, the server needs us to send FUSE_OPEN every time somebody opens
* a new file descriptor.
*
* Another option would be to never open FUSE files concurrently, but send a
* FUSE_ACCESS prior to every open after the first. That would give the server
* the opportunity to authorize the access. Unfortunately, the FUSE protocol
* makes ACCESS optional. File systems that don't implement it are assumed to
* authorize everything. A survey of 32 fuse file systems showed that only 14
* implemented access. Among the laggards were a few that really ought to be
* doing server-side authorization.
*
* So we do something hacky, similar to what OpenBSD, Illumos, and OSXFuse do.
* we store a list of file handles, one for each combination of vnode, uid,
* gid, pid, and access mode. When opening a file, we first check whether
* there's already a matching file handle. If so, we reuse it. If not, we
* send FUSE_OPEN and create a new file handle. That minimizes the number of
* open file handles while still allowing the server to authorize stuff.
*
* VOPs that need a file handle search through the list for a close match.
* They can't be guaranteed of finding an exact match because, for example, a
* process may have changed its UID since opening the file. Also, most VOPs
* don't know exactly what permission they need. Is O_RDWR required or is
* O_RDONLY good enough? So the file handle we end up using may not be exactly
* the one we're supposed to use with that file descriptor. But if the FUSE
* file system isn't too picky, it will work. (FWIW even Linux sometimes
* guesses the file handle, during writes from cache or most SETATTR
* operations).
*
* I suspect this mess is part of the reason why neither NFS nor 9P have an
* equivalent of FUSE file handles.
*/
struct fuse_filehandle {
LIST_ENTRY(fuse_filehandle) next;

/* The filehandle returned by FUSE_OPEN */
uint64_t fh_id;
fufh_type_t fh_type;
};

#define FUFH_IS_VALID(f) ((f)->fh_type != FUFH_INVALID)
/*
* flags returned by FUSE_OPEN
* Supported flags: FOPEN_DIRECT_IO, FOPEN_KEEP_CACHE
* Unsupported:
* FOPEN_NONSEEKABLE: Adding support would require a new per-file
* or per-vnode attribute, which would have to be checked by
* kern_lseek (and others) for every file system. The benefit is
* dubious, since I'm unaware of any file systems in ports that use
* this flag.
*/
uint32_t fuse_open_flags;

static inline fufh_type_t
fuse_filehandle_xlate_from_mmap(int fflags)
{
if (fflags & (PROT_READ | PROT_WRITE))
return FUFH_RDWR;
else if (fflags & (PROT_WRITE))
return FUFH_WRONLY;
else if ((fflags & PROT_READ) || (fflags & PROT_EXEC))
return FUFH_RDONLY;
else
return FUFH_INVALID;
}
/* The access mode of the file handle */
fufh_type_t fufh_type;

static inline fufh_type_t
fuse_filehandle_xlate_from_fflags(int fflags)
{
if ((fflags & FREAD) && (fflags & FWRITE))
return FUFH_RDWR;
else if (fflags & (FWRITE))
return FUFH_WRONLY;
else if (fflags & (FREAD))
return FUFH_RDONLY;
else
panic("FUSE: What kind of a flag is this (%x)?", fflags);
}
/* Credentials used to open the file */
gid_t gid;
pid_t pid;
uid_t uid;
};

#define FUFH_IS_VALID(f) ((f)->fufh_type != FUFH_INVALID)

/*
* Get the flags to use for FUSE_CREATE, FUSE_OPEN and FUSE_RELEASE
*
* These are supposed to be the same as the flags argument to open(2).
* However, since we can't reliably associate a fuse_filehandle with a specific
* file descriptor it would would be dangerous to include anything more than
* the access mode flags. For example, suppose we open a file twice, once with
* O_APPEND and once without. Then the user pwrite(2)s to offset using the
* second file descriptor. If fusefs uses the first file handle, then the
* server may append the write to the end of the file rather than at offset 0.
* To prevent problems like this, we only ever send the portion of flags
* related to access mode.
*
* It's essential to send that portion, because FUSE uses it for server-side
* authorization.
*/
static inline int
fuse_filehandle_xlate_to_oflags(fufh_type_t type)
fufh_type_2_fflags(fufh_type_t type)
{
int oflags = -1;

@@ -119,6 +187,7 @@ fuse_filehandle_xlate_to_oflags(fufh_type_t type)
case FUFH_RDONLY:
case FUFH_WRONLY:
case FUFH_RDWR:
case FUFH_EXEC:
oflags = type;
break;
default:
@@ -128,19 +197,28 @@ fuse_filehandle_xlate_to_oflags(fufh_type_t type)
return oflags;
}

int fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type);
fufh_type_t fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type);
int fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp);
int fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp);
bool fuse_filehandle_validrw(struct vnode *vp, int mode,
struct ucred *cred, pid_t pid);
int fuse_filehandle_get(struct vnode *vp, int fflag,
struct fuse_filehandle **fufhp, struct ucred *cred,
pid_t pid);
int fuse_filehandle_get_anyflags(struct vnode *vp,
struct fuse_filehandle **fufhp, struct ucred *cred,
pid_t pid);
int fuse_filehandle_getrw(struct vnode *vp, int fflag,
struct fuse_filehandle **fufhp, struct ucred *cred,
pid_t pid);

void fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp, uint64_t fh_id);
int fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
struct fuse_filehandle **fufhp, struct thread *td,
struct ucred *cred, struct fuse_open_out *foo);
int fuse_filehandle_open(struct vnode *vp, int mode,
struct fuse_filehandle **fufhp, struct thread *td,
struct ucred *cred);
int fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type,
int fuse_filehandle_close(struct vnode *vp, struct fuse_filehandle *fufh,
struct thread *td, struct ucred *cred);

void fuse_file_init(void);
void fuse_file_destroy(void);

#endif /* _FUSE_FILE_H_ */

+ 687
- 165
sys/fs/fuse/fuse_internal.c
File diff suppressed because it is too large
View File


+ 89
- 37
sys/fs/fuse/fuse_internal.h View File

@@ -32,6 +32,11 @@
*
* Copyright (C) 2005 Csaba Henk.
* All rights reserved.
*
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by BFF Storage Systems, LLC under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -61,6 +66,8 @@
#define _FUSE_INTERNAL_H_

#include <sys/types.h>
#include <sys/counter.h>
#include <sys/limits.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/vnode.h>
@@ -68,6 +75,9 @@
#include "fuse_ipc.h"
#include "fuse_node.h"

extern counter_u64_t fuse_lookup_cache_hits;
extern counter_u64_t fuse_lookup_cache_misses;

static inline bool
vfs_isrdonly(struct mount *mp)
{
@@ -80,12 +90,6 @@ vnode_mount(struct vnode *vp)
return (vp->v_mount);
}

static inline bool
vnode_mountedhere(struct vnode *vp)
{
return (vp->v_mountedhere != NULL);
}

static inline enum vtype
vnode_vtype(struct vnode *vp)
{
@@ -134,12 +138,6 @@ uio_setoffset(struct uio *uio, off_t offset)
uio->uio_offset = offset;
}

static inline void
uio_setresid(struct uio *uio, ssize_t resid)
{
uio->uio_resid = resid;
}

/* miscellaneous */

static inline bool
@@ -156,25 +154,57 @@ fuse_iosize(struct vnode *vp)
return (vp->v_mount->mnt_stat.f_iosize);
}

/* access */

#define FVP_ACCESS_NOOP 0x01
/*
* Make a cacheable timeout in bintime format value based on a fuse_attr_out
* response
*/
static inline void
fuse_validity_2_bintime(uint64_t attr_valid, uint32_t attr_valid_nsec,
struct bintime *timeout)
{
struct timespec now, duration, timeout_ts;

getnanouptime(&now);
/* "+ 2" is the bound of attr_valid_nsec + now.tv_nsec */
/* Why oh why isn't there a TIME_MAX defined? */
if (attr_valid >= INT_MAX || attr_valid + now.tv_sec + 2 >= INT_MAX) {
timeout->sec = INT_MAX;
} else {
duration.tv_sec = attr_valid;
duration.tv_nsec = attr_valid_nsec;
timespecadd(&duration, &now, &timeout_ts);
timespec2bintime(&timeout_ts, timeout);
}
}

#define FACCESS_VA_VALID 0x01
#define FACCESS_DO_ACCESS 0x02
#define FACCESS_STICKY 0x04
#define FACCESS_CHOWN 0x08
#define FACCESS_NOCHECKSPY 0x10
#define FACCESS_SETGID 0x12
/*
* Make a cacheable timeout value in timespec format based on the fuse_entry_out
* response
*/
static inline void
fuse_validity_2_timespec(const struct fuse_entry_out *feo,
struct timespec *timeout)
{
struct timespec duration, now;

getnanouptime(&now);
/* "+ 2" is the bound of entry_valid_nsec + now.tv_nsec */
if (feo->entry_valid >= INT_MAX ||
feo->entry_valid + now.tv_sec + 2 >= INT_MAX) {
timeout->tv_sec = INT_MAX;
} else {
duration.tv_sec = feo->entry_valid;
duration.tv_nsec = feo->entry_valid_nsec;
timespecadd(&duration, &now, timeout);
}
}

#define FACCESS_XQUERIES (FACCESS_STICKY | FACCESS_CHOWN | FACCESS_SETGID)

struct fuse_access_param {
uid_t xuid;
gid_t xgid;
uint32_t facc_flags;
};
/* VFS ops */
int
fuse_internal_get_cached_vnode(struct mount*, ino_t, int, struct vnode**);

/* access */
static inline int
fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
{
@@ -189,8 +219,8 @@ fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
return (EPERM);
}

int fuse_internal_access(struct vnode *vp, mode_t mode,
struct fuse_access_param *facp, struct thread *td, struct ucred *cred);
int fuse_internal_access(struct vnode *vp, accmode_t mode,
struct thread *td, struct ucred *cred);

/* attributes */
void fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,
@@ -198,20 +228,34 @@ void fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,

/* fsync */

int fuse_internal_fsync(struct vnode *vp, struct thread *td,
struct ucred *cred, struct fuse_filehandle *fufh);
int fuse_internal_fsync(struct vnode *vp, struct thread *td, int waitfor,
bool datasync);
int fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);

/* readdir */
/* getattr */
int fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
struct ucred *cred, struct thread *td);
int fuse_internal_getattr(struct vnode *vp, struct vattr *vap,
struct ucred *cred, struct thread *td);

/* asynchronous invalidation */
int fuse_internal_invalidate_entry(struct mount *mp, struct uio *uio);
int fuse_internal_invalidate_inode(struct mount *mp, struct uio *uio);

/* mknod */
int fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, struct vattr *vap);

/* readdir */
struct pseudo_dirent {
uint32_t d_namlen;
};

int fuse_internal_readdir(struct vnode *vp, struct uio *uio,
struct fuse_filehandle *fufh, struct fuse_iov *cookediov);
int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize,
void *buf, size_t bufsize, void *param);
int fuse_internal_readdir(struct vnode *vp, struct uio *uio, off_t startoff,