* Alex Williamson (alex.william...@redhat.com) wrote: > This reverts the following commits due to their basis on a bogus > linux kernel header update: > > c93a656f7b65 ("tests/acceptance: Add virtiofs_submounts.py") > 45ced7ca2f27 ("tests/acceptance/boot_linux: Accept SSH pubkey") > 08dce386e77e ("virtiofsd: Announce sub-mount points") > eba8b096c17c ("virtiofsd: Store every lo_inode's parent_dev") > ede24b6be798 ("virtiofsd: Add fuse_reply_attr_with_flags()") > e2577435d343 ("virtiofsd: Add attr_flags to fuse_entry_param") > 2f10415abfc5 ("virtiofsd: Announce FUSE_ATTR_FLAGS") > 97d741cc96dd ("linux/fuse.h: Pull in from Linux") > > Cc: Max Reitz <mre...@redhat.com> > Cc: Stefan Hajnoczi <stefa...@redhat.com> > Cc: Dr. David Alan Gilbert <dgilb...@redhat.com> > Signed-off-by: Alex Williamson <alex.william...@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilb...@redhat.com> Peter: Can you take this directly please > --- > > The following pull request, based on legitimate v5.10-rc1 kernel > headers, applies cleanly after this revert: > > https://lists.nongnu.org/archive/html/qemu-devel/2020-10/msg07849.html > > > include/standard-headers/linux/fuse.h | 11 - > tests/acceptance/boot_linux.py | 13 - > tests/acceptance/virtiofs_submounts.py | 289 > -------------------- > .../virtiofs_submounts.py.data/cleanup.sh | 46 --- > .../virtiofs_submounts.py.data/guest-cleanup.sh | 30 -- > .../acceptance/virtiofs_submounts.py.data/guest.sh | 138 ---------- > .../acceptance/virtiofs_submounts.py.data/host.sh | 127 --------- > tools/virtiofsd/fuse_common.h | 8 - > tools/virtiofsd/fuse_lowlevel.c | 34 -- > tools/virtiofsd/fuse_lowlevel.h | 20 - > tools/virtiofsd/helper.c | 1 > tools/virtiofsd/passthrough_ll.c | 84 +----- > 12 files changed, 21 insertions(+), 780 deletions(-) > delete mode 100644 tests/acceptance/virtiofs_submounts.py > delete mode 100644 tests/acceptance/virtiofs_submounts.py.data/cleanup.sh > delete mode 100644 > tests/acceptance/virtiofs_submounts.py.data/guest-cleanup.sh > delete mode 100644 tests/acceptance/virtiofs_submounts.py.data/guest.sh > delete mode 100644 tests/acceptance/virtiofs_submounts.py.data/host.sh > > diff --git a/include/standard-headers/linux/fuse.h > b/include/standard-headers/linux/fuse.h > index 7dd7a3b992c8..f4df0a40f604 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 ad997c3f2eed..0055dc7cee77 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 8b207b3e577f..000000000000 > --- 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 2a6579a0fea6..000000000000 > --- 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 729cb2d1a5ec..000000000000 > --- 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 59ba40fde179..000000000000 > --- 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 d8a9afebdb54..000000000000 > --- 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 870544fe132f..686c42c0a528 100644 > --- a/tools/virtiofsd/fuse_common.h > +++ b/tools/virtiofsd/fuse_common.h > @@ -352,14 +352,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 > * > diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c > index 5198f627bcb3..4d1ba2925d1b 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 1ff6ba1e4f1e..562fd5241ed4 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; > }; > > /** > @@ -1313,21 +1308,6 @@ int fuse_reply_create(fuse_req_t req, const struct > fuse_entry_param *e, > 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 > * > diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c > index a212f329317b..2e181a49b5ff 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 4db50046d49f..a0beb986f36a 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) > -- Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK