Skip to content

Crucial fixes for xfstests and kernel_source_packager code #4526

Open
psachdeva-ms wants to merge 7 commits into
microsoft:mainfrom
psachdeva-ms:master
Open

Crucial fixes for xfstests and kernel_source_packager code #4526
psachdeva-ms wants to merge 7 commits into
microsoft:mainfrom
psachdeva-ms:master

Conversation

@psachdeva-ms

Copy link
Copy Markdown
Collaborator

Changes are put in the order of importance

  • Adds parallel execution support for the xfstests Azure File Share test suites (SMB/CIFS and NFSv4.1), splitting test cases across multiple workers (default 4) to cut total runtime.
  • Also fixes a paramiko SSH transport-lock deadlock during parallel result collection via a two-phase (parallel-exec → sequential-collect) approach
  • Adds graceful handling of the "expunged" result category
  • Adds a PV2 storage-account fallback in get_or_create_file_share.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Documentation update

Checklist

  • Description is filled in above
  • No credentials, secrets, or internal details are included
  • Peer review requested (if not, add required peer reviewers after raising PR)
  • Tests executed and results posted below

Test Validation

Key Test Cases:
verify_azure_file_share|verify_azure_file_share_nfsv4

Impacted LISA Features:
AzureFileShare

Tested Azure Marketplace Images:

  • canonical ubuntu-24_04-lts server latest
  • canonical 0001-com-ubuntu-server-jammy 22_04-lts-gen2 latest

Test Results

Image VM Size Result
canonical ubuntu-24_04-lts server latest Standard_D8s_v5 PASSED
canonical 0001-com-ubuntu-server-jammy 22_04-lts-gen2 lates Standard_D8s_v5 PASSED

The data plane SDK now natively supports provisioned_iops and
provisioned_bandwidth_mibps parameters in create_share() API.

Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves LISA’s Azure File Share xfstests execution by parallelizing xfstests runs (with a safer “parallel execute → sequential collect” flow to avoid SSH/paramiko contention), and includes related robustness updates in kernel source worktree handling and Azure file share provisioning.

Changes:

  • Add a two-phase parallel execution model for xfstests workers, collecting results sequentially to avoid SSH channel deadlocks.
  • Update kernel repo worktree checkout logic (tag-aware checkout + detached worktree cleanup).
  • Add Azure Files share creation fallback when PV2 headers aren’t supported, and bump azure-storage-file-share dependency.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pyproject.toml Bumps azure-storage-file-share dependency version.
lisa/transformers/kernel_source_packager.py Adds worktree cleanup and tag-aware ref checkout logic for kernel source packaging.
lisa/transformers/kernel_source_installer.py Adjusts ccache directory handling for kernel builds.
lisa/tools/git.py Updates worktree_remove parameter type to align with worktree listing output usage.
lisa/sut_orchestrator/azure/common.py Adds PV2-parameter fallback logic when creating Azure file shares.
lisa/microsoft/testsuites/xfstests/xfstests.py Implements parallel xfstests execution with sequential result collection and related refactors.
lisa/microsoft/testsuites/xfstests/xfstesting.py Removes now-unneeded deferred notification calls after parallel execution changes.

Comment thread lisa/microsoft/testsuites/xfstests/xfstests.py Outdated
Comment thread lisa/microsoft/testsuites/xfstests/xfstests.py
Comment on lines +429 to +434
result = self._node.execute(
f"git tag -l {ref}",
shell=True,
cwd=target_path,
)
return bool(result.stdout.strip())
Comment thread lisa/microsoft/testsuites/xfstests/xfstests.py Outdated
Comment thread lisa/sut_orchestrator/azure/common.py Outdated
Comment thread lisa/sut_orchestrator/azure/common.py Outdated
LiliDeng
LiliDeng previously approved these changes Jul 6, 2026
@LiliDeng

LiliDeng commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

@psachdeva-ms please fix the comments, thanks,

- Add error handling for PV2 unsupported storage accounts
- Automatically retry without provisioned_iops/provisioned_bandwidth_mibps
  when UnsupportedHeader error occurs
- Increase quota to 100 GiB minimum when falling back to non-PV2
  (PV1 minimum requirement)

Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (2)

lisa/microsoft/testsuites/xfstests/xfstests.py:836

  • Major: run_test() waits via pgrep.wait_processes("check"), which can match unrelated processes and can also raise on timeout before the xfstests failure summary is raised. Since you already have the async Process handle, wait on that specific process (with raise_on_timeout=False) and then collect results.
        pgrep = self.node.tools[Pgrep]
        # this is the actual process name, when xfstests runs.
        # monitor till process completes or timesout
        try:
            pgrep.wait_processes("check", timeout=timeout)

lisa/transformers/kernel_source_packager.py:434

  • Major: _is_tag() uses git tag -l {ref} which performs pattern matching (so a ref like "v1" can match multiple tags) and is executed with shell=True without quoting. Prefer a verification-style command and avoid shell parsing so tag detection is exact and robust.
        result = self._node.execute(
            f"git tag -l {ref}",
            shell=True,
            cwd=target_path,
        )
        return bool(result.stdout.strip())

Comment on lines 143 to 147
"""
Result object returned by run_test() to support parallel execution.
Instead of raising immediately on failure, this allows callers to
aggregate results from multiple parallel runs before deciding how to fail.

For parallel execution, raw_message and data_disk are stored to enable
deferred notification sending after all workers complete. This prevents
deadlock when multiple workers try to send SubTestResult notifications
concurrently to the single-threaded notifier message manager.
"""
Comment on lines +552 to +555
if runbook.worktree_repo:
assert runbook.worktree_repo == git.remote_get_url(
code_path, remote
), f"Existing remote url doesn't match with {runbook.worktree_repo}"
Comment on lines +559 to +563
else:
assert runbook.worktree_repo, "Remote can not be added without a URL"
remote = runbook.worktree_name
self._log.info(f"adding remote {remote} for {runbook.worktree_repo}")
git.remote_add(cwd=code_path, name=remote, url=runbook.worktree_repo)
Comment on lines 579 to 581
if not git.worktree_exists(cwd=code_path, path=str(worktree_path)):
assert runbook.worktree_ref, "Worktree ref needs to be set by user"
self._log.info(
Comment on lines +2394 to +2399
except HttpResponseError as e:
# Handle PV2 parameters unsupported by the storage account
if "UnsupportedHeader" in str(e) and (
"x-ms-share-provisioned-iops" in str(e)
or "x-ms-share-provisioned-bandwidth" in str(e)
):
Comment on lines +471 to +476
self._node.execute(
f"git checkout -f {expected_local_branch_name}",
shell=True,
cwd=target_path,
expected_exit_code=0,
)
Comment on lines +410 to +415
self._node.execute(
f"git branch --list '{worktree_name}-*' | xargs git branch -D",
shell=True,
no_error_log=True,
cwd=code_path,
)
psachdeva-ms and others added 5 commits July 19, 2026 14:40
Parallel xfstests workers deadlocked during result collection when
multiple threads simultaneously made rapid SSH calls (shell.exists,
Cat.run, copy_back) competing for paramiko's transport lock. Workers
would hang for hours until timeout.

Fix by splitting parallel execution into two phases:
- Phase 1: Execute xfstests across all workers in parallel via
  _execute_test(), which issues a single long-running check command
  per worker (no rapid SSH-call churn, no deadlock).
- Phase 2: Collect results sequentially via check_test_results(),
  avoiding the rapid SSH channel churn that triggers the deadlock.

Because Phase 2 runs on the main thread one worker at a time, subtest
notifications are now sent inline during collection. This removes the
need for the deferred-notification path, so the following are deleted:
- XfstestsParallelRunner.send_deferred_notifications()
- XfstestsRunResult.raw_message / data_disk fields
- the send_notifications parameter on check_test_results()
Subtests are now tagged with the filesystem section (cifs/nfs) instead
of the per-worker id (cifs_worker_N), matching non-parallel runs.

Also simplify run_test() back to the original run_async + pgrep
pattern for single-worker filesystem tests (btrfs, ext4), keeping the
parallel-specific _execute_test() as a private method used only by
XfstestsParallelRunner.run_parallel().

Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
- Add function to support deleting detached worktrees and linked branches.
- Modularize the code by moving checkout of target ref in a method.
- Don't let the user set a local tracking branch for the worktree, rather use a
  pattern: "<remote_name>-<target_ref>"

Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
Signed-off-by: Piyush Sachdeva <psachdeva@microsoft.com>
Signed-off-by: Piyush Sachdeva <s.piyush1024@gmail.com>
Copilot AI review requested due to automatic review settings July 19, 2026 09:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (5)

lisa/transformers/kernel_source_packager.py:563

  • Major: Avoid using assert for runbook/remote validation. Assertions are skipped when Python runs with optimizations (-O), which would silently bypass these safety checks and can lead to using the wrong remote URL or trying to add a remote without a URL. Raise LisaException (or ValueError) instead so validation is enforced in all runs.
        if runbook.worktree_name:
            if runbook.worktree_name in remotes:
                self._log.debug("Setting the remote based on worktree name/path.")
                remote = runbook.worktree_name
                if runbook.worktree_repo:
                    assert runbook.worktree_repo == git.remote_get_url(
                        code_path, remote
                    ), f"Existing remote url doesn't match with {runbook.worktree_repo}"
            elif runbook.worktree_name == repo_name:
                self._log.debug("Using the upstream repo pointed by 'origin' remote")

            else:
                assert runbook.worktree_repo, "Remote can not be added without a URL"
                remote = runbook.worktree_name
                self._log.info(f"adding remote {remote} for {runbook.worktree_repo}")
                git.remote_add(cwd=code_path, name=remote, url=runbook.worktree_repo)

lisa/transformers/kernel_source_packager.py:434

  • Major: _is_tag() builds a shell command with an unquoted, user-controlled ref and uses git tag -l <pattern>, which treats the input as a glob pattern. This can mis-detect tags (e.g., v*) and is vulnerable to shell metacharacters. Prefer an exact ref verification via git show-ref --tags --verify and avoid shell=True.
    def _is_tag(
        self,
        target_path: PurePath,
        ref: str,
    ) -> bool:
        result = self._node.execute(
            f"git tag -l {ref}",
            shell=True,
            cwd=target_path,
        )
        return bool(result.stdout.strip())

lisa/transformers/kernel_source_packager.py:415

  • Minor: xargs git branch -D will run git branch -D even when no branches match, causing a non-zero exit and forcing the code into the exception path. Using xargs -r avoids the spurious failure and keeps cleanup best-effort without unnecessary exceptions.
                self._node.execute(
                    f"git branch --list '{worktree_name}-*' | xargs git branch -D",
                    shell=True,
                    no_error_log=True,
                    cwd=code_path,
                )

lisa/microsoft/testsuites/xfstests/xfstests.py:846

  • Major: run_test() waits for completion via pgrep.wait_processes("check"), which can match unrelated processes named "check" and either return early or hang until timeout. Since run_async() already returns a Process handle, prefer waiting on that specific process (process.wait_result(...)) to avoid false matches and reduce extra SSH calls.
        # run ./check command
        process = self.run_async(
            cmd,
            sudo=True,
            shell=True,
            force_run=True,
            cwd=self.get_xfstests_path(),
        )

        pgrep = self.node.tools[Pgrep]
        # this is the actual process name, when xfstests runs.
        # monitor till process completes or timesout
        try:
            pgrep.wait_processes("check", timeout=timeout)
        finally:
            # On timeout wait_processes() only raises; the check process keeps
            # running and holds the test/scratch mounts, wedging after_case
            # cleanup. Kill the async handle so the mounts are free before we
            # collect results.
            if process.is_running():
                process.kill()
            run_result = self.check_test_results(

lisa/sut_orchestrator/azure/common.py:2399

  • Minor: The PV2 fallback detection relies on repeated str(e) substring checks, which is brittle (message formats can change across azure-core/azure-storage versions). Prefer checking the service error code from the response (e.g., x-ms-error-code) and compute message = str(e) once for the header-name checks.
            except HttpResponseError as e:
                # Handle PV2 parameters unsupported by the storage account
                if "UnsupportedHeader" in str(e) and (
                    "x-ms-share-provisioned-iops" in str(e)
                    or "x-ms-share-provisioned-bandwidth" in str(e)
                ):

Comment on lines 463 to 473
make_args = ""
if use_ccache:
make_args = "CC='ccache gcc'"
node.execute(
cmd=f"export CCACHE_DIR={str(code_path.parent)}/.ccache",
shell=True,
no_error_log=True,
)
ccache_dir = code_path.parent / ".ccache"
if not node.shell.exists(ccache_dir):
node.execute(f"mkdir -p {ccache_dir}", sudo=True)
node.execute(f"chmod 0777 {ccache_dir}", sudo=True)

make_args = f"CC='ccache gcc' CCACHE_DIR={str(ccache_dir)}"

# set timeout to 2 hours
make.make(arguments=make_args, cwd=code_path, timeout=60 * 60 * 2)
Comment on lines +1158 to +1163
combined_cmd = (
f"rm -rf {worker_path} && "
f"mkdir -p {base_dir} && "
f"cp -a {source_path} {worker_path} && "
f"chmod -R a+rwx {worker_path}"
)
Comment on lines +565 to 571
self._node.execute(
f"git fetch -p {remote} --force --tags",
shell=True,
no_info_log=False,
cwd=code_path,
remote=remote,
expected_exit_code=0,
)
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

Successfully merging this pull request may close these issues.

4 participants