lib/ffi/libfuse/fuse_conn_info.rb in ffi-libfuse-0.0.1.rctest12 vs lib/ffi/libfuse/fuse_conn_info.rb in ffi-libfuse-0.1.0.rc20220550
- old
+ new
@@ -1,65 +1,63 @@
# frozen_string_literal: true
require_relative 'fuse_version'
require_relative '../accessors'
+require_relative '../boolean_int'
module FFI
# Ruby FFI Binding for [libfuse](https://github.com/libfuse/libfuse)
module Libfuse
- # These are constants in fuse_common.h but defined like bitmask
- #
- # FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
- # FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
- # FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
- # FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
- # FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
- # FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
- # FUSE_CAP_SPLICE_WRITE: ability to use splice() to write to the fuse device
- # FUSE_CAP_SPLICE_MOVE: ability to move data to the fuse device with splice()
- # FUSE_CAP_SPLICE_READ: ability to use splice() to read from the fuse device
- # FUSE_CAP_FLOCK_LOCKS: ?
- # FUSE_CAP_IOCTL_DIR: ioctl support on directories
+ capabilities =
+ if FUSE_MAJOR_VERSION >= 3
+ %i[
+ async_read
+ posix_locks
+ atomic_o_trunc
+ export_support
+ dont_mask
+ splice_write
+ splice_move
+ splice_read
+ flock_locks
+ ioctl_dir
+ auto_inval_data
+ readdirplus
+ readdirplus_auto
+ async_dio
+ writeback_cache
+ no_open_support
+ parallel_dirops
+ posix_acl
+ handle_killpriv
+ cache_symlinks
+ no_opendir_support
+ explicit_inval_data
+ ]
+ else
+ %i[
+ async_readcap
+ posix_locks
+ atomic_o_trunc
+ export_support
+ big_writes
+ dont_mask
+ splice_write
+ splice_move
+ splice_read
+ flock_locks
+ ioctl_dir
+ ]
+ end
- # FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
- # FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
- # FUSE_IOCTL_RETRY: retry with new iovecs
- # FUSE_IOCTL_DIR: is a directory
- bitmask :fuse_ioctl, %i[compat unrestricted retry dir]
+ bitmask :fuse_cap, capabilities
- # #define FUSE_CAP_ASYNC_READ (1 << 0)
- # #define FUSE_CAP_POSIX_LOCKS (1 << 1)
- # #define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
- # #define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
- # #define FUSE_CAP_BIG_WRITES (1 << 5)
- # #define FUSE_CAP_DONT_MASK (1 << 6)
- # #define FUSE_CAP_SPLICE_WRITE (1 << 7)
- # #define FUSE_CAP_SPLICE_MOVE (1 << 8)
- # #define FUSE_CAP_SPLICE_READ (1 << 9)
- # #define FUSE_CAP_FLOCK_LOCKS (1 << 10)
- # #define FUSE_CAP_IOCTL_DIR (1 << 11)
-
- if FUSE_MAJOR_VERSION >= 3
- bitmask :fuse_cap, %i[
- async_read posix_locks atomic_o_trunc export_support
- big_writes dont_mask splice_write splice_move splice_read
- flock_locks ioctl_dir
- ]
- else
- bitmask :fuse_cap, %i[
- async_read posix_locks atomic_o_trunc export_support
- dont_mask splice_write splice_move splice_read flock_locks ioctl_dir
- auto_inval_data readdirplus readdirplus_auto async_dio writeback_cache no_open_support
- parallel_dirops posix_acl handle_killpriv explicit_inval_data
- ]
- end
#
# Connection information
#
- # Some of the elements are read-write, these can be changed to
- # indicate the value requested by the filesystem. The requested
- # value must usually be smaller than the indicated value.
+ # Some of the elements are read-write, these can be changed to indicate the value requested by the filesystem. The
+ # requested value must usually be smaller than the indicated value.
#
# @see FuseOperations#init
class FuseConnInfo < FFI::Struct
fuse_layout =
if FUSE_MAJOR_VERSION >= 3
@@ -67,85 +65,22 @@
proto_major: :uint,
proto_minor: :uint,
max_write: :uint,
max_read: :uint,
max_readahead: :uint,
- #
- # Capability flags that the kernel supports (read-only)
- #
capable: :fuse_cap,
- #
- # Capability flags that the filesystem wants to enable.
- #
- # libfuse attempts to initialize this field with
- # reasonable default values before calling the init() handler.
- #
want: :fuse_cap,
- #
- # Maximum number of pending "background" requests. A
- # background request is any type of request for which the
- # total number is not limited by other means. As of kernel
- # 4.8, only two types of requests fall into this category:
- #
- # 1. Read-ahead requests
- # 2. Asynchronous direct I/O requests
- #
- # Read-ahead requests are generated (if max_readahead is
- # non-zero) by the kernel to preemptively fill its caches
- # when it anticipates that userspace will soon read more
- # data.
- #
- # Asynchronous direct I/O requests are generated if
- # FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
- # direct I/O request. In this case the kernel will internally
- # split it up into multiple smaller requests and submit them
- # to the filesystem concurrently.
- #
- # Note that the following requests are *not* background
- # requests: writeback requests (limited by the kernel's
- # flusher algorithm), regular (i.e., synchronous and
- # buffered) userspace read/write requests (limited to one per
- # thread), asynchronous read requests (Linux's io_submit(2)
- # call actually blocks, so these are also limited to one per
- # thread).
- #
max_background: :uint,
- #
- # Kernel congestion threshold parameter. If the number of pending
- # background requests exceeds this number, the FUSE kernel module will
- # mark the filesystem as "congested". This instructs the kernel to
- # expect that queued requests will take some time to complete, and to
- # adjust its algorithms accordingly (e.g. by putting a waiting thread
- # to sleep instead of using a busy-loop).
- #
congestion_threshold: :uint,
- #
- # When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
- # for updating mtime and ctime when write requests are received. The
- # updated values are passed to the filesystem with setattr() requests.
- # However, if the filesystem does not support the full resolution of
- # the kernel timestamps (nanoseconds), the mtime and ctime values used
- # by kernel and filesystem will differ (and result in an apparent
- # change of times after a cache flush).
- #
- # To prevent this problem, this variable can be used to inform the
- # kernel about the timestamp granularity supported by the file-system.
- # The value should be power of 10. The default is 1, i.e. full
- # nano-second resolution. Filesystems supporting only second resolution
- # should set this to 1000000000.
- #
time_gran: :uint,
- #
- # For future use.
- #
- reserved: [:uint, 22]
+ reserved: [:uint, 22] # for future use
}
else
{
proto_major: :uint,
proto_minor: :uint,
- async_read: :uint, # This slot is max_read in Fuse 3
+ async_read: :bool_int, # long deprecated
max_write: :uint,
max_readahead: :uint,
capable: :fuse_cap,
want: :fuse_cap,
max_background: :uint,
@@ -157,55 +92,296 @@
include(FFI::Accessors)
layout fuse_layout
# @!attribute [r] proto_major
- # @return [Integer] Major version of the protocol (read-only)
+ # @return [Integer] Major version of the protocol (read-only)
# @!attribute [r] proto_minor
- # @return [Integer] Minor version of the protocol (read-only)
+ # @return [Integer] Minor version of the protocol (read-only)
ffi_attr_reader :proto_major, :proto_minor
- # Is asynchronous read supported (read-write)
- ffi_attr_accessor :async_read if FUSE_MAJOR_VERSION < 3
-
# @!attribute [rw] max_read
- # @return [Integer] Maximum size of read requests.
+ # @return [Integer] Maximum size of read requests.
#
- # A value of zero indicates no limit. However, even if the filesystem does not specify a limit, the maximum size
- # of read requests will still be limited by the kernel.
+ # A value of zero indicates no limit. However, even if the filesystem does not specify a limit, the maximum size
+ # of read requests will still be limited by the kernel.
#
- # @note For the time being, the maximum size of read requests must be set both here *and* passed to
- # using the ``-o max_read=<n>`` mount option. At some point in the future, specifying the mount
- # option will no longer be necessary.
+ # @note For the time being, the maximum size of read requests must be set both here *and* passed to
+ # using the ``-o max_read=<n>`` mount option. At some point in the future, specifying the mount
+ # option will no longer be necessary.
+ # @since Fuse3
ffi_attr_accessor :max_read if FUSE_MAJOR_VERSION >= 3
# @!attribute [rw] max_write
# @return [Integer] Maximum size of the write buffer
# @!attribute [rw] max_readahead
# @return [Integer] Maximum size of the readahead buffer
ffi_attr_accessor :max_write, :max_readahead
- # Capability flags that kernel supports
+ # @!attribute [r] capable
+ # Capability flags supported by kernel fuse module
+ #
+ # * `:async_read` Indicates that the filesystem supports asynchronous read requests.
+ #
+ # If this capability is not requested/available, the kernel will ensure that there is at most one pending read
+ # request per file-handle at any time, and will attempt to order read requests by increasing offset.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:posix_locks` Indicates that the filesystem supports "remote" locking.
+ #
+ # This feature is enabled by default when supported by the kernel,
+ # and if getlk() and setlk() handlers are implemented.
+ #
+ # * `:atomic_o_trunc` Indicates that the filesystem supports the O_TRUNC open flag.
+ #
+ # If disabled, and an application specifies O_TRUNC, fuse first calls truncate() and then open() with O_TRUNC
+ # filtered out.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:export_support` Indicates that the filesystem supports lookups of "." and "..".
+ #
+ # This feature is disabled by default.
+ #
+ # * `:big_writes` Indicates the filesystem can handle write size larger than 4kB.
+ #
+ # Removed in Fuse3 where is now always active. Filesystems that want to limit the size of write requests should
+ # use the {#max_write} option instead.
+ #
+ # * `:dont_mask` Indicates that the kernel should not apply the umask to the file mode on create operations.
+ #
+ # This feature is disabled by default.
+ #
+ # * `:splice_write` Indicates that libfuse should try to use splice() when writing to the fuse device.
+ #
+ # This may improve performance. This feature is disabled by default.
+ #
+ # * `:splice_move` Indicates that libfuse should try to move pages instead of copying when writing to / reading
+ # from the fuse device.
+ #
+ # This may improve performance. This feature is disabled by default.
+ #
+ # * `:splice_read` Indicates that libfuse should try to use splice() when reading from the fuse device.
+ #
+ # This may improve performance. This feature is enabled by default when supported by the kernel and
+ # if the filesystem implements a write_buf() handler.
+ #
+ # * `:flock_locks` If set, the calls to flock(2) will be emulated using POSIX locks and must then be handled by
+ # the filesystem's :flock handler.
+ #
+ # If not set, flock(2) calls will be handled by the FUSE kernel module internally (so any access that does not go
+ # through the kernel cannot be taken into account).
+ #
+ # This feature is enabled by default when supported by the kernel and if the filesystem implements a flock()
+ # handler.
+ #
+ # * `:ioctl_dir` Indicates that the filesystem supports ioctl's on directories.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * :`auto_inval_data`
+ #
+ # Traditionally, while a file is open the FUSE kernel module only asks the filesystem for an update of the file's
+ # attributes when a client attempts to read beyond EOF. This is unsuitable for e.g. network filesystems, where
+ # the file contents may change without the kernel knowing about it.
+ #
+ # If this flag is set, FUSE will check the validity of the attributes on every read. If the attributes are no
+ # longer valid (i.e., if the *attr_timeout* passed to fuse_reply_attr() or set in `struct fuse_entry_param` has
+ # passed), it will first issue a `getattr` request. If the new mtime differs from the previous value, any cached
+ # file *contents* will be invalidated as well.
+ #
+ # This flag should always be set when available. If all file changes go through the kernel, *attr_timeout* should
+ # be set to a very large number to avoid unnecessary getattr() calls.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:readdirplus` Indicates that the filesystem supports readdirplus.
+ #
+ # This feature is enabled by default when supported by the kernel and if the filesystem implements the
+ # readdirplus() handler
+ #
+ # * `:readdirplus_auto` Indicates that the filesystem supports adaptive readdirplus.
+ #
+ # If :readdirplus is not set, this flag has no effect.
+ #
+ # If :readdirplus is set and this flag is not set, the kernel will always issue readdirplus() requests to
+ # retrieve directory contents.
+ #
+ # If :readdirplus is set and this flag is set, the kernel will issue both readdir() and readdirplus() requests,
+ # depending on how much information is expected to be required.
+ #
+ # As of Linux 4.20, the algorithm is as follows: when userspace starts to read directory entries, issue a
+ # :reaadirplus request to the filesystem. If any entry attributes have been looked up by the time userspace
+ # requests the next batch of entries continue with :reaadirplus, otherwise switch to plain :readdir. This will
+ # result in eg plain "ls" triggering :reaadirplus first then :readdir after that because it doesn't do lookups.
+ # "ls -l" should result in all :reaadirplus, except if dentries are already cached.
+ #
+ # This feature is enabled by default when supported by the kernel and if the filesystem implements both a
+ # readdirplus() and a readdir() handler.
+ #
+ # **Note** The high-level operations mix :readdir and :readdirplus into one operation
+ # with flags to indicate behaviour. As such for the purposes of above :readdirplus is always implemented!
+ #
+ # * `:async_dio` Indicates that the filesystem supports asynchronous direct I/O submission.
+ #
+ # If this capability is not requested/available, the kernel will ensure that there is at most one pending read
+ # and one pending write request per direct I/O file-handle at any time.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:writeback_cache` Indicates that writeback caching should be enabled.
+ #
+ # This means that individual write request may be buffered and merged in the kernel before they are send to the
+ # filesystem.
+ #
+ # This feature is disabled by default.
+ #
+ # * `:no_open_support` Indicates support for zero-message opens.
+ #
+ # If this flag is set in the `capable` field of the `fuse_conn_info` structure, then the filesystem may return
+ # `ENOSYS` from the open() handler to indicate success. Further attempts to open files will be handled in the
+ # kernel. (If this flag is not set, returning ENOSYS will be treated as an error and signaled to the caller).
+ #
+ # Setting (or unsetting) this flag in the `want` field has *no effect*.
+ #
+ # * `:parallel_dirops` Indicates support for parallel directory operations.
+ #
+ # If this flag is unset, the FUSE kernel module will ensure that lookup() and readdir() requests are never issued
+ # concurrently for the same directory.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:posix_acl` Indicates support for POSIX ACLs.
+ #
+ # If this feature is enabled, the kernel will cache and have responsibility for enforcing ACLs. ACL will be
+ # stored as xattrs and passed to userspace, which is responsible for updating the ACLs in the filesystem, keeping
+ # the file mode in sync with the ACL, and ensuring inheritance of default ACLs when new filesystem nodes are
+ # created. Note that this requires that the file system is able to parse and interpret the xattr representation
+ # of ACLs.
+ #
+ # Enabling this feature implicitly turns on the ``default_permissions`` mount option (even if it was not passed
+ # to mount(2)).
+ #
+ # This feature is disabled by default.
+ #
+ # * `:handle_killpriv` Indicates that the filesystem is responsible for unsetting setuid and setgid bits when a
+ # file is written, truncated, or its owner is changed.
+ #
+ # This feature is enabled by default when supported by the kernel.
+ #
+ # * `:cache_symlinks` Indicates that the kernel supports caching symlinks in its page cache.
+ #
+ # When this feature is enabled, symlink targets are saved in the page cache. You can invalidate a cached link by
+ # calling: `fuse_lowlevel_notify_inval_inode(se, ino, 0, 0);`
+ #
+ # This feature is disabled by default.
+ #
+ # * `:no_opendir_support` Indicates support for zero-message opendirs.
+ #
+ # If this flag is set then the filesystem may return `ENOSYS` from the opendir() handler to indicate success.
+ # Further opendir and releasedir messages will be handled in the kernel. (If this flag is not set, returning
+ # ENOSYS will be treated as an error and signalled to the caller.)
+ #
+ # Setting (or unsetting) this flag in the `want` field has *no effect*.
+ #
+ # * `:explicit_inval_data` Indicates support for invalidating cached pages only on explicit request.
+ #
+ # If this flag is set in the `capable` field of the `fuse_conn_info` structure, then the FUSE kernel module
+ # supports invalidating cached pages only on explicit request by the filesystem through
+ # fuse_lowlevel_notify_inval_inode() or fuse_invalidate_path().
+ #
+ # By setting this flag in the `want` field of the `fuse_conn_info` structure, the filesystem is responsible for
+ # invalidating cached pages through explicit requests to the kernel.
+ #
+ # Note that setting this flag does not prevent the cached pages from being flushed by OS itself and/or through
+ # user actions.
+ #
+ # Note that if both :explicit_inval_data and :auto_inval_data are set then :auto_inval_data takes precedence.
+ #
+ # This feature is disabled by default.
+ # @return [Array<Symbol>]
ffi_attr_reader :capable
- # Is capable of all of these FUSE_CAPs
- def capable?(*of)
- of.all? { |c| self[:capable].include?(c) }
+ # @param [Array<Symbol>] capabilities
+ # @return [Boolean] true if {#capable} of all capabilities
+ def capable?(*capabilities)
+ capabilities.all? { |c| self[:capable].include?(c) }
end
- # Capability flags that the filesystem wants
- ffi_attr_accessor :want
+ # @attribute [rw] want
+ # @overload want()
+ # Capability flags that the filesystem wants to enable.
+ #
+ # libfuse attempts to initialize this field with reasonable default values before calling the :init handler.
+ #
+ # @overload want(*capabiities)
+ # Add to the capabilities wanted by the filesystem
+ # @param [Array<Symbol>] capabilities list to add
+ # @overload want(**capabilities)
+ # @param [Hash<Symbol,Boolean>] capabilities map of capability names to whether they are explicitly wanted
+ # or unwanted
+ # @return [Array<Symbol>]
+ # @see capable
+ ffi_attr_reader(:want, simple: false) do |*caps, **h|
+ next self[:want] if caps.empty? && h.empty?
- # Maximum number of backgrounded requests
+ h.merge!(caps.pop) if caps.last.is_a?(Hash)
+ add, del = h.keys.partition { |c| h[c] }
+ self[:want] = (self[:want] - del + add + caps)
+ end
+
+ # @param [Array<Symbol>] capabilities
+ # @return [Boolean] true if all capabilities are wanted
+ def wanted?(*capabilities)
+ capabilities.all? { |c| self[:want].include?(c) }
+ end
+
+ # @!attribute [rw] max_background
+ # @return [Integer] Maximum number of pending "background" requests.
+ #
+ # A background request is any type of request for which the total number is not limited by other means. As of
+ # kernel 4.8, only two types of requests fall into this category:
+ #
+ # 1. Read-ahead requests
+ # 2. Asynchronous direct I/O requests
+ #
+ # Read-ahead requests are generated (if max_readahead is non-zero) by the kernel to preemptively fill its
+ # caches when it anticipates that userspace will soon read more data.
+ #
+ # Asynchronous direct I/O requests are generated if :async_dio is enabled and userspace submits a large
+ # direct I/O request. In this case the kernel will internally split it up into multiple smaller requests and
+ # submit them to the filesystem concurrently.
+ #
+ # Note that the following requests are *not* background requests: writeback requests (limited by the kernel's
+ # flusher algorithm), regular (i.e., synchronous and buffered) userspace read/write requests (limited to one per
+ # thread), asynchronous read requests (Linux's io_submit(2) call actually blocks, so these are also limited to one
+ # per thread).
ffi_attr_accessor :max_background
- # Kernel congestion threshold parameter
- ffi_attr_reader :congestion_threshold
+ # @!attribute [rw] congestion_threshold
+ # @return [Integer] Kernel congestion threshold parameter
+ #
+ # f the number of pending background requests exceeds this number, the FUSE kernel module will mark the filesystem
+ # as "congested". This instructs the kernel to expect that queued requests will take some time to complete, and to
+ # adjust its algorithms accordingly (e.g. by putting a waiting thread to sleep instead of using a busy-loop).
+ ffi_attr_accessor :congestion_threshold
+ # @!attribute [rw] time_gran
+ # @return [Integer] timestamp granularity supported by the file-system
+ #
+ # When :writeback_cache is enabled, the kernel is responsible for updating mtime and ctime when write requests are
+ # received. The updated values are passed to the filesystem with setattr() requests. However, if the filesystem
+ # does not support the full resolution of the kernel timestamps (nanoseconds), the mtime and ctime values used by
+ # kernel and filesystem will differ (and result in an apparent change of times after a cache flush).
+ #
+ # To prevent this problem, this variable can be used to inform the kernel about the timestamp granularity
+ # supported by the file-system. The value should be power of 10. The default is 1, i.e. full nano-second
+ # resolution. Filesystems supporting only second resolution should set this to 1000000000.
ffi_attr_accessor :time_gran if FUSE_MAJOR_VERSION >= 3
end
end
end