Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_release_unlink_race failed in mkstemp #928

Open
chenxy1988 opened this issue Apr 16, 2024 · 3 comments
Open

test_release_unlink_race failed in mkstemp #928

chenxy1988 opened this issue Apr 16, 2024 · 3 comments

Comments

@chenxy1988
Copy link

chenxy1988 commented Apr 16, 2024

Hello,

Currently, on libfuse 3.16.2, the test_release_unlink_race case failed with python 3.12.2, when calling _os.open, the python lib raise an error
as below:

Error message is :

>               fd = _os.open(file, flags, 0o600)
E               OSError: [Errno 38] Function not implemented: '/var/volatile/tmp/pytest-of-root/pytest-2/test_release_unlink_race0/tmp/tmpfjtoizhl/tmpf9k36bhc'

../../python3.12/tempfile.py:256: OSError

The full trace is

platform linux -- Python 3.12.2, pytest-8.0.2, pluggy-1.4.0
rootdir: /usr/lib64/fuse3/ptest
plugins: hypothesis-6.98.15, putao-0.1, subtests-0.11.0
collected 53 items

PASS: test/test_ctests.py::test_write_cache[False] 
PASS: test/test_ctests.py::test_write_cache[True] 
PASS: test/test_ctests.py::test_notify1[True-notify_inval_inode] 
PASS: test/test_ctests.py::test_notify1[True-invalidate_path] 
PASS: test/test_ctests.py::test_notify1[True-notify_store_retrieve] 
PASS: test/test_ctests.py::test_notify1[False-notify_inval_inode] 
PASS: test/test_ctests.py::test_notify1[False-invalidate_path] 
PASS: test/test_ctests.py::test_notify1[False-notify_store_retrieve] 
PASS: test/test_ctests.py::test_notify_file_size[True] 
PASS: test/test_ctests.py::test_notify_file_size[False] 
PASS: test/test_custom_io.py::test_hello_uds 
PASS: test/test_examples.py::test_printcap 
PASS: test/test_examples.py::test_hello[hello-options0-invoke_directly] 
PASS: test/test_examples.py::test_hello[hello-options0-invoke_mount_fuse] 
PASS: test/test_examples.py::test_hello[hello-options0-invoke_mount_fuse_drop_privileges] 
PASS: test/test_examples.py::test_hello[hello-options1-invoke_directly] 
PASS: test/test_examples.py::test_hello[hello-options1-invoke_mount_fuse] 
PASS: test/test_examples.py::test_hello[hello-options1-invoke_mount_fuse_drop_privileges] 
PASS: test/test_examples.py::test_hello[hello_ll-options0-invoke_directly] 
PASS: test/test_examples.py::test_hello[hello_ll-options0-invoke_mount_fuse] 
PASS: test/test_examples.py::test_hello[hello_ll-options0-invoke_mount_fuse_drop_privileges] 
PASS: test/test_examples.py::test_hello[hello_ll-options1-invoke_directly] 
PASS: test/test_examples.py::test_hello[hello_ll-options1-invoke_mount_fuse] 
PASS: test/test_examples.py::test_hello[hello_ll-options1-invoke_mount_fuse_drop_privileges] 
PASS: test/test_examples.py::test_passthrough[False-passthrough-False] 
SKIP: test/test_examples.py::test_passthrough[False-passthrough-True] 
PASS: test/test_examples.py::test_passthrough[False-passthrough_plus-False] 
SKIP: test/test_examples.py::test_passthrough[False-passthrough_plus-True] 
PASS: test/test_examples.py::test_passthrough[False-passthrough_fh-False] 
SKIP: test/test_examples.py::test_passthrough[False-passthrough_fh-True] 
PASS: test/test_examples.py::test_passthrough[False-passthrough_ll-False] 
PASS: test/test_examples.py::test_passthrough[False-passthrough_ll-True] 
PASS: test/test_examples.py::test_passthrough[True-passthrough-False] 
SKIP: test/test_examples.py::test_passthrough[True-passthrough-True] 
PASS: test/test_examples.py::test_passthrough[True-passthrough_plus-False] 
SKIP: test/test_examples.py::test_passthrough[True-passthrough_plus-True] 
PASS: test/test_examples.py::test_passthrough[True-passthrough_fh-False] 
SKIP: test/test_examples.py::test_passthrough[True-passthrough_fh-True] 
PASS: test/test_examples.py::test_passthrough[True-passthrough_ll-False] 
PASS: test/test_examples.py::test_passthrough[True-passthrough_ll-True] 
PASS: test/test_examples.py::test_passthrough_hp[False] 
PASS: test/test_examples.py::test_passthrough_hp[True] 
PASS: test/test_examples.py::test_ioctl 
PASS: test/test_examples.py::test_poll 
PASS: test/test_examples.py::test_null 
PASS: test/test_examples.py::test_notify_inval_entry[True-invalidate_entries] 
PASS: test/test_examples.py::test_notify_inval_entry[True-expire_entries] 
PASS: test/test_examples.py::test_notify_inval_entry[False-invalidate_entries] 
PASS: test/test_examples.py::test_notify_inval_entry[False-expire_entries] 
PASS: test/test_examples.py::test_dev_auto_unmount[root] 
test/test_examples.py::test_dev_auto_unmount[non_root] SKIP (need...) 
PASS: test/test_examples.py::test_cuse 
FAIL: test/test_examples.py::test_release_unlink_race 

=================================== FAILURES ===================================
___________________________ test_release_unlink_race ___________________________

tmpdir = local('/var/volatile/tmp/pytest-of-root/pytest-2/test_release_unlink_race0')
output_checker = <conftest.OutputChecker object at 0x7f051c32e540>

    def test_release_unlink_race(tmpdir, output_checker):
        """test case for Issue #746
    
        If RELEASE and UNLINK opcodes are sent back to back, and fuse_fs_release()
        and fuse_fs_rename() are slow to execute, UNLINK will run while RELEASE is
        still executing. UNLINK will try to rename the file and, while the rename
        is happening, the RELEASE will finish executing. As a result, RELEASE will
        not detect in time that UNLINK has happened, and UNLINK will not detect in
        time that RELEASE has happened.
    
    
        NOTE: This is triggered only when nullpath_ok is set.
    
        If it is NOT SET then get_path_nullok() called by fuse_lib_release() will
        call get_path_common() and lock the path, and then the fuse_lib_unlink()
        will wait for the path to be unlocked before executing and thus synchronise
        with fuse_lib_release().
    
        If it is SET then get_path_nullok() will just set the path to null and
        return without locking anything and thus allowing fuse_lib_unlink() to
        eventually execute unimpeded while fuse_lib_release() is still running.
        """
    
        fuse_mountpoint = str(tmpdir)
    
        fuse_binary_command = base_cmdline + \
            [ pjoin(basename, 'test', 'release_unlink_race'),
            "-f", fuse_mountpoint]
    
        fuse_process = subprocess.Popen(fuse_binary_command,
                                       stdout=output_checker.fd,
                                       stderr=output_checker.fd)
    
        try:
            wait_for_mount(fuse_process, fuse_mountpoint)
    
            temp_dir = tempfile.TemporaryDirectory(dir="/tmp/")
            temp_dir_path = temp_dir.name
    
>           fuse_temp_file, fuse_temp_file_path = tempfile.mkstemp(dir=(fuse_mountpoint + temp_dir_path))

test/test_examples.py:486: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../python3.12/tempfile.py:357: in mkstemp
    return _mkstemp_inner(dir, prefix, suffix, flags, output_type)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

dir = '/var/volatile/tmp/pytest-of-root/pytest-2/test_release_unlink_race0/tmp/tmpfjtoizhl'
pre = 'tmp', suf = '', flags = 131266, output_type = <class 'str'>

    def _mkstemp_inner(dir, pre, suf, flags, output_type):
        """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
    
        dir = _os.path.abspath(dir)
        names = _get_candidate_names()
        if output_type is bytes:
            names = map(_os.fsencode, names)
    
        for seq in range(TMP_MAX):
            name = next(names)
            file = _os.path.join(dir, pre + name + suf)
            _sys.audit("tempfile.mkstemp", file)
            try:
>               fd = _os.open(file, flags, 0o600)
E               OSError: [Errno 38] Function not implemented: '/var/volatile/tmp/pytest-of-root/pytest-2/test_release_unlink_race0/tmp/tmpfjtoizhl/tmpf9k36bhc'

../../python3.12/tempfile.py:256: OSError
=============================== warnings summary ===============================
test/util.py:134
test/util.py:134
  /usr/lib64/fuse3/ptest/test/util.py:134: PytestUnknownMarkWarning: Unknown pytest.mark.uses_fuse - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    return pytest.mark.uses_fuse()

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAIL test/test_examples.py::test_release_unlink_race - OSError: [Errno 38] ...
======== 1 failed, 45 passed, 7 skipped, 2 warnings in 62.27s (0:01:02) ========

My kernel version is:

# uname -a
Linux intel-x86-64 6.6.27-rt28-yocto-preempt-rt #1 SMP PREEMPT_RT Mon Apr 15 15:20:23 UTC 2024 x86_64 GNU/Linux

python version is

python3 --version
Python 3.12.2

Thanks

@bsbernd
Copy link
Collaborator

bsbernd commented Apr 16, 2024

I wonder if this tries to use O_TMPFILE - we need to add support for that to libfuse (kernel supports it) and would also need to add a method for it to release_unlink_race.c then. Although I would see it as python bug if it wouldn't fall back to open/creat.

@trapexit
Copy link
Collaborator

https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryFile

"The os.O_TMPFILE flag is used if it is available and works (Linux-specific, requires Linux kernel 3.11 or later)."

But one would think anything using O_TMPFILE would be prepared for failure. It's hardly universal.

@bsbernd
Copy link
Collaborator

bsbernd commented Apr 16, 2024

Yeah, but from the logs I'm not absolutely sure if it is O_TMPFILE. My ubuntu systems are also still at python 3.11 and don't have time right now to test are more recent environment - I'm just going to wait for the next ubuntu version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants