aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/standard-headers/linux/fuse.h11
-rw-r--r--tests/acceptance/boot_linux.py13
-rw-r--r--tests/acceptance/virtiofs_submounts.py289
-rw-r--r--tests/acceptance/virtiofs_submounts.py.data/cleanup.sh46
-rw-r--r--tests/acceptance/virtiofs_submounts.py.data/guest-cleanup.sh30
-rw-r--r--tests/acceptance/virtiofs_submounts.py.data/guest.sh138
-rw-r--r--tests/acceptance/virtiofs_submounts.py.data/host.sh127
-rw-r--r--tools/virtiofsd/fuse_common.h8
-rw-r--r--tools/virtiofsd/fuse_lowlevel.c34
-rw-r--r--tools/virtiofsd/fuse_lowlevel.h20
-rw-r--r--tools/virtiofsd/helper.c1
-rw-r--r--tools/virtiofsd/passthrough_ll.c84
12 files changed, 21 insertions, 780 deletions
diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h
index 7dd7a3b..f4df0a4 100644
--- a/include/standard-headers/linux/fuse.h
+++ b/include/standard-headers/linux/fuse.h
@@ -227,7 +227,7 @@ struct fuse_attr {
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
- uint32_t flags;
+ uint32_t padding;
};
struct fuse_kstatfs {
@@ -310,7 +310,6 @@ struct fuse_file_lock {
* FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
* FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request
* FUSE_MAP_ALIGNMENT: map_alignment field is valid
- * FUSE_ATTR_FLAGS: fuse_attr.flags is present and valid
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -339,7 +338,6 @@ struct fuse_file_lock {
#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
#define FUSE_MAP_ALIGNMENT (1 << 26)
-#define FUSE_ATTR_FLAGS (1 << 27)
/**
* CUSE INIT request/reply flags
@@ -415,13 +413,6 @@ struct fuse_file_lock {
*/
#define FUSE_FSYNC_FDATASYNC (1 << 0)
-/**
- * fuse_attr flags
- *
- * FUSE_ATTR_SUBMOUNT: File/directory is a submount point
- */
-#define FUSE_ATTR_SUBMOUNT (1 << 0)
-
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py
index 1da4a53..c743e23 100644
--- a/tests/acceptance/boot_linux.py
+++ b/tests/acceptance/boot_linux.py
@@ -57,7 +57,7 @@ class BootLinuxBase(Test):
self.cancel('Failed to download/prepare boot image')
return boot.path
- def download_cloudinit(self, ssh_pubkey=None):
+ def download_cloudinit(self):
self.log.info('Preparing cloudinit image')
try:
cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
@@ -67,8 +67,7 @@ class BootLinuxBase(Test):
password='password',
# QEMU's hard coded usermode router address
phone_home_host='10.0.2.2',
- phone_home_port=self.phone_home_port,
- authorized_key=ssh_pubkey)
+ phone_home_port=self.phone_home_port)
except Exception:
self.cancel('Failed to prepared cloudinit image')
return cloudinit_iso
@@ -81,19 +80,19 @@ class BootLinux(BootLinuxBase):
timeout = 900
chksum = None
- def setUp(self, ssh_pubkey=None):
+ def setUp(self):
super(BootLinux, self).setUp()
self.vm.add_args('-smp', '2')
self.vm.add_args('-m', '1024')
self.prepare_boot()
- self.prepare_cloudinit(ssh_pubkey)
+ self.prepare_cloudinit()
def prepare_boot(self):
path = self.download_boot()
self.vm.add_args('-drive', 'file=%s' % path)
- def prepare_cloudinit(self, ssh_pubkey=None):
- cloudinit_iso = self.download_cloudinit(ssh_pubkey)
+ def prepare_cloudinit(self):
+ cloudinit_iso = self.download_cloudinit()
self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
def launch_and_wait(self):
diff --git a/tests/acceptance/virtiofs_submounts.py b/tests/acceptance/virtiofs_submounts.py
deleted file mode 100644
index 8b207b3..0000000
--- a/tests/acceptance/virtiofs_submounts.py
+++ /dev/null
@@ -1,289 +0,0 @@
-import logging
-import re
-import os
-import subprocess
-import time
-
-from avocado import skipUnless
-from avocado_qemu import Test, BUILD_DIR
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import ssh
-
-from qemu.accel import kvm_available
-
-from boot_linux import BootLinux
-
-
-def run_cmd(args):
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = subp.communicate()
- ret = subp.returncode
-
- return (stdout, stderr, ret)
-
-def has_passwordless_sudo():
- """
- This function is for use in a @avocado.skipUnless decorator, e.g.:
-
- @skipUnless(*has_passwordless_sudo())
- def test_something_that_needs_sudo(self):
- ...
- """
-
- _, stderr, exitcode = run_cmd(('sudo', '-n', 'true'))
- if exitcode != 0:
- return (False, f'Failed to use sudo -n: {stderr.strip()}')
- else:
- return (True, '')
-
-
-class VirtiofsSubmountsTest(BootLinux):
- """
- :avocado: tags=arch:x86_64
- """
-
- def get_portfwd(self):
- port = None
-
- res = self.vm.command('human-monitor-command',
- command_line='info usernet')
- for line in res.split('\r\n'):
- match = \
- re.search(r'TCP.HOST_FORWARD.*127\.0\.0\.1\s*(\d+)\s+10\.',
- line)
- if match is not None:
- port = match[1]
- break
-
- self.assertIsNotNone(port)
- self.log.debug('sshd listening on port: ' + port)
- return port
-
- def ssh_connect(self, username, keyfile):
- self.ssh_logger = logging.getLogger('ssh')
- port = self.get_portfwd()
- self.ssh_session = ssh.Session('127.0.0.1', port=int(port),
- user=username, key=keyfile)
- for i in range(10):
- try:
- self.ssh_session.connect()
- return
- except:
- time.sleep(4)
- pass
- self.fail('sshd timeout')
-
- def ssh_command(self, command):
- self.ssh_logger.info(command)
- result = self.ssh_session.cmd(command)
- stdout_lines = [line.rstrip() for line
- in result.stdout_text.splitlines()]
- for line in stdout_lines:
- self.ssh_logger.info(line)
- stderr_lines = [line.rstrip() for line
- in result.stderr_text.splitlines()]
- for line in stderr_lines:
- self.ssh_logger.warning(line)
-
- self.assertEqual(result.exit_status, 0,
- f'Guest command failed: {command}')
- return stdout_lines, stderr_lines
-
- def run(self, args, ignore_error=False):
- stdout, stderr, ret = run_cmd(args)
-
- if ret != 0:
- cmdline = ' '.join(args)
- if not ignore_error:
- self.fail(f'{cmdline}: Returned {ret}: {stderr}')
- else:
- self.log.warn(f'{cmdline}: Returned {ret}: {stderr}')
-
- return (stdout, stderr, ret)
-
- def set_up_shared_dir(self):
- atwd = os.getenv('AVOCADO_TEST_WORKDIR')
- self.shared_dir = os.path.join(atwd, 'virtiofs-shared')
-
- os.mkdir(self.shared_dir)
-
- self.run(('cp', self.get_data('guest.sh'),
- os.path.join(self.shared_dir, 'check.sh')))
-
- self.run(('cp', self.get_data('guest-cleanup.sh'),
- os.path.join(self.shared_dir, 'cleanup.sh')))
-
- def set_up_virtiofs(self):
- attmp = os.getenv('AVOCADO_TESTS_COMMON_TMPDIR')
- self.vfsdsock = os.path.join(attmp, 'vfsdsock')
-
- self.run(('sudo', '-n', 'rm', '-f', self.vfsdsock), ignore_error=True)
-
- self.virtiofsd = \
- subprocess.Popen(('sudo', '-n',
- 'tools/virtiofsd/virtiofsd',
- f'--socket-path={self.vfsdsock}',
- '-o', f'source={self.shared_dir}',
- '-o', 'cache=always',
- '-o', 'xattr',
- '-o', 'announce_submounts',
- '-f'),
- stdout=subprocess.DEVNULL,
- stderr=subprocess.PIPE,
- universal_newlines=True)
-
- while not os.path.exists(self.vfsdsock):
- if self.virtiofsd.poll() is not None:
- self.fail('virtiofsd exited prematurely: ' +
- self.virtiofsd.communicate()[1])
- time.sleep(0.1)
-
- self.run(('sudo', '-n', 'chmod', 'go+rw', self.vfsdsock))
-
- self.vm.add_args('-chardev',
- f'socket,id=vfsdsock,path={self.vfsdsock}',
- '-device',
- 'vhost-user-fs-pci,queue-size=1024,chardev=vfsdsock' \
- ',tag=host',
- '-object',
- 'memory-backend-file,id=mem,size=1G,' \
- 'mem-path=/dev/shm,share=on',
- '-numa',
- 'node,memdev=mem')
-
- def launch_vm(self):
- self.launch_and_wait()
- self.ssh_connect('root', self.ssh_key)
-
- def set_up_nested_mounts(self):
- scratch_dir = os.path.join(self.shared_dir, 'scratch')
- try:
- os.mkdir(scratch_dir)
- except FileExistsError:
- pass
-
- args = ['bash', self.get_data('host.sh'), scratch_dir]
- if self.seed:
- args += [self.seed]
-
- out, _, _ = self.run(args)
- seed = re.search(r'^Seed: \d+', out)
- self.log.info(seed[0])
-
- def mount_in_guest(self):
- self.ssh_command('mkdir -p /mnt/host')
- self.ssh_command('mount -t virtiofs host /mnt/host')
-
- def check_in_guest(self):
- self.ssh_command('bash /mnt/host/check.sh /mnt/host/scratch/share')
-
- def live_cleanup(self):
- self.ssh_command('bash /mnt/host/cleanup.sh /mnt/host/scratch')
-
- # It would be nice if the above was sufficient to make virtiofsd clear
- # all references to the mounted directories (so they can be unmounted
- # on the host), but unfortunately it is not. To do so, we have to
- # resort to a remount.
- self.ssh_command('mount -o remount /mnt/host')
-
- scratch_dir = os.path.join(self.shared_dir, 'scratch')
- self.run(('bash', self.get_data('cleanup.sh'), scratch_dir))
-
- @skipUnless(*has_passwordless_sudo())
- def setUp(self):
- vmlinuz = self.params.get('vmlinuz')
- if vmlinuz is None:
- self.cancel('vmlinuz parameter not set; you must point it to a '
- 'Linux kernel binary to test (to run this test with ' \
- 'the on-image kernel, set it to an empty string)')
-
- self.seed = self.params.get('seed')
-
- atwd = os.getenv('AVOCADO_TEST_WORKDIR')
- self.ssh_key = os.path.join(atwd, 'id_ed25519')
-
- self.run(('ssh-keygen', '-t', 'ed25519', '-f', self.ssh_key))
-
- pubkey = open(self.ssh_key + '.pub').read()
-
- super(VirtiofsSubmountsTest, self).setUp(pubkey)
-
- if len(vmlinuz) > 0:
- self.vm.add_args('-kernel', vmlinuz,
- '-append', 'console=ttyS0 root=/dev/sda1')
-
- # Allow us to connect to SSH
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'e1000,netdev=vnet')
-
- if not kvm_available(self.arch, self.qemu_bin):
- self.cancel(KVM_NOT_AVAILABLE)
- self.vm.add_args('-accel', 'kvm')
-
- def tearDown(self):
- try:
- self.vm.shutdown()
- except:
- pass
-
- scratch_dir = os.path.join(self.shared_dir, 'scratch')
- self.run(('bash', self.get_data('cleanup.sh'), scratch_dir),
- ignore_error=True)
-
- def test_pre_virtiofsd_set_up(self):
- self.set_up_shared_dir()
-
- self.set_up_nested_mounts()
-
- self.set_up_virtiofs()
- self.launch_vm()
- self.mount_in_guest()
- self.check_in_guest()
-
- def test_pre_launch_set_up(self):
- self.set_up_shared_dir()
- self.set_up_virtiofs()
-
- self.set_up_nested_mounts()
-
- self.launch_vm()
- self.mount_in_guest()
- self.check_in_guest()
-
- def test_post_launch_set_up(self):
- self.set_up_shared_dir()
- self.set_up_virtiofs()
- self.launch_vm()
-
- self.set_up_nested_mounts()
-
- self.mount_in_guest()
- self.check_in_guest()
-
- def test_post_mount_set_up(self):
- self.set_up_shared_dir()
- self.set_up_virtiofs()
- self.launch_vm()
- self.mount_in_guest()
-
- self.set_up_nested_mounts()
-
- self.check_in_guest()
-
- def test_two_runs(self):
- self.set_up_shared_dir()
-
- self.set_up_nested_mounts()
-
- self.set_up_virtiofs()
- self.launch_vm()
- self.mount_in_guest()
- self.check_in_guest()
-
- self.live_cleanup()
- self.set_up_nested_mounts()
-
- self.check_in_guest()
diff --git a/tests/acceptance/virtiofs_submounts.py.data/cleanup.sh b/tests/acceptance/virtiofs_submounts.py.data/cleanup.sh
deleted file mode 100644
index 2a6579a..0000000
--- a/tests/acceptance/virtiofs_submounts.py.data/cleanup.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
- rm -rf "$mp"
-done
-echo
-
-rm some-file
-cd ..
-rmdir share
-
-imgs=(fs*.img)
-img_i=0
-for img in "${imgs[@]}"; do
- img_i=$((img_i + 1))
- printf "Detaching and deleting %i/%i...\r" "$img_i" "${#imgs[@]}"
-
- dev=$(losetup -j "$img" | sed -e 's/:.*//')
- sudo losetup -d "$dev"
- rm -f "$img"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/acceptance/virtiofs_submounts.py.data/guest-cleanup.sh b/tests/acceptance/virtiofs_submounts.py.data/guest-cleanup.sh
deleted file mode 100644
index 729cb2d..0000000
--- a/tests/acceptance/virtiofs_submounts.py.data/guest-cleanup.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/acceptance/virtiofs_submounts.py.data/guest.sh b/tests/acceptance/virtiofs_submounts.py.data/guest.sh
deleted file mode 100644
index 59ba40f..0000000
--- a/tests/acceptance/virtiofs_submounts.py.data/guest.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <shared dir>"
- echo '(The shared directory is the "share" directory in the scratch' \
- 'directory)'
-}
-
-shared_dir=$1
-if [ -z "$shared_dir" ]; then
- print_usage "$0" 'Shared dir not given' >&2
- exit 1
-fi
-
-cd "$shared_dir"
-
-# FIXME: This should not be necessary, but it is. In order for all
-# submounts to be proper mount points, we need to visit them.
-# (Before we visit them, they will not be auto-mounted, and so just
-# appear as normal directories, with the catch that their st_ino will
-# be the st_ino of the filesystem they host, while the st_dev will
-# still be the st_dev of the parent.)
-# `find` does not work, because it will refuse to touch the mount
-# points as long as they are not mounted; their st_dev being shared
-# with the parent and st_ino just being the root node's inode ID
-# will practically ensure that this node exists elsewhere on the
-# filesystem, and `find` is required to recognize loops and not to
-# follow them.
-# Thus, we have to manually visit all nodes first.
-
-mnt_i=0
-
-function recursively_visit()
-{
- pushd "$1" >/dev/null
- for entry in *; do
- if [[ "$entry" == mnt* ]]; then
- mnt_i=$((mnt_i + 1))
- printf "Triggering auto-mount $mnt_i...\r"
- fi
-
- if [ -d "$entry" ]; then
- recursively_visit "$entry"
- fi
- done
- popd >/dev/null
-}
-
-recursively_visit .
-echo
-
-
-if [ -n "$(find -name not-mounted)" ]; then
- echo "Error: not-mounted files visible on mount points:" >&2
- find -name not-mounted >&2
- exit 1
-fi
-
-if [ ! -f some-file -o "$(cat some-file)" != 'root' ]; then
- echo "Error: Bad file in the share root" >&2
- exit 1
-fi
-
-shopt -s nullglob
-
-function check_submounts()
-{
- local base_path=$1
-
- for mp in mnt*; do
- printf "Checking submount %i...\r" "$((${#devs[@]} + 1))"
-
- mp_i=$(echo "$mp" | sed -e 's/mnt//')
- dev=$(stat -c '%D' "$mp")
-
- if [ -n "${devs[mp_i]}" ]; then
- echo "Error: $mp encountered twice" >&2
- exit 1
- fi
- devs[mp_i]=$dev
-
- pushd "$mp" >/dev/null
- path="$base_path$mp"
- while true; do
- expected_content="$(printf '%s\n%s\n' "$mp_i" "$path")"
- if [ ! -f some-file ]; then
- echo "Error: $PWD/some-file does not exist" >&2
- exit 1
- fi
-
- if [ "$(cat some-file)" != "$expected_content" ]; then
- echo "Error: Bad content in $PWD/some-file:" >&2
- echo '--- found ---'
- cat some-file
- echo '--- expected ---'
- echo "$expected_content"
- exit 1
- fi
- if [ "$(stat -c '%D' some-file)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
-
- if [ -d sub ]; then
- if [ "$(stat -c '%D' sub)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
- cd sub
- path="$path/sub"
- else
- if [ -n "$(echo mnt*)" ]; then
- check_submounts "$path/"
- fi
- break
- fi
- done
- popd >/dev/null
- done
-}
-
-root_dev=$(stat -c '%D' some-file)
-devs=()
-check_submounts ''
-echo
-
-reused_devs=$(echo "$root_dev ${devs[@]}" | tr ' ' '\n' | sort | uniq -d)
-if [ -n "$reused_devs" ]; then
- echo "Error: Reused device IDs: $reused_devs" >&2
- exit 1
-fi
-
-echo "Test passed for ${#devs[@]} submounts."
diff --git a/tests/acceptance/virtiofs_submounts.py.data/host.sh b/tests/acceptance/virtiofs_submounts.py.data/host.sh
deleted file mode 100644
index d8a9afe..0000000
--- a/tests/acceptance/virtiofs_submounts.py.data/host.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-mount_count=128
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir> [seed]"
- echo "(If no seed is given, it will be randomly generated.)"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'No scratch dir given' >&2
- exit 1
-fi
-
-if [ ! -d "$scratch_dir" ]; then
- print_usage "$0" "$scratch_dir is not a directory" >&2
- exit 1
-fi
-
-seed=$2
-if [ -z "$seed" ]; then
- seed=$RANDOM
-fi
-RANDOM=$seed
-
-echo "Seed: $seed"
-
-set -e
-shopt -s nullglob
-
-cd "$scratch_dir"
-if [ -d share ]; then
- echo 'Error: This directory seems to be in use already' >&2
- exit 1
-fi
-
-for ((i = 0; i < $mount_count; i++)); do
- printf "Setting up fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- rm -f fs$i.img
- truncate -s 512M fs$i.img
- mkfs.xfs -q fs$i.img
- devs[i]=$(sudo losetup -f --show fs$i.img)
-done
-echo
-
-top_level_mounts=$((RANDOM % mount_count + 1))
-
-mkdir -p share
-echo 'root' > share/some-file
-
-for ((i = 0; i < $top_level_mounts; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mkdir -p share/mnt$i
- touch share/mnt$i/not-mounted
- sudo mount "${devs[i]}" share/mnt$i
- sudo chown "$(id -u):$(id -g)" share/mnt$i
-
- pushd share/mnt$i >/dev/null
- path=mnt$i
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
-cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-
-for ((; i < $mount_count; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mp_i=$((i % top_level_mounts))
-
- pushd share/mnt$mp_i >/dev/null
- path=mnt$mp_i
- while true; do
- sub_mp="$(echo mnt*)"
- if cd sub 2>/dev/null; then
- path="$path/sub"
- elif [ -n "$sub_mp" ] && cd "$sub_mp" 2>/dev/null; then
- path="$path/$sub_mp"
- else
- break
- fi
- done
- mkdir mnt$i
- touch mnt$i/not-mounted
- sudo mount "${devs[i]}" mnt$i
- sudo chown "$(id -u):$(id -g)" mnt$i
-
- cd mnt$i
- path="$path/mnt$i"
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
- cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-echo
-
-echo 'Done.'
diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
index 870544f..686c42c 100644
--- a/tools/virtiofsd/fuse_common.h
+++ b/tools/virtiofsd/fuse_common.h
@@ -353,14 +353,6 @@ struct fuse_file_info {
#define FUSE_CAP_NO_OPENDIR_SUPPORT (1 << 24)
/**
- * Indicates that the client will provide fuse_attr.flags, and the kernel will
- * interpret it.
- *
- * This feature is enabled by default when supported by the kernel.
- */
-#define FUSE_CAP_ATTR_FLAGS (1 << 27)
-
-/**
* Ioctl flags
*
* FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
index 5198f62..4d1ba29 100644
--- a/tools/virtiofsd/fuse_lowlevel.c
+++ b/tools/virtiofsd/fuse_lowlevel.c
@@ -329,8 +329,7 @@ static unsigned int calc_timeout_nsec(double t)
}
}
-static void fill_entry(struct fuse_session *se,
- struct fuse_entry_out *arg,
+static void fill_entry(struct fuse_entry_out *arg,
const struct fuse_entry_param *e)
{
*arg = (struct fuse_entry_out){
@@ -342,10 +341,6 @@ static void fill_entry(struct fuse_session *se,
.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout),
};
convert_stat(&e->attr, &arg->attr);
-
- if (se->conn.capable & FUSE_CAP_ATTR_FLAGS) {
- arg->attr.flags = e->attr_flags;
- }
}
/*
@@ -370,7 +365,7 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
struct fuse_direntplus *dp = (struct fuse_direntplus *)buf;
memset(&dp->entry_out, 0, sizeof(dp->entry_out));
- fill_entry(req->se, &dp->entry_out, e);
+ fill_entry(&dp->entry_out, e);
struct fuse_dirent *dirent = &dp->dirent;
*dirent = (struct fuse_dirent){
@@ -408,7 +403,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
size_t size = sizeof(arg);
memset(&arg, 0, sizeof(arg));
- fill_entry(req->se, &arg, e);
+ fill_entry(&arg, e);
return send_reply_ok(req, &arg, size);
}
@@ -421,13 +416,13 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
memset(buf, 0, sizeof(buf));
- fill_entry(req->se, earg, e);
+ fill_entry(earg, e);
fill_open(oarg, f);
return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out));
}
-int fuse_reply_attr_with_flags(fuse_req_t req, const struct stat *attr,
- double attr_timeout, uint32_t attr_flags)
+int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+ double attr_timeout)
{
struct fuse_attr_out arg;
size_t size = sizeof(arg);
@@ -437,19 +432,9 @@ int fuse_reply_attr_with_flags(fuse_req_t req, const struct stat *attr,
arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
convert_stat(attr, &arg.attr);
- if (req->se->conn.capable & FUSE_CAP_ATTR_FLAGS) {
- arg.attr.flags = attr_flags;
- }
-
return send_reply_ok(req, &arg, size);
}
-int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
- double attr_timeout)
-{
- return fuse_reply_attr_with_flags(req, attr, attr_timeout, 0);
-}
-
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
{
return send_reply_ok(req, linkname, strlen(linkname));
@@ -2003,9 +1988,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
bufsize = max_bufsize;
}
}
- if (arg->flags & FUSE_ATTR_FLAGS) {
- se->conn.capable |= FUSE_CAP_ATTR_FLAGS;
- }
#ifdef HAVE_SPLICE
#ifdef HAVE_VMSPLICE
se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
@@ -2032,7 +2014,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
- LL_SET_DEFAULT(1, FUSE_CAP_ATTR_FLAGS);
LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS);
LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
@@ -2122,9 +2103,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
if (se->conn.want & FUSE_CAP_POSIX_ACL) {
outarg.flags |= FUSE_POSIX_ACL;
}
- if (se->conn.want & FUSE_CAP_ATTR_FLAGS) {
- outarg.flags |= FUSE_ATTR_FLAGS;
- }
outarg.max_readahead = se->conn.max_readahead;
outarg.max_write = se->conn.max_write;
if (se->conn.max_background >= (1 << 16)) {
diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
index 1ff6ba1..562fd52 100644
--- a/tools/virtiofsd/fuse_lowlevel.h
+++ b/tools/virtiofsd/fuse_lowlevel.h
@@ -102,11 +102,6 @@ struct fuse_entry_param {
* large value.
*/
double entry_timeout;
-
- /**
- * Flags for fuse_attr.flags that do not fit into attr.
- */
- uint32_t attr_flags;
};
/**
@@ -1314,21 +1309,6 @@ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
double attr_timeout);
/**
- * Reply with attributes and set fuse_attr.flags
- *
- * Possible requests:
- * getattr, setattr
- *
- * @param req request handle
- * @param attr the attributes
- * @param attr_timeout validity timeout (in seconds) for the attributes
- * @param attr_flags flags to put into fuse_attr.flags
- * @return zero for success, -errno for failure to send reply
- */
-int fuse_reply_attr_with_flags(fuse_req_t req, const struct stat *attr,
- double attr_timeout, uint32_t attr_flags);
-
-/**
* Reply with the contents of a symbolic link
*
* Possible requests:
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
index a212f32..2e181a4 100644
--- a/tools/virtiofsd/helper.c
+++ b/tools/virtiofsd/helper.c
@@ -178,7 +178,6 @@ void fuse_cmdline_help(void)
" default: depends on cache= option.\n"
" -o writeback|no_writeback enable/disable writeback cache\n"
" default: no_writeback\n"
- " -o announce_submounts Announce sub-mount points to the guest\n"
" -o xattr|no_xattr enable/disable xattr\n"
" default: no_xattr\n"
" -o modcaps=CAPLIST Modify the list of capabilities\n"
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 4db5004..a0beb98 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -40,7 +40,6 @@
#include "fuse_virtio.h"
#include "fuse_log.h"
#include "fuse_lowlevel.h"
-#include "standard-headers/linux/fuse.h"
#include <assert.h>
#include <cap-ng.h>
#include <dirent.h>
@@ -126,14 +125,6 @@ struct lo_inode {
GHashTable *posix_locks; /* protected by lo_inode->plock_mutex */
mode_t filetype;
-
- /*
- * So we can detect crossmount roots
- * (As such, this only needs to be valid for directories. Note
- * that files can have multiple parents due to hard links, and so
- * their parent_dev may fluctuate.)
- */
- dev_t parent_dev;
};
struct lo_cred {
@@ -174,7 +165,6 @@ struct lo_data {
int timeout_set;
int readdirplus_set;
int readdirplus_clear;
- int announce_submounts;
int allow_direct_io;
struct lo_inode root;
GHashTable *inodes; /* protected by lo->mutex */
@@ -213,7 +203,6 @@ static const struct fuse_opt lo_opts[] = {
{ "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
{ "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 },
{ "no_readdirplus", offsetof(struct lo_data, readdirplus_clear), 1 },
- { "announce_submounts", offsetof(struct lo_data, announce_submounts), 1 },
{ "allow_direct_io", offsetof(struct lo_data, allow_direct_io), 1 },
{ "no_allow_direct_io", offsetof(struct lo_data, allow_direct_io), 0 },
FUSE_OPT_END
@@ -611,52 +600,22 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
}
}
-/**
- * Call fstatat() and set st_rdev whenever a directory's st_dev
- * differs from the rparent's st_dev (@parent_dev). This will
- * announce submounts to the FUSE client (unless @announce_submounts
- * is false).
- */
-static int do_fstatat(int dirfd, const char *pathname, struct stat *statbuf,
- int flags, dev_t parent_dev, uint32_t *fuse_attr_flags)
-{
- int res = fstatat(dirfd, pathname, statbuf, flags);
- if (res == -1) {
- return res;
- }
-
- if (statbuf->st_dev != parent_dev && S_ISDIR(statbuf->st_mode) &&
- fuse_attr_flags)
- {
- *fuse_attr_flags |= FUSE_ATTR_SUBMOUNT;
- }
-
- return 0;
-}
-
static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
int res;
struct stat buf;
struct lo_data *lo = lo_data(req);
- struct lo_inode *inode = lo_inode(req, ino);
- uint32_t fuse_attr_flags = 0;
(void)fi;
- res = do_fstatat(inode->fd, "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW,
- inode->parent_dev, &fuse_attr_flags);
- lo_inode_put(lo, &inode);
+ res =
+ fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1) {
return (void)fuse_reply_err(req, errno);
}
- if (!lo->announce_submounts) {
- fuse_attr_flags &= ~FUSE_ATTR_SUBMOUNT;
- }
-
- fuse_reply_attr_with_flags(req, &buf, lo->timeout, fuse_attr_flags);
+ fuse_reply_attr(req, &buf, lo->timeout);
}
static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi)
@@ -852,16 +811,11 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
goto out_err;
}
- res = do_fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW,
- dir->key.dev, &e->attr_flags);
+ res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1) {
goto out_err;
}
- if (!lo->announce_submounts) {
- e->attr_flags &= ~FUSE_ATTR_SUBMOUNT;
- }
-
inode = lo_find(lo, &e->attr);
if (inode) {
close(newfd);
@@ -893,7 +847,6 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
g_hash_table_insert(lo->inodes, &inode->key, inode);
pthread_mutex_unlock(&lo->mutex);
}
- inode->parent_dev = dir->key.dev;
e->ino = inode->fuse_ino;
lo_inode_put(lo, &inode);
lo_inode_put(lo, &dir);
@@ -1107,17 +1060,11 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
goto out_err;
}
- res = do_fstatat(inode->fd, "", &e.attr,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW,
- parent_inode->key.dev, &e.attr_flags);
+ res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1) {
goto out_err;
}
- if (!lo->announce_submounts) {
- e.attr_flags &= ~FUSE_ATTR_SUBMOUNT;
- }
-
pthread_mutex_lock(&lo->mutex);
inode->nlookup++;
pthread_mutex_unlock(&lo->mutex);
@@ -1126,14 +1073,6 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long)parent,
name, (unsigned long long)e.ino);
- /*
- * No need to update inode->parent_dev, because
- * (1) We cannot, the inode now has more than one parent,
- * (2) Directories cannot have more than one parent, so link()
- * does not work for them; but parent_dev only needs to be
- * valid for directories.
- */
-
fuse_reply_entry(req, &e);
lo_inode_put(lo, &parent_inode);
lo_inode_put(lo, &inode);
@@ -1152,21 +1091,14 @@ static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent,
{
int res;
struct stat attr;
- struct lo_data *lo = lo_data(req);
- struct lo_inode *dir = lo_inode(req, parent);
- if (!dir) {
- return NULL;
- }
-
- res = do_fstatat(dir->fd, name, &attr,
- AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, dir->key.dev, NULL);
- lo_inode_put(lo, &dir);
+ res = fstatat(lo_fd(req, parent), name, &attr,
+ AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
if (res == -1) {
return NULL;
}
- return lo_find(lo, &attr);
+ return lo_find(lo_data(req), &attr);
}
static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)